Форум сайта python.su
Игра в крестики-нолики на поле 3x3. Есть массив arr, например такой:
0 0 0
0 1 2
0 0 1
2 - крестики
1 - нолики
0 - пустые поля
Сделать ход за крестики, чтобы нолики не выиграли партию следующим ходом, т.е. поставить двойку в нужное место (в примере выше это arr)
arr = 2 - заполняет двойками все нулевые элементы исходного массива.
Вопрос как написать в индекс условие которое к имеющейся проверке элемента на значение проверит, что 2 соседа ЛИБО по (горизонталям/вертикалям/диагоналями) равные единицам.
Офлайн
да это же крестики-нолики там всего 8 вариантов, забей их все, а потом перебирай, ставя по почереди во все поля где 0 единицы и сравнивай, если сошлось с одним из 8-ми выиграшных вариантов, туда и лепи двойку.
[code python][/code]
Офлайн
mick_g1 - крестик
2 - крестики
1 - нолики
0 - пустые поля
Офлайн
Для игрового поля 3x3 здесь-то и NumPy не особо нужен, можно напрямую все проверить. Но вот если обобщить эту задачу, и сформулировать так:
Игра в крестики - нолики выполняется на игровом поле n x n. Исходя из заданного состояния игрового поля (и принятых обозначений для x и o), найти оптимальный ход для заданного игрока (x или o), чтобы его оппонент следующим ходом не выиграл. Если такой ход не может быть найден, сообщить об этом.
В общем, я набросал решение этой обощенной задачи в крестики нолики, и здесь уже арсенал numpy используется в более полной мере…
import numpy as np class TicTacBoard: def __init__(self, size=3, state=None, rules={'x': 2, 'o': 1}): self.rules = rules self.state = np.array(state, dtype=int) if state is not None\ else np.zeros((size, size), dtype=int) def checker(self, state=None, query='x'): '''Simple tictactoe checker. Returns `True` if queried gamer (e.g. `x` or `o`) is win. #TODO: two winners problem needs to be handled... (optionally) ''' state = self.state if state is None else np.array(state, dtype=int) if query not in self.rules: raise IndexError('Allowed indecies are `x` or `o`.') if len(query) != 1: raise IndexError('Index length should be equal 1') solution = state == self.rules[query] return any(np.all(solution, axis=0)) or any(np.all(solution, axis=1)) or\ all(np.diag(np.fliplr(solution))) or all(np.diag(solution)) def search_winning_move(self, state=None, query='x'): '''Looking for move, that leads to winning. Returns (indx, indy) if the move was found or None otherwise. ''' if query not in self.rules: raise IndexError('Query value should be declared in rules') state = self.state if state is None else np.array(state, dtype=int) allowed_positions = ~((state == self.rules['x']) | (state == self.rules['o'])) if not allowed_positions.any(): return None for ir, ic in zip(*np.where(allowed_positions)): _state = state.copy() _state[ir, ic] = self.rules[query] if self.checker(_state, query=query): return ir, ic return None def suggest_move(self, query='x'): '''Try to suggest move, that your opponent wouldn't win by next move. ''' if query not in self.rules: raise IndexError('Query value should be declared in rules') allowed_positions = ~((self.state == self.rules['x']) | (self.state == self.rules['o'])) if not allowed_positions.any(): # No moves available # raise custom exception here or print error msg... return None else: # Searching for winning position prob_res = self.search_winning_move(query=query) if prob_res: print('You will win, if accept the move...') return prob_res #No winning moves were found for ir, ic in zip(*np.where(allowed_positions)): _state = self.state.copy() _state[ir, ic] = self.rules[query] if self.search_winning_move(_state, query='x' if query == 'o' else 'o') is None: return ir, ic print('Sorry...your opponent will win in any case...') return None # ---------- testing ---------------- # 2 = x # 1 = o # 0 = Empty nowin = np.array([[0, 1, 2], [1,1,0], [2,2,1]]) board = TicTacBoard(state=nowin) print('nowin: checking for winner `x`, result=', board.checker( query='x')) print('nowin: checking for winner `o`, result=', board.checker(query='o')) winx = np.array([[0, 1, 2], [1,2,0], [2,0,1]]) print('winx: checking for winner `x`, result=', board.checker(winx, query='x')) print('winx: checking for winner `o`, result=', board.checker(winx, query='o')) # ------------------------------------- # --------- more complicated ... ------ test_board = np.zeros((3,3), dtype=int) test_board[2,2] = 1 test_board[2,1] = 1 test_board[1,2] = 1 test_board[1,1] = 2 # | | #--------- # | x | o #--------- # | o | o board = TicTacBoard(state=test_board) # Suggest move for 'x' (default) suggested = board.suggest_move() print('Hint for x: ', suggested) # Suggest move for 'o': suggested = board.suggest_move(query='o') print('Hint for o:', suggested) # ----- another case -- test_board = np.zeros((3,3), dtype=int) test_board[2,2] = 1 test_board[2,1] = 1 test_board[1,1] = 2 # | | #--------- # | x | #--------- # | o | o #---------------------- board = TicTacBoard(state=test_board) result = board.suggest_move() print('Try this move: ', result)
Офлайн
scidam, спасибо за такой фундаментальный подход.
Я новичок и мне пока трудно ориентироваться в вашем коде, хотя бы потому что я еще до ООП не добрался.
Получилось сделать следующим образом:
arr2 = np.logical_or(
np.logical_and(arr == 0, np.logical_and(np.roll(arr, 1, axis = 0) == 1, np.roll(arr, -1, axis = 0) == 1)),
np.logical_and(arr == 0, np.logical_and(np.roll(arr, 1, axis = 1) == 1, np.roll(arr, -1, axis = 1) == 1))
)
arr3 = np.logical_or(
np.logical_and(arr == 0, np.logical_and(np.roll(np.roll(arr, 1, axis=1), 1, axis=0) == 1, np.roll(np.roll(arr, 2, axis=1), 2, axis=0) == 1)),
np.logical_and(arr == 0, np.logical_and(np.roll(np.roll(arr, -1, axis=0), -1, axis=1) == 1, np.roll(np.roll(arr, -2, axis=0), -2, axis=1) == 1))
arr = 2
Офлайн