Python多人Tic-Tac-Toe游戏故障:对手无法落子+标记显示错误
问题描述
我正在开发一款基于Python的多人Tic-Tac-Toe(井字棋)游戏,目前遇到两个问题:
- 回合无法传递到客户端(guest)侧;
- 棋盘上显示错误的标记位置。
主机侧操作及输出:
Enter row and column numbers to fix spot(row,column): 1,2 - X - - - - - - -
客户端侧输出:
X - - - - - - - -
代码说明:需将提供的源码复制生成两个文件,主机文件调用host_game函数,客户端文件调用connect_to_game函数。已尝试搜索资料、咨询AI,但未解决问题,现附上完整代码寻求帮助。
import socket import threading HOST = '192.168.1.115' PORT = 9090 class TicTacToe: def __init__(self): self.you = 'O' self.opponet = 'X' self.turn = 'X' self.board = [] self.game_over = False self.winner = None self.counter = 0 self.create_board() def create_board(self): for i in range(3): row = [] for j in range(3): row.append('-') self.board.append(row) def show_board(self): for row in self.board: for item in row: print(item, end=" ") print() def is_board_filled(self): for row in self.board: for item in row: if item == '-': return False return True def fix_move(self, row, col, player): if self.game_over: return self.counter +=1 self.board[row-1][col-1] = player self.show_board() if self.is_player_win(player): if self.winner == self.you: print('You win!') exit() if self.winner == self.opponet: print('You lose!') exit() else: if self.counter == 9: print('Its a draw!') exit() def valid_move(self, row, col): if self.board[row][col] == 'O' or self.board[row][col] == 'X': return False return True def swap_player_turn(self): self.turn = self.you if self.turn == self.opponet else self.opponet def handle(self, client): while not self.game_over: if self.turn == self.you: move = input("Enter row and column numbers to fix spot(row,column): ") place = move.split(',') if self.valid_move(int(place[0]), int(place[1])): self.fix_move(int(place[0]), int(place[1]), self.you) self.turn = self.opponet client.send(move.encode('utf-8')) else: print('Invalid Move!') else: data = client.recv(1024) if not data: client.close() break else: place = data.decode('utf-8').split(',') self.fix_move(int(place[0]), int(place[0]), self.opponet) client.close() def is_player_win(self, player): if self.board[0][0] == self.board[0][1] == self.board[0][2] == 'X': return True if self.board[1][0] == self.board[1][1] == self.board[1][2] == 'X' or 'O': return True if self.board[2][0] == self.board[2][1] == self.board[2][2] == 'X' or 'O': return True # etc etc def host_game(self, host, port): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((host, port)) server.listen(1) client, addr = server.accept() self.you = 'X' self.opponet = 'O' threading.Thread(target=self.handle, args=(client,)).start() server.close() def connect_to_game(self, host, port): client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((host, port)) self.you = 'O' self.opponet = 'X' threading.Thread(target=self.handle, args=(client,)).start() game = TicTacToe() game.host_game(HOST, PORT)
问题分析与修复方案
1. 标记位置错误的原因及修复
客户端接收主机移动时,代码错误地将行号同时作为列号传入fix_move:
self.fix_move(int(place[0]), int(place[0]), self.opponet)
修复:将第二个参数改为int(place[1]),确保行和列参数正确分离。
2. 回合无法传递的核心问题及修复
问题点:
- 主机手动修改回合状态,客户端处理完对方移动后未更新回合;
valid_move方法未将用户输入的1-based索引转换为棋盘的0-based索引,导致判断逻辑错误;is_player_win方法硬编码判断'X',且逻辑错误(== 'X' or 'O'永远为True),未正确设置winner和game_over状态;- 回合切换逻辑分散,未统一管理。
修复步骤:
(1)修复valid_move方法
将输入的行/列转换为0-based索引,并增加合法性检查:
def valid_move(self, row, col): row_idx = row - 1 col_idx = col - 1 if 0 <= row_idx < 3 and 0 <= col_idx < 3: return self.board[row_idx][col_idx] == '-' return False
(2)修复is_player_win方法
正确判断当前玩家的获胜条件,并设置全局状态:
def is_player_win(self, player): # 检查行 for row in self.board: if all(cell == player for cell in row): self.winner = player self.game_over = True return True # 检查列 for col in range(3): if all(self.board[row][col] == player for row in range(3)): self.winner = player self.game_over = True return True # 检查对角线 if self.board[0][0] == self.board[1][1] == self.board[2][2] == player: self.winner = player self.game_over = True return True if self.board[0][2] == self.board[1][1] == self.board[2][0] == player: self.winner = player self.game_over = True return True return False
(3)统一回合切换逻辑
修改fix_move方法,在移动处理完成后自动切换回合(游戏未结束时),并移除handle方法中手动修改回合的代码:
def fix_move(self, row, col, player): if self.game_over: return row_idx = row - 1 col_idx = col - 1 self.counter += 1 self.board[row_idx][col_idx] = player self.show_board() if self.is_player_win(player): print('You win!' if self.winner == self.you else 'You lose!') self.game_over = True exit() elif self.counter == 9: print('Its a draw!') self.game_over = True exit() # 自动切换回合 if not self.game_over: self.swap_player_turn()
(4)修复handle方法的接收逻辑
增加输入合法性检查,并移除手动修改回合的代码:
def handle(self, client): while not self.game_over: if self.turn == self.you: move = input("Enter row and column numbers to fix spot(row,column): ") place = move.split(',') if len(place) != 2: print('Invalid input! Use format: row,column') continue try: row = int(place[0]) col = int(place[1]) except ValueError: print('Invalid input! Enter numbers only') continue if self.valid_move(row, col): self.fix_move(row, col, self.you) client.send(move.encode('utf-8')) else: print('Invalid Move!') else: print("Waiting for opponent's move...") data = client.recv(1024) if not data: print("Opponent disconnected!") client.close() self.game_over = True break else: place = data.decode('utf-8').split(',') if len(place) != 2: print("Invalid move from opponent!") continue try: row = int(place[0]) col = int(place[1]) except ValueError: print("Invalid move from opponent!") continue self.fix_move(row, col, self.opponet) client.close()
完整修复后的代码
主机文件(host.py)
import socket import threading HOST = '192.168.1.115' PORT = 9090 class TicTacToe: def __init__(self): self.you = 'O' self.opponet = 'X' self.turn = 'X' self.board = [] self.game_over = False self.winner = None self.counter = 0 self.create_board() def create_board(self): for i in range(3): row = [] for j in range(3): row.append('-') self.board.append(row) def show_board(self): for row in self.board: for item in row: print(item, end=" ") print() def valid_move(self, row, col): row_idx = row - 1 col_idx = col - 1 if 0 <= row_idx < 3 and 0 <= col_idx < 3: return self.board[row_idx][col_idx] == '-' return False def swap_player_turn(self): self.turn = self.you if self.turn == self.opponet else self.opponet def is_player_win(self, player): # 检查行 for row in self.board: if all(cell == player for cell in row): self.winner = player self.game_over = True return True # 检查列 for col in range(3): if all(self.board[row][col] == player for row in range(3)): self.winner = player self.game_over = True return True # 检查对角线 if self.board[0][0] == self.board[1][1] == self.board[2][2] == player: self.winner = player self.game_over = True return True if self.board[0][2] == self.board[1][1] == self.board[2][0] == player: self.winner = player self.game_over = True return True return False def fix_move(self, row, col, player): if self.game_over: return row_idx = row - 1 col_idx = col - 1 self.counter += 1 self.board[row_idx][col_idx] = player self.show_board() if self.is_player_win(player): print('You win!' if self.winner == self.you else 'You lose!') self.game_over = True exit() elif self.counter == 9: print('Its a draw!') self.game_over = True exit() if not self.game_over: self.swap_player_turn() def handle(self, client): while not self.game_over: if self.turn == self.you: move = input("Enter row and column numbers to fix spot(row,column): ") place = move.split(',') if len(place) != 2: print('Invalid input! Use format: row,column') continue try: row = int(place[0]) col = int(place[1]) except ValueError: print('Invalid input! Enter numbers only') continue if self.valid_move(row, col): self.fix_move(row, col, self.you) client.send(move.encode('utf-8')) else: print('Invalid Move!') else: print("Waiting for opponent's move...") data = client.recv(1024) if not data: print("Opponent disconnected!") client.close() self.game_over = True break else: place = data.decode('utf-8').split(',') if len(place) != 2: print("Invalid move from opponent!") continue try: row = int(place[0]) col = int(place[1]) except ValueError: print("Invalid move from opponent!") continue self.fix_move(row, col, self.opponet) client.close() def host_game(self, host, port): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((host, port)) server.listen(1) client, addr = server.accept() self.you = 'X' self.opponet = 'O' threading.Thread(target=self.handle, args=(client,)).start() server.close() game = TicTacToe() game.host_game(HOST, PORT)
客户端文件(client.py)
仅需将最后两行替换为:
game = TicTacToe() game.connect_to_game(HOST, PORT)
内容的提问来源于stack exchange,提问作者Scalobe
相关产品推荐
相关产品推荐

