<p>我尊重您的自学能力,因此我花了一些时间学习python的基础知识,让您思考一些问题。我还不是python爱好者,所以我可能在某个地方做了一些误导性的操作(因此,如果有一个比我更好的程序员在读这篇文章并发现了一些糟糕的东西,请让我知道),但我相信这大部分是好东西</p>
<p>我使用了<code>class</code>,因为我倾向于在<a href="https://dev.to/charanrajgolla/beginners-guide---object-oriented-programming" rel="nofollow noreferrer">OOP</a>中思考(一段时间后你也会这样)。我看到的不是X和O的网格,而是这样的游戏:</p>
<p><a href="https://i.stack.imgur.com/5tv3o.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5tv3o.png" alt="Tic-tac-toe"/></a></p>
<ol>
<li>一个游戏就是一个目标</李>
<li><p>游戏管理:</p>
<p>网格(也是一个对象)</p>
<p>轮到谁了(当轮到人工智能时,人工智能应该如何发挥)</p>
<p>比赛结束时</p></li>
<li><p>网格管理:</p>
<p>9例(也是实物)</p></li>
<li><p>案例管理:</p>
<p>它自己画(所以…是坐标之类的)</p>
<p>如果上面有X或O</p>
<p>如果已单击它</p></li>
</ol>
<p>我完全意识到,当你开始编程时,对象是学习曲线上的一个巨大障碍,但我坚持在这里,因为我在你的代码中看到了很多硬编码,当你扩展你的项目时,这种东西会给你带来问题</p>
<p>硬编码,比如你如何检查哪一个案例被点击,从本质上来说并不坏,但它让一切变得更加困难。这是你有时通过“艰苦的方式”学到的东西的一部分,所以我的建议是:当你忍者编写一些东西(写得很快的短代码片段,不会成为更大的东西的一部分)时,它不是很好,但它确实起到了作用。在任何其他情况下,它必须是出于某种特定的需要,成为一种良好的实践,即使在这种情况下,大多数情况下也可以避免</p>
<p>这里是基于我刚刚写的注释代码。我没有做整个tic-tac-toe游戏,只是在玩家或玩家/人工智能之间切换(我在上面放了一个布尔值,让你在人类对手和人工智能对手之间切换)。缺少的主要是人工智能逻辑(我把一个临时逻辑放在它选择找到的第一个案例的地方)和胜利条件</p>
<p>布尔值当前处于“玩家对玩家”模式。将其更改为<code>True</code>,让AI接管O端</p>
<pre><code># 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)
</code></pre>
<p>您应该将此代码复制并粘贴到Processing.py IDE中,然后重试。闲逛并阅读评论。如果你尝试,你可以在这里学到很多东西。如果你有问题,请用我的手柄在评论中提问,我会回来帮你</p>
<p>而且。。。玩得开心</p>