Логика, используемая для перемещения в матрице, не работает

#python #python-3.x #matrix #chess

#python #python-3.x #матрица #шахматы

Вопрос:

Я создаю шахматы на Python. Я изо всех сил пытаюсь переместить фигуру на доске, которая состоит из 8 списков, вот так:

 [['___' for z in range(x)] for z in range(x)]  # z is 8 in this instance
  

Довольно печатно это выглядит так:

       a      b      c      d      e      f      g      h

8  ['___', '___', '___', '___', '___', '___', '___', '___']  8

7  ['___', '___', '___', '___', '___', '___', '___', '___']  7

6  ['___', '___', '___', '___', '___', '___', '___', '___']  6

5  ['___', '___', '___', '___', '___', '___', '___', '___']  5

4  ['___', '___', '___', '___', '___', '___', '___', '___']  4

3  ['___', '___', '___', '___', '___', '___', '___', '___']  3

2  ['___', '___', '___', '___', '___', '___', '___', '___']  2

1  ['___', '___', '___', '___', '___', '___', '___', '___']  1

      a      b      c      d      e      f      g      h
  

Я размещаю фигуру на доске:

 def create(self):
        Config.board[self.y][self.x] = self.pieceid
  

Тогда это выглядит так:

       a      b      c      d      e      f      g      h

8  ['___', '___', '___', '___', '___', '___', '___', '___']  8

7  ['___', '___', '___', '___', '___', '___', '___', '___']  7

6  ['___', '___', '___', '___', '___', '___', '___', '___']  6

5  ['___', '___', '___', '___', '___', '___', '___', '___']  5

4  ['___', '___', '___', '___', '___', '___', '___', '___']  4

3  ['___', '___', '___', '___', '___', '___', '___', '___']  3

2  ['___', '___', '___', '___', '___', '___', '___', '___']  2

1  ['___', '___', '___', '___', 'wN1', '___', '___', '___']  1

      a      b      c      d      e      f      g      h
  

Теперь я проверяю возможные ходы коня (проверка еще не реализована):

 def possible_moves(self):
        pos_moves = []

        # Up, Right (1 space, 2 spaces)
        try:
            if 1 <= self.x   2 <= len(Config.board) and 1 <= self.y - 1 <= len(Config.board):
                if Config.board[self.x   2][self.y - 1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   2)}{Config.tile_convert(self.y - 1, True)}')
        except IndexError: pass

        #Up, Left
        try:
            if 1 <= self.x - 2 <= len(Config.board) and 1 <= self.y - 1 <= len(Config.board):
                if Config.board[self.x - 2][self.y - 1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 2)}{Config.tile_convert(self.y - 1, True)}')
        except IndexError: pass

        # Down, Right
        try:
            if 1 <= self.x   2 <= len(Config.board) and 1 <= self.y   1 <= len(Config.board):
                if Config.board[self.x   2][self.y   1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   2)}{Config.tile_convert(self.y   1, True)}')
        except IndexError: pass

        #Down, Left
        try:
            if 1 <= self.x - 2 <= len(Config.board) and 1 <= self.y   1 <= len(Config.board):
                if Config.board[self.x - 2][self.y   1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 2)}{Config.tile_convert(self.y   1, True)}')
        except IndexError: pass

        # Right, Up
        try:
            if 1 <= self.x   1 <= len(Config.board) and 1 <= self.y - 2 <= len(Config.board):
                if Config.board[self.x   1][self.y - 2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   1)}{Config.tile_convert(self.y - 2, True)}')
        except IndexError: pass

        # Right, Down
        try:
            if 1 <= self.x   1 <= len(Config.board) and 1 <= self.y   2 <= len(Config.board):
                if Config.board[self.x   1][self.y   2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   1)}{Config.tile_convert(self.y   2, True)}')
        except IndexError: pass

        #Left, Up
        try:
            if 1 <= self.x - 1 <= len(Config.board) and 1 <= self.y - 2 <= len(Config.board):
                print('Current: ', self.x, self.y)
                print('New: ', self.x - 1, self.y - 2)
                if Config.board[self.x - 1][self.y - 2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 1)}{Config.tile_convert(self.y - 2, True)}')
        except IndexError: pass

        # Left, Down
        try:
            if 1 <= self.x - 1 <= len(Config.board) and 1 <= self.y   2 <= len(Config.board):
                if Config.board[self.x - 1][self.y   2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 1)}{Config.tile_convert(self.y   2, True)}')
        except IndexError: pass

        return pos_moves
  

И если перемещение находится в пределах этих возможных ходов, я перемещаю его:

  def move(self, pos):
        if pos in self.possible_moves():
            Config.board[self.y][self.x] = '___'

            self.x = Config.tile_convert(pos[0])
            self.y = Config.tile_convert(pos[1], True)

            Config.board[self.y][self.x] = self.pieceid
  

Тем не менее, по какой-то причине координаты выходят из строя, и фрагмент не может перемещаться, когда он должен быть в состоянии:

 knight1.move('f3')
time.sleep(2)
knight1.move('g5')
time.sleep(2)
knight1.move('h7')
time.sleep(2)
print(knight1.possible_moves())  # f8 should be in here
knight1.move('f8') #  fails
  

Печатая координаты, я пришел к выводу, что проблема в том, что они обновляются некорректно. Что не так с моей логикой?

Это мой tile_convert() метод:

 def tile_convert(cls, x, disp=False):
        if not disp:
            if isinstance(x, str):
                return cls.letters.index(x)
            else:
                return cls.letters[x]
        else:
            return len(Config.board) - int(x)
  

Вот мой полный код, если вы хотите его запустить:

 import time

class Config:
    letters = tuple('abcdefghijklmnopqrstuvwxyz')


    @classmethod
    def new_board(cls, btype):
        def size(x):
            return [['___' for z in range(x)] for z in range(x)]

        if 'custom' in btype.lower():
            btype = int(btype.replace('custom', '').strip())
            cls.board = size(btype)
        elif btype.lower() == 'default':
            cls.board = size(8)
        elif btype.lower() == 'extended':
            cls.board = size(10)
        elif btype.lower() == 'small':
            cls.board = size(5)
        elif btype.lower() == 'max':
            cls.board = size(25)
        elif btype.lower() == 'min':
            cls.board = size(1)

    @classmethod
    def print_board(cls):
        def printl():
            for x in range(len(cls.board)):
                print(' '*6   f'{cls.letters[x]}', end='')
            print('n')

        printl()
        for x in range(len(cls.board)):
            print(f'{len(cls.board)-x}  {cls.board[x]}  {len(Config.board)-x}n')
        printl()
        print('n'*4)

    @classmethod
    def tile_convert(cls, x, disp=False):
        if not disp:
            if isinstance(x, str):
                return cls.letters.index(x)
            else:
                return cls.letters[x]
        else:
            return len(Config.board) - int(x)

class ChessPiece:
    def __init__(self, pos, color, num, piece):
        self.x = int(Config.tile_convert(pos[0]))
        self.y = len(Config.board) - int(pos[1])
        self.color = color
        self.pieceid = num
        self.set_id()
        self.create()

    def __str__(self):
        return self.__class__.__name__

    def set_id(self):
        if self.__class__.__name__ != "Knight":
            self.pieceid = f'{piece[0]}{self.pieceid}'
        else:
            self.pieceid = f'N{self.pieceid}'

        if self.color is not None:
            if self.color.lower() in ('black', 'white', 'b', 'w'):
                self.pieceid = self.color.lower()[0]   self.pieceid
                if self.color.lower() == 'b':
                    self.color = 'black'
                elif self.color.lower() == 'w':
                    self.color = 'white'
            else:
                self.color = None
                print("Invalid color input. Color not set.")
                self.set_id()
        else:
             self.pieceid = '_'   self.pieceid


    def create(self):
        Config.board[self.y][self.x] = self.pieceid

    def move(self, pos):
        if pos in self.possible_moves():
            Config.board[self.y][self.x] = '___'

            self.x = Config.tile_convert(pos[0])
            self.y = Config.tile_convert(pos[1], True)

            Config.board[self.y][self.x] = self.pieceid

            Config.print_board()

        else:
            print(f'Unable to move to {pos}')


    def get_info(self):
        print(f'{self.__class__.__name__}:n')
        print('ID: ', self.pieceid)
        print('Position: ', Config.tile_convert(self.x), Config.tile_convert(self.y, True), sep='')
        print('Color: ', self.color)


class Knight(ChessPiece):
    def __init__(self, pos, color=None, num=''):
        ChessPiece.__init__(self, pos, color, num, self.__class__.__name__)


    def possible_moves(self):
        pos_moves = []

        # Up, Right (1 space, 2 spaces)
        try:
            if 1 <= self.x   2 <= len(Config.board) and 1 <= self.y - 1 <= len(Config.board):
                if Config.board[self.x   2][self.y - 1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   2)}{Config.tile_convert(self.y - 1, True)}')
        except IndexError: pass

        #Up, Left
        try:
            if 1 <= self.x - 2 <= len(Config.board) and 1 <= self.y - 1 <= len(Config.board):
                if Config.board[self.x - 2][self.y - 1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 2)}{Config.tile_convert(self.y - 1, True)}')
        except IndexError: pass

        # Down, Right
        try:
            if 1 <= self.x   2 <= len(Config.board) and 1 <= self.y   1 <= len(Config.board):
                if Config.board[self.x   2][self.y   1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   2)}{Config.tile_convert(self.y   1, True)}')
        except IndexError: pass

        #Down, Left
        try:
            if 1 <= self.x - 2 <= len(Config.board) and 1 <= self.y   1 <= len(Config.board):
                if Config.board[self.x - 2][self.y   1] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 2)}{Config.tile_convert(self.y   1, True)}')
        except IndexError: pass

        # Right, Up
        try:
            if 1 <= self.x   1 <= len(Config.board) and 1 <= self.y - 2 <= len(Config.board):
                if Config.board[self.x   1][self.y - 2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   1)}{Config.tile_convert(self.y - 2, True)}')
        except IndexError: pass

        # Right, Down
        try:
            if 1 <= self.x   1 <= len(Config.board) and 1 <= self.y   2 <= len(Config.board):
                if Config.board[self.x   1][self.y   2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x   1)}{Config.tile_convert(self.y   2, True)}')
        except IndexError: pass

        #Left, Up
        try:
            if 1 <= self.x - 1 <= len(Config.board) and 1 <= self.y - 2 <= len(Config.board):
                print('Current: ', self.x, self.y)
                print('New: ', self.x - 1, self.y - 2)
                if Config.board[self.x - 1][self.y - 2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 1)}{Config.tile_convert(self.y - 2, True)}')
        except IndexError: pass

        # Left, Down
        try:
            if 1 <= self.x - 1 <= len(Config.board) and 1 <= self.y   2 <= len(Config.board):
                if Config.board[self.x - 1][self.y   2] == '___':
                    pos_moves.append(f'{Config.tile_convert(self.x - 1)}{Config.tile_convert(self.y   2, True)}')
        except IndexError: pass

        return pos_moves


Config.new_board('default')
Config.print_board()

knight1 = Knight('e1', color='w', num=1)

Config.print_board()

# knight1.get_info()

# print('nnnPossible Moves:', knight1.possible_moves())

knight1.move('f3')
time.sleep(2)
knight1.move('g5')
time.sleep(2)
knight1.move('h7')
time.sleep(2)
print(knight1.possible_moves())
knight1.move('f8')
  

Комментарии:

1. Почему вы используете disp=True при настройке self.y ?

2. Что означает этот параметр? Я не понимаю логику tile_convert .

3. Преобразование с помощью disp=True преобразует отображаемое число y во внутреннее, поскольку внутренние числа возрастают, а отображаемые числа уменьшаются. В этом случае я загружаю отображаемое значение y. В любом случае, значения y, похоже, работают, а значения x, похоже, отключены

4. Вам действительно нужно, try/except IndexError когда вы проверяете индекс с помощью if инструкций?

5. Вот почему код прерывается без try , потому что ваши if тесты неверны.

Ответ №1:

Ваши проверки индекса possible_moves неверны, потому что индексы списка переходят от 0 к len(Config.board)-1 , а не от 1 к len(Config.board) .

Вы можете значительно упростить код, используя цикл, чтобы попробовать все различные перемещения, и установить переменные, чтобы вам не приходилось постоянно повторять длинные выражения.

 def possible_moves(self):
    pos_moves = []
    boardlen = len(Config.board)
    for xoff, yoff in [(1, 2), (-1, 2), (1, -2), (-1, -2), (2, 1), (-2, 1), (2, -1), (-2, -1)]:
        newx = self.x   xoff
        newy = self.y   yoff
        if 0 <= newx < boardlen and 0 <= newy < boardlen and Config.board[newy][newx] == '___':
            pos_moves.append(f'{Config.tile_convert(newx)}{Config.tile_convert(newy, True)}')
    return pos_moves