Python教程-用Python编写的井字游戏
在下面的教程中,我们将使用Python编程语言从头开始创建一个名为井字游戏的游戏。我们将整个程序分为不同的步骤,以便更好地理解。但在开始操作之前,让我们先了解一下这个游戏。
什么是井字游戏?
井字游戏是两名玩家之间进行的一种游戏,游戏是在一个3 x 3的方格网格上进行的。每位玩家在自己的回合中占据一个单元格,目标是在垂直、水平或对角线方向上放置三个相同的标记。第一个玩家使用叉号(X)作为标记,而另一个玩家使用零(O)。
现在,让我们了解井字游戏的设计。
井字游戏的设计
我们将使用命令提示符来玩井字游戏。因此,构建井字游戏的设计是主要目标。
目标:如果玩家需要标记特定的方块,他/她必须在终端中输入网格中显示的相应数字。例如,如果我们想要占据右上角的方块,那么我们必须在终端中输入数字3。
让我们了解生成网格的代码片段。
程序:
# Function to print the Tic-Tac-Toe Design
def mytictactoe(val):
print("\n")
print("\t | |")
print("\t {} | {} | {}".format(val[0], val[1], val[2]))
print('\t_____|_____|_____')
print("\t | |")
print("\t {} | {} | {}".format(val[3], val[4], val[5]))
print('\t_____|_____|_____')
print("\t | |")
print("\t {} | {} | {}".format(val[6], val[7], val[8]))
print("\t | |")
print("\n")
解释:
在上面的代码片段中,我们定义了一个用于井字游戏的函数,该函数以值作为参数。这里的val参数是一个包含网格中每个单元格状态的列表。在函数内部,我们打印了井字游戏网格的设计。
现在,下一步是使用数据结构存储数据。
使用数据结构存储数据
任何游戏的原理都依赖于游戏背后的机制。由于我们正在创建一个相对简单的游戏,所包含的机制也很简单。
在任何时间点,都需要两个关键信息:
1.网格状态:我们必须创建一个包含每个单元格状态的数据结构。状态可以是占用或空闲。
2.每位玩家的动作:需要了解每位玩家的过去和现在的动作,即“X”和“O”所占据的位置。
注意:上述数据可以通过网格状态的帮助来访问。但这将需要我们在需要玩家位置时每次遍历此信息。这可以称为时间与空间复杂度的权衡。这是一种为了节省时间而采取的常用技巧。
以下是相同操作的语法:
代码片段:
# Function for a single game of Tic-Tac-Toe
def singlegame(curplayer):
# Representing the Tic-Tac-Toe
val = [' ' for i in range(9)]
# Storing the positions occupied by X and O
playerpos = {'X' : [], 'O' : []}
解释:
在上述代码片段中,我们定义了一个用于井字游戏的单个游戏的函数,其中val表示前一个函数的参数,playerpos存储由叉号(X)和零(O)分别占据的方块的位置。
字符列表中通常有三个值,用于管理网格状态:
- ' ' - 此字符表示空单元格。
- 'X' - 此字符表示X玩家占据的单元格。
- 'O' - 此字符表示O玩家占据的单元格。
每位玩家的动作都存储在一个整数列表的字典中,其中键由'X'和'O'表示对应的玩家。它们的各自列表包括分配给它们在网格中的单元格的数字。
注意:curplayer变量存储着当前进行移动的玩家,如'X'或'O'。
理解游戏循环
每个游戏都包含某种游戏循环,允许玩家玩游戏,直到有玩家获胜或游戏结束为止。在井字游戏中,游戏的每个迭代表示玩家的一个动作。
让我们考虑以下代码片段以设计游戏循环。
语法:
# Loop of Game for a single game of Tic-Tac-Toe
while True:
mytictactoe(val)
解释:
正如我们可以看到的,我们使用while循环来打印函数mytictactoe()的值,为单个井字游戏创建了一个游戏循环。
处理玩家输入
在游戏的每个迭代中,玩家必须提供他们的移动输入。让我们考虑以下语法以处理玩家的输入。
语法:
# Try-Exception block for CHANCE input
try:
print("Player ", curplayer, " turn. Choose your Block : ", end="")
chance = int(input())
except ValueError:
print("Invalid Input!!! Try Again")
continue
# Sanity check for CHANCE input
if chance < 1 or chance > 9:
print("Invalid Input!!! Try Again")
continue
# Checking if the block is not occupied already
if val[chance - 1] != ' ':
print("Oops! The Place is already occupied. Try again!!")
continue
解释:
对于上面的代码片段,我们创建了一个try块来处理玩家的意外值。然后我们处理了ValueError的异常,以便游戏不会停止。然后我们进行了一些合理性检查,例如输入值是否是有效位置,如果是有效位置,它是否已经被填充?
现在,让我们继续下一步。
更新游戏信息
根据玩家提供的输入,我们必须更新游戏的信息,以确保游戏顺利进行。我们可以通过将以下代码片段添加到主项目来更新游戏信息。
语法:
# Updating the game information
# Update the status of the grid
val[chance - 1] = curplayer
# Update the positions of the player
playerpos[curplayer].append(chance)
解释:
在上述代码片段中,我们通过更新网格的状态和玩家的位置来更新游戏信息。val列表将根据当前玩家更新单元格。玩家的位置将添加到当前玩家刚占据的位置。
一旦val列表被更新,我们将调用mytictactoe()函数,网格将如下所示:
输出:
| |
1 | 2 | 3
_____|_____|_____
| |
4 | 5 | 6
_____|_____|_____
| |
7 | 8 | 9
| |
检查胜利或平局
在每一步之后,我们需要检查是否有任何玩家获胜或游戏是否平局。我们可以使用以下语法来进行检查:
语法:
# Calling Function to check Victory
if check_Victory(playerpos, curplayer):
mytictactoe(val)
print("Congratulations! Player ", curplayer, " has won the game!")
print("\n")
return curplayer
# Calling Function to check Tie
if check_Tie(playerpos):
mytictactoe(val)
print("Oh! Game Tied")
print("\n")
return 'D'
解释:
在上述语法中,我们使用if语句来检查胜利或平局。如果singlegame()函数返回当前玩家,那么他/她获胜了游戏。否则,游戏是平局的,会返回'D'。
让我们考虑一个函数,检查是否有玩家获胜。
语法:
# Defining Function to check Victory
def check_Victory(playerpos, curplayer):
# All probable winning combinations
solution = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 4, 7], [2, 5, 8], [3, 6, 9], [1, 5, 9], [3, 5, 7]]
# Loop to check whether any winning combination is satisfied or not
for i in solution:
if all(j in playerpos[curplayer] for j in i):
# Return True if any winning combination is satisfied
return True
# Return False if no combination is satisfied
return False
# Defining Function to check if the game is Tied
def check_Tie(playerpos):
if len(playerpos['X']) + len(playerpos['O']) == 9:
return True
return False
解释:
在上面的代码片段中,我们定义了检查胜利或平局的函数,这些函数是check_Victory()和check_Tie()。
- check_Victory(): 它存储了所有获胜游戏的组合。函数检查当前玩家的位置是否满足任何获胜组合的要求。如果是,它将返回True;否则,它将返回False,表示不满足要求。
- check_Tie(): 这很简单,只需检查是否所有“九”个位置都被占据,游戏就是平局的。
切换当前玩家
每个玩家一次只有一个机会。因此,每次成功移动后,当前玩家将被切换。让我们考虑以下语法以进行切换。
语法:
# Switching moves of the player
if curplayer == 'X':
curplayer = 'O'
else:
curplayer = 'X'
解释:
在上面的代码片段中,我们再次使用if-else语句以切换玩家的移动,即如果当前玩家标记了一个位置,那么当前玩家将被更改,另一个玩家将标记他们的移动。
这些是制作单个游戏时需要关注的一些步骤。但是,我们将创建一个记分板系统,以跟踪想要玩多个游戏的玩家。
输入玩家的名称
由于我们创建了一个记分板,因此有必要显示每个玩家的名称。
以下是用于此目的的语法:
语法:
if __name__ == "__main__":
print("First Player")
FirstPlayer = input("Specify the Name: ")
print("\n")
print("Second Player")
SecondPlayer = input("Specify the Name: ")
print("\n")
解释:
如您所见,我们使用特殊变量name来获取"main"的值。然后,我们为第一个和第二个玩家的名称提供了输入。这将成为程序的入口点,当执行程序时,它将首先要求输入名称。
存储有关游戏的信息
我们必须存储信息,例如当前玩家、玩家的选择(即X或O)、可用的选择(X或O)和记分板。
以下是用于此目的的语法。
语法:
# Storing the player who chooses X and O
curplayer = FirstPlayer
# Storing the Players' choice
playerchoice = {'X' : "", 'O' : ""}
# Storing the options
opt = ['X', 'O']
# Storing the scoreboard
scoreboard = {FirstPlayer: 0, SecondPlayer: 0}
myscoreboard(scoreboard)
解释:
在上面的代码片段中,我们将当前玩家设置为第一个玩家。我们还存储了玩家的选择、可用选项和记分板。
设计记分板
我们将设计一个字典数据结构的记分板。在此记分板中,玩家的名称将充当键,其获胜的总数将充当值。让我们考虑以下语法,以设计Tic-Tac-Toe的记分板。
语法:
def myscoreboard(scoreboard):
print("\t--------------------------------")
print("\t SCORE BOARD ")
print("\t--------------------------------")
listlistofplayers = list(scoreboard.keys())
print("\t ", listofplayers[0], "\t ", scoreboard[listofplayers[0]])
print("\t ", listofplayers[1], "\t ", scoreboard[listofplayers[1]])
print("\t--------------------------------\n")
解释:
在上述代码片段中,我们定义了myscoreboard函数,该函数接受scoreboard作为参数。然后,我们打印了记分板的设计。我们使用.keys()函数将玩家的名称存储为列表,并将它们索引到记分板并显示得分。
创建外部游戏循环
为了维护多场Tic-Tac-Toe比赛,我们需要另一个循环来进行游戏。当前玩家将在每场比赛中选择标记。在每次迭代中,都应显示选择菜单。
让我们考虑以下语法以创建外部游戏循环。
语法:
# Loop for a series of Tic-Tac-Toe game
# The loop executes until the players quit
while True:
# Main Menu for Players
print(curplayer, "will make the choice:")
print("Press 1 for X")
print("Press 2 for O")
print("Press 3 to Quit")
解释:
在上述代码片段中,我们创建了一个while循环,以在每次迭代中显示主菜单,当前玩家可以在其中选择标记(Cross 'X'或Naught 'O')或退出游戏。
输出:
First Player
Specify the Name: Andy
Second Player
Specify the Name: Carlo
--------------------------------
SCORE BOARD
--------------------------------
Andy 0
Carlo 0
--------------------------------
Andy will make the choice:
Press 1 for X
Press 2 for O
Press 3 to Quit
处理和分配玩家的选择
我们需要处理和存储当前玩家每次迭代的选择。让我们考虑以下语法以进行此操作。
语法:
# Try exception for THE_CHOICE input
try:
the_choice = int(input())
except ValueError:
print("Invalid Input!!! Try Again\n")
continue
# Conditions for player choice
if the_choice == 1:
playerchoice['X'] = curplayer
if curplayer == FirstPlayer:
playerchoice['O'] = SecondPlayer
else:
playerchoice['O'] = FirstPlayer
elif the_choice == 2:
playerchoice['O'] = curplayer
if curplayer == FirstPlayer:
playerchoice['X'] = SecondPlayer
else:
playerchoice['X'] = FirstPlayer
elif the_choice == 3:
print("The Final Scores")
myscoreboard(scoreboard)
break
else:
print("Invalid Selection!! Try Again\n")
解释:
在上述代码片段中,我们通过input()函数获取当前玩家的选择。然后,我们对选择进行验证,以确保它是1、2或3。最后,我们根据选择将当前玩家分配为'X'或'O',并更改另一个玩家的选择。
执行游戏
在存储所有所需信息后,我们可以执行一场独立的比赛并记录胜利者。
下面是相应的语法。
语法:
# Storing the winner in a single game of Tic-Tac-Toe
win = singlegame(opt[the_choice - 1])
解释:
在上面的代码片段中,我们已经存储了井字棋单场比赛的获胜者详情。
更新记分牌
在每场井字棋比赛结束后,我们需要更新记分牌。
让我们考虑以下代码片段来更新记分牌。
语法:
# Updation of the scoreboard as per the winner
if win != 'D' :
playerWon = playerchoice[win]
scoreboard[playerWon] = scoreboard[playerWon] + 1
myscoreboard(scoreboard)
解释:
在上面的代码片段中,我们使用了if语句来检查比赛是否不是平局。一旦比赛没有平局,记分牌将被更新。
切换选择玩家
在游戏中,有必要切换选择标记的机会。因此,让我们考虑以下语法来理解切换过程。
语法:
# Switching player who chooses X or O
if curplayer == FirstPlayer:
curplayer = SecondPlayer
else:
curplayer = FirstPlayer
解释:
在上面的代码片段中,我们再次使用if-else语句来在玩家之间切换选择标记(叉或圈)。
因此,我们已经成功构建了我们自己的井字棋游戏。
下载代码
游戏的代码可以从此链接下载: https://static.javatpoint.com/python/download/TicTacToe.zip
游戏时间到了
由于所有步骤最终都完成了,这是游戏的最终输出。
输出:
First Player
Specify the Name: Andy
Second Player
Specify the Name: Carlo
--------------------------------
SCORE BOARD
--------------------------------
Andy 0
Carlo 0
--------------------------------
Andy will make the choice:
Press 1 for X
Press 2 for O
Press 3 to Quit
1
| |
| |
_____|_____|_____
| |
| |
_____|_____|_____
| |
| |
| |
Player X turn. Choose your Block : 5
| |
| |
_____|_____|_____
| |
| X |
_____|_____|_____
| |
| |
| |
Player O turn. Choose your Block : 3
| |
| | O
_____|_____|_____
| |
| X |
_____|_____|_____
| |
| |
| |
Player X turn. Choose your Block : 1
| |
X | | O
_____|_____|_____
| |
| X |
_____|_____|_____
| |
| |
| |
Player O turn. Choose your Block : 9
| |
X | | O
_____|_____|_____
| |
| X |
_____|_____|_____
| |
| | O
| |
Player X turn. Choose your Block : 6
| |
X | | O
_____|_____|_____
| |
| X | X
_____|_____|_____
| |
| | O
| |
Player O turn. Choose your Block : 4
| |
X | | O
_____|_____|_____
| |
O | X | X
_____|_____|_____
| |
| | O
| |
Player X turn. Choose your Block : 2
| |
X | X | O
_____|_____|_____
| |
O | X | X
_____|_____|_____
| |
| | O
| |
Player O turn. Choose your Block : 8
| |
X | X | O
_____|_____|_____
| |
O | X | X
_____|_____|_____
| |
| O | O
| |
Player X turn. Choose your Block : 7
| |
X | X | O
_____|_____|_____
| |
O | X | X
_____|_____|_____
| |
X | O | O
| |
Game Tied
--------------------------------
SCORE BOARD
--------------------------------
Andy 0
Carlo 0
--------------------------------
Carlo will make the choice:
Press 1 for X
Press 2 for O
Press 3 to Quit
3
The Final Scores
--------------------------------
SCORE BOARD
--------------------------------
Andy 0
Carlo 0
--------------------------------