Получайте удовольствие от пользовательского класса, чтобы играть в Column4 на консоли
После моего последнего туториала Крестики-нолики (ссылка) мне захотелось создать еще одну игру на основе оболочки с Python. Когда я был ребенком, я много играл в Connect4 (puissance 4 по-французски), и эта игра напомнила мне много воспоминаний. Вот почему я хотел создать свою собственную игру с классом Python.
Прежде всего, я должен признать, что я не убийца в математике, поэтому просто думать о том, как узнать, что одна диагональ заполнена тот же маркер заставляет меня иметь несколько плохих ночей. Но вы увидите, я нашел способ, который отлично работает, и на самом деле не так ориентирован на математику…
Я поделюсь с вами всем кодом в конце этой статьи, если вы хотите его пропустить. Если нет, я буду делиться им блок за блоком, чтобы объяснить вам логику всего этого.
Во-первых, вам нужно немного узнать о классах Python, я не буду объяснять здесь всю концепцию (в Интернете есть множество статей, я даже создал одну самостоятельно, если вы хотите посмотреть.
Давайте начнем с создания собственного класса с некоторыми основными параметрами внутри метода __init__:
class Connect4: def __init__(self): self.numberOfColumns = 7 self.numberOfColumns = 6 self.board = [ [ ' ' for _ in range(self.numberOfColumns)] for _ in range(self.numberOfLines) ]
По сути, здесь мы определяем наш класс, начиная с метода __init__, что означает, что каждый раз, когда вызывается наш класс, три элемента numberOfColumns, numberOfColumns и board также будут создаваться.
Это создаст список из 6 списков, каждый один содержит 7 элементов (которые будут нашими столбцами). Каждый элемент пуст.
def displayBoard(self): for i, line in enumerate(self.board): # Printing the line separators print("_" * self.numberOfColumns * 4) # Printing the line print(*line, sep=' |') # Printing numbers print(' '.join(str(x) for x in range(self.numberOfColumns))) def isAvailable(self, line, column): if line[column] == ' ': return True return False def player_choice(self): choice = int(input("Please select an empty space between 0 and 6 : ")) while self.board[0][choice] != ' ': choice = int(input("This column is full. Please choose between 0 and 6 : ")) return choice def player_input(self): player1 = input("Please pick a marker 'X' or 'O' ") while True: if player1.upper() == 'X': player2='O' print("You've choosen " + player1 + ". Player 2 will be " + player2) return player1.upper(),player2 elif player1.upper() == 'O': player2='X' print("You've choosen " + player1 + ". Player 2 will be " + player2) return player1.upper(),player2 else: player1 = input("Please pick a marker 'X' or 'O' ") def play(self, playercolumn, marker): for item in reversed(self.board): if self.isAvailable(item, playercolumn): item[playercolumn] = " " + marker return True return False
Здесь у нас есть четыре основные функции для работы с пользовательским выбором и печатью.
- displayBoard : отображать доску на основе нашего основного списка под названием self.board.
- isAvailable : вернуть True или False, если слот доступен для игры
- player_choice : выберите столбец для игры
- player_input : выбор маркера для игроков
- игра : поместите маркер
Итак, сейчас мы начнем с самых простых функций, которые легко понять. Теперь пришло время проверить, выиграл ли кто-нибудь раунд!
def checkLines(self, marker, board=None): if board is None: board=self.board # Checkin lines for line in board: for i in range(0,len(line)): if i < len(line) - 3: if line[i] == line[i+1] == line[i+2] == line[i+3] == " " + marker: return True def checkDiags(self, marker): diagBoard = [] for i, line in enumerate(self.board): for idx, item in enumerate(line): # Find of there is some marker if item == ' ' + marker: diagBoard.append(int(str(i)+str(idx))) for item in diagBoard: if int(item) + 11 in diagBoard and int(item) + 22 in diagBoard and int(item) + 33 in diagBoard: return True for item in reversed(diagBoard): if int(item) - 9 in diagBoard and int(item) - 18 in diagBoard and int(item) - 27 in diagBoard: return True def generateReversedBoard(self): reversedBoard = [] for line in self.board: for index, item in enumerate(line): try: reversedBoard[index].append(item) except: reversedBoard.append([]) reversedBoard[index].append(item) return reversedBoard
Итак, что нам здесь нужно? Функция для проверки заполнения строк. Может быть хорошей идеей использовать эту функцию как для столбцов, так и для строк.
Таким образом, эта функция будет проверять, только если в строке есть 4 маркера подряд. Чтобы также проверить столбцы, нам может понадобиться преобразовать столбцы в строки.
Это достигается функцией generateReversedBoard, которая использует доску по умолчанию (self.board) и возвращает ту же доску, но перевернутую.
Теперь обе платы можно проверить с помощью нашей функции checkLines. По умолчанию он использует self.board в качестве доски по умолчанию. Но вы можете передать плату в качестве параметра, чтобы перегрузить этот параметр. Эта функция проверит, есть ли у вас 4 одинаковых маркера в строке со следующим оператором
if i < len(line) - 3: # Avoid out of range exception if line[i] == line[i+1] == line[i+2] == line[i+3] == " " + marker:
Затем нам нужно, чтобы кто-то выиграл по диагонали. Эта функция будет применять следующую логику:
Таким образом, мы преобразуем каждый маркер в строку из двух цифр, где обе цифры: цифра горизонтальной линии + цифра вертикальной линии
Это помещается в список, где мы можем применить базовую функцию:
# Check if someone won from left to the right if int(item) + 11 in diagBoard and int(item) + 22 in diagBoard and int(item) + 33 in diagBoard: return True OR # Check if someone won from right to the left if int(item) - 9 in diagBoard and int(item) - 18 in diagBoard and int(item) - 27 in diagBoard: return True
Итак, в нашем примере мы ясно видим, что выиграл маркер «О». И это проверяется в нашем списке, который содержит следующие элементы, соответствующие нашему первому оператору if: [00, 11,21, 22, 33].
Последний шаг, нам нужно вызвать наш класс, чтобы начать играть в игру (здесь все очень просто, я позволю вам обратиться к командам из кода для пояснений).
c = Connect4() # First while lopp init game = True while game: # Choose your marker players = c.player_input() # Display the board c.displayBoard() # Second while loop init win = False i = 1 while not win: # Start Playing if i % 2 == 0: currentPlayer = "Player1" marker = players[1] else: currentPlayer = "Player2" marker = players[0] # Player to choose where to put the mark position = c.player_choice() if not c.play(position, marker): print(f"Column {position} full") # Generate the reversed board reversedBoard = c.generateReversedBoard() # Check if won if c.checkLines(marker) or c.checkLines(marker, reversedBoard) or c.checkDiags(marker): # update the win to exit the second while loop win = True c.displayBoard() print(f"Game won by {currentPlayer}") # Ask for replay. # If no, change the first loop game = True to False # If yes, reset our class with fresh new datas replay = input("Do you want to play again (Y/N) ? ") if replay.lower() == 'n': game = False print("Game ended !") else: c = Connect4() break c.displayBoard() i += 1
Итак, я надеюсь, что всем понравился этот урок, я знаю, что отображение не идеально, но это не было здесь целью, если кто-то может исправить это, пожалуйста, не стесняйтесь :)
Дайте мне знать, что вы думаете об этой статье, и не стесняйтесь использовать раздел комментариев, чтобы поделиться своими идеями.
Вот полный список доступных:
https://gist.github.com/gmariette/232599715b45e8b5412113ea40f52d92