Уведомления

Группа в Telegram: @pythonsu

#1 Март 28, 2017 16:42:32

mick_g
Зарегистрирован: 2017-02-13
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Numpy: Составное условие проверки элемента массива

Игра в крестики-нолики на поле 3x3. Есть массив arr, например такой:
0 0 0
0 1 2
0 0 1

2 - крестики
1 - нолики
0 - пустые поля

Сделать ход за крестики, чтобы нолики не выиграли партию следующим ходом, т.е. поставить двойку в нужное место (в примере выше это arr)

arr = 2 - заполняет двойками все нулевые элементы исходного массива.

Вопрос как написать в индекс условие которое к имеющейся проверке элемента на значение проверит, что 2 соседа ЛИБО по (горизонталям/вертикалям/диагоналями) равные единицам.

Офлайн

#2 Март 28, 2017 20:42:24

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Numpy: Составное условие проверки элемента массива

да это же крестики-нолики там всего 8 вариантов, забей их все, а потом перебирай, ставя по почереди во все поля где 0 единицы и сравнивай, если сошлось с одним из 8-ми выиграшных вариантов, туда и лепи двойку.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Офлайн

#3 Март 28, 2017 21:11:20

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

Numpy: Составное условие проверки элемента массива

mick_g
2 - крестики
1 - нолики
0 - пустые поля
1 - крестик
-1 - нолик
0 - пустое

Офлайн

#4 Март 29, 2017 04:45:43

scidam
Зарегистрирован: 2016-06-15
Сообщения: 288
Репутация: +  35  -
Профиль   Отправить e-mail  

Numpy: Составное условие проверки элемента массива

Для игрового поля 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)

На python3.5, numpy 1.11.2 – все работает… но, конечно, здесь нужно хорошо все протестировать…

Офлайн

#5 Март 29, 2017 09:30:55

mick_g
Зарегистрирован: 2017-02-13
Сообщения: 10
Репутация: +  0  -
Профиль   Отправить e-mail  

Numpy: Составное условие проверки элемента массива

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

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version