需要帮助寻找解决决定回合的井字游戏的方法。

问题描述 投票:0回答:1

我正在做一个 tic tac toe 在处理游戏时,我不知道如何使一个方法有 XO 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 processing tic-tac-toe
1个回答
1
投票

我尊重你是在自学,所以我花了一些时间来学习python的基础知识,给你一些思考。我不是一个python爱好者(还没有),所以我可能在某些地方做了一些错误的操作(所以如果有比我更优秀的编码者在读这篇文章,并发现了一些可怕的东西,请告诉我),但我相信这大部分是好东西。

我用的是 class 因为我倾向于 OOP (过段时间你也会这样做)。我看到的不是一个有X和O的网格,而是这样的游戏。

Tic-tac-toe

  1. 一个游戏是一个对象。
  2. 一个游戏管理。

    一个网格(也是一个对象).

    轮到谁了(轮到AI的时候,AI应该怎么玩)。

    游戏何时结束。

  3. 一个格子管理着。

    九个案例(也是一个对象)。

  4. 一个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
投票

当按钮被按下时,检查转数是否等于1或2,然后告诉程序显示一个十字或圆圈,而不是做一个函数来改变这个值。

希望这能帮到你!


1
投票

你有很多方法可以做到这一点。

  1. 你可以翻转一个变量(有点像你刚才展示的)。由于只有两个玩家,我可能会用布尔变量来代替。myBoolean = !myBoolean 在每一个回合之后
  2. 你可以计算回合数,然后使用 模数 操作员。然后你们都知道现在是哪一回合,以及当前游戏的总回合数。假设你有一个全局的 TurnCount 变量。如果你做 TurnCount % 2 结果要么是0,要么是1,这样就可以确定是哪个回合。这个运算符真的很有用,无论怎样你都应该记住它!
  3. 如果玩家1和2之间除了X和O之外,在游戏中没有任何区别,你可以像你的代码片段一样,在字符 "X "和字符 "O "之间翻转,而不是1和2。这个变量可以用来直观地显示哪个符号将被放置或直接放置一个符号或其他。简单又高效。

所以这主要取决于你的代码会有多忍者。如果你要做一个 "简单的热座",玩家轮流用同一个鼠标点击,方法3就很好。如果你想在游戏结束后显示 "统计",方法2会很好地工作。方法1也可以,但它比较粗糙,即使它很简单。如果你需要量身定做的建议,可以多加一些代码。

祝你玩得开心


0
投票

设置变量'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()函数就可以正常工作了。

© www.soinside.com 2019 - 2024. All rights reserved.