我正在做一个 tic tac toe
在处理游戏时,我不知道如何使一个方法有 X
和 O
swap来模糊地模仿交换回合,我已经看到有人像下面的代码一样做了,但由于某些原因,我要么得到一个错误,要么就是当我把它挂到我现有的代码上时,它就不工作了。
我应该有更多的阐述,我计划(尝试)使用Minimax算法来使这个游戏无法赢。
print("Begin")
global top_left, top_middle, top_right
global middle_left, center, middle_right
global bottem_left, bottem_middle, bottem_right
#these are the variables used to check if someone has put their move their already
#0 = empty
#1 = Circle
#2 = X
top_left = 0
top_middle = 0
top_right = 0
middle_left = 0
center = 0
middle_right = 0
bottem_left = 0
bottem_middle = 0
bottem_right = 0
#code for changing turns
turn = 1
def turn_changer():
global turn
if turn == 1:
turn = 2
else:
turn = 1
#board setup
def setup():
size(600,600)
#this hurt my brain trying to fully understand
#lines dividing board
def draw():
for y in range(3):
for x in range(3):
rect(200*x,200*y,200,200)
#hope this is not what geomtry is like
#top left ellipse
if top_left == 1:
ellipse(100,100,150,150)
#top left X
elif top_left == 2:
line(0,0,200,200)
line(200,0,0,200)
#top middle ellipse
if top_middle == 1:
ellipse(300,100,150,150)
#top middle X
elif top_middle == 2:
line(200,0,400,200)
line(400,0,200,200)
#top right ellipse
if top_right == 1:
ellipse(500,100,150,150)
#top right X
elif top_right == 2:
line(400,0,600,200)
line(600,0,400,200)
#middle left ellipse
if middle_left == 1:
ellipse(100,300,150,150)
#middle left X
elif middle_left == 2:
line(0,200,200,400)
line(200,200,0,400)
#middle ellipse
if center == 1:
ellipse(300,300,150,150)
#middle X
elif center == 2:
line(200,200,400,400)
line(400,200,200,400)
#middle right ellipse
if middle_right == 1:
ellipse(500,300,150,150)
#middle right X
elif middle_right == 2:
line(400,200,600,400)
line(600,200,400,400)
#bottem left ellipse
if bottem_left == 1:
ellipse(100,500,150,150)
#bottem left X
elif bottem_left == 2:
line(0,400,200,600)
line(200,400,0,600)
#bottem middle ellipse
if bottem_middle == 1:
ellipse(300,500,150,150)
#bottem middle X
elif bottem_middle == 2:
line(200,400,400,600)
line(400,400,200,600)
#bottem right ellipse
if bottem_right == 1:
ellipse (500,500,150,150)
#bottem right Xw
elif bottem_right == 2:
line(400,400,600,600)
line(600,400,400,600)
#dectects the quardnates where the mouse clicked and prints them
def mousePressed():
println( (mouseX, mouseY) )
#top left square hitbox
if (mouseX > 0 and mouseX < 200) and (mouseY > 0 and mouseY < 200):
top_left =+ turn
turn_changer()
print("top left")
#top middle square hitbox
elif (mouseX > 200 and mouseX < 400) and (mouseY > 0 and mouseY < 200):
top_middle = turn
turn_changer()
print(turn)
print("top middle")
#top right square hitbox
elif (mouseX > 400 and mouseX < 600) and (mouseY > 0 and mouseY < 200):
top_right = turn
turn_changer()
print("top right")
#middle left square hitbox
elif (mouseX > 0 and mouseX < 200) and (mouseY > 200 and mouseY < 400):
middle_left = turn
turn_changer()
print("middle left")
#center square hitbox
elif (mouseX > 200 and mouseX < 400) and (mouseY > 200 and mouseY < 400):
center = turn
turn_changer()
print("middle")
#middle right square hitbox
elif (mouseX > 400 and mouseX < 600) and (mouseY > 200 and mouseY < 400):
middle_right = turn
turn_changer()
print("middle right")
#bottem left square hitbox
elif (mouseX > 0 and mouseX < 200) and (mouseY > 400 and mouseY < 600):
bottem_left = turn
turn_changer()
print("bottem left")
#bottem middle square hitbox
elif (mouseX > 200 and mouseX < 400) and (mouseY > 400 and mouseY < 600):
bottem_middle = turn
turn_changer()
print("bottem middle")
#bottem right square hitbox
elif (mouseX > 400 and mouseX < 600) and (mouseY > 400 and mouseY < 600):
bottem_right = turn
turn_changer()
print("bottem right")
我尊重你是在自学,所以我花了一些时间来学习python的基础知识,给你一些思考。我不是一个python爱好者(还没有),所以我可能在某些地方做了一些错误的操作(所以如果有比我更优秀的编码者在读这篇文章,并发现了一些可怕的东西,请告诉我),但我相信这大部分是好东西。
我用的是 class
因为我倾向于 OOP (过段时间你也会这样做)。我看到的不是一个有X和O的网格,而是这样的游戏。
一个游戏管理。
一个网格(也是一个对象).
轮到谁了(轮到AI的时候,AI应该怎么玩)。
游戏何时结束。
一个格子管理着。
九个案例(也是一个对象)。
一个Case管理:9个Case(也是对象)。
它自己画画(所以... 它的坐标之类的东西)。
如果它上面有X或O。
如果它被点击了
我完全意识到,当你开始编程时,对象是学习曲线上的一个巨大的障碍,但我在这里坚持,因为我在你的代码中看到了大量的硬编码,当你扩大项目规模时,这些东西会给你带来问题。
硬编码,就像你检查哪个案例被点击一样,本质上并不是坏事,但它让一切变得更加困难。这也是你有时会 "硬着头皮 "学的东西的一部分,所以我的建议是:当你忍者编码的东西(快速编写的短代码片段,不会是更大的东西的一部分),它不是很好,但它能完成工作。在任何其他情况下,它必须是由一些特定的需求所驱动,才是一个好的做法,即使在那里,它也可以在大多数时候避免。
下面是根据我刚才写的注释代码。我并没有做完整的井字游戏,只是到了它在玩家或玩家AI之间切换回合的部分(我在上面放了一个布尔值,让你在人类对手和AI对手之间切换)。缺少的主要是AI逻辑(我放了一个临时的逻辑,它选择它发现的第一个案例)和胜利条件。
布林目前处于 "玩家对战 "模式。把它改成 "玩家对玩家 "模式。True
让AI接管O端。
# Player 1 (X) is human and play first
# Player 2 (O) is cpu
# You can change this boolean to play hotseat with a human if you want:
_AIPlayer = False
# Game own a grid, count turns and do any other game-specific concepts
# One "game of tic-tac-toe" would equal one of this object
class Game:
def __init__(self):
self.Grid = Grid(self) # creating the grid we'll use
self.TurnCount = 0 # first turn is turn number zero
def Render(self):
# when you draw the game, in fact it asks it's grid to draw itself
self.Grid.Render()
def Play(self):
# if it's the CPU's turn, let him play, else the game will wait for the player before going forward
# if there is no cpu player, the mouse can be used by player two
# the difference is that the cpu will do it's turn as a consequence of the player's turn
# and then add +1 to the turn count, while player 2 is exactly like player one but with O instead of X
# the game will check X and O to see who win, not a player class (but it could have been designed that way if needed)
if self.GetCurrentPlayer() == "O" and _AIPlayer:
self.AITurn()
def GetCurrentPlayer(self):
# return which's player is currently playing
if self.TurnCount % 2 == 0:
return "X"
else:
return "O"
def AITurn(self):
# this is a dumb placeholder
# your AI logic will be used here
# for now it just put a O on the first available case
print("AI turn")
for c in self.Grid.Cases:
if c.XO == "":
c.XO = self.GetCurrentPlayer()
break
self.TurnCount += 1
# Grid class is the whole grid
class Grid:
def __init__(self, game):
# the grid knows the game. I could use the global variable instead, but I dislike
# this kind of spaghetti. It would have worked, though.
# It's usually best to make everything you can dynamic, i.e. not hardcoded.
# It's easier to maintain and fix bugs that way, and you can upscale more easily too
# for an example, I could use this code to run several tic-tac-toe games in the
# same window at the same time with only a few modifications
self.Game = game
self.Cases = []
for i in range(3):
for j in range(3):
self.Cases.append(GridCase(i, j))
def Render(self):
# when you draw the grid, in fact it ask it's cases to draw themselves
for c in self.Cases:
c.Render()
def CaseClicked(self, xPos, yPos):
# this checks which case was clicked when it's a player
# since we don't care about the case's coordinated, we ask them if they have been clicked instead
for c in self.Cases:
if c.Clicked(xPos, yPos, self.Game.GetCurrentPlayer()):
self.Game.TurnCount += 1
return
# GridCase is each instance of 1 case in the grid
class GridCase:
def __init__(self, gridX, gridY):
# gridX and gridY are useful to know which case is part of which line
self.gridX = gridX
self.gridY = gridY
# I hardcoded the case's width and height, but you could totally make them dynamic
# and decide "on the fly" how big the grid will be. And it would still work.
self.w = 200 # width
self.h = 200 # height
# these coordinates are in pixels, and are useful to draw the case and for hit detection
self.x = self.w * gridX # x coordinate of the case
self.y = self.h * gridY # y coordinate of the case
# the "content" of the case
self.XO = "" # X or O as a character (it could be anything, I choose to stick to these)
def Render(self):
# the lines positions are dynamic: they'll be calculated from the case's perspective
# every case top left corner is in fact: (self.x, self.y)
rect(self.x, self.y, self.w, self.h)
# if the case has content, it'll be drawn at the same time than the case
if self.XO == "X":
line(self.x , self.y, self.x+self.w, self.y+self.h)
line(self.x, self.y+self.h, self.x+self.w, self.y)
elif self.XO == "O":
ellipse(self.x+(self.w/2),self.y+(self.h/2), self.w*0.75, self.h*0.75)
def SetXO(self, XO):
self.XO = XO
def Clicked(self, xPos, yPos, car):
# if the case is free and the click was inside it's boundaries, then attribute it to the current player
# the return True to tell that a sign was just placed
if self.XO == "" and xPos > self.x and xPos < self.x + self.w and yPos > self.y and yPos < self.y + self.h:
self.XO = car
return True
return False
# globals
_game = Game()
def setup():
size(600,600)
def draw():
# background wipes the screen "clean" (here it paints it black)
# then we can draw the current state of the grid
# here we could do without but I wanted you to know about it
background(0)
# draw the grid, then let the players do their thing
_game.Render()
# here you should check for game end conditions (victory or draw)
_game.Play()
def mouseClicked():
# listeing to mouse clicks
_game.Grid.CaseClicked(mouseX, mouseY)
你应该把这段代码复制粘贴到Processing.py IDE中试试。摆弄一下并阅读注释。如果你尝试的话,你可以在这里学到很多东西。如果你有问题,可以在评论中用我的名字问,我会回来帮你。
还有......玩得开心点
当按钮被按下时,检查转数是否等于1或2,然后告诉程序显示一个十字或圆圈,而不是做一个函数来改变这个值。
希望这能帮到你!
你有很多方法可以做到这一点。
myBoolean = !myBoolean
在每一个回合之后TurnCount
变量。如果你做 TurnCount % 2
结果要么是0,要么是1,这样就可以确定是哪个回合。这个运算符真的很有用,无论怎样你都应该记住它!所以这主要取决于你的代码会有多忍者。如果你要做一个 "简单的热座",玩家轮流用同一个鼠标点击,方法3就很好。如果你想在游戏结束后显示 "统计",方法2会很好地工作。方法1也可以,但它比较粗糙,即使它很简单。如果你需要量身定做的建议,可以多加一些代码。
祝你玩得开心
设置变量'turn'为全局变量(在'turn_changer'函数之外,确保这段代码只运行一次,而不是每次你的游戏循环).运行你的游戏逻辑,玩家(X或O)由'turn'的值决定.在玩家做出他们的举动后,调用'turn_changer',这样回合就改变了.重复.
使用你提供的代码,我添加了这个。
def game():
print (turn)
turn_changer()
print (turn)
turn_changer()
print (turn)
if __name__ == "__main__":
game()
然后turn_changer()函数就可以正常工作了。