首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TicTacToe在Python3 w/简单AI中的应用

TicTacToe在Python3 w/简单AI中的应用
EN

Code Review用户
提问于 2017-01-06 15:41:32
回答 1查看 1.7K关注 0票数 9

下面是我在python3.x上的TicTacToe版本

我正在学习蟒蛇几个星期,如果你看一下我的脚本并复习它,我会非常高兴的!

我已经使用NumPad输入移动,使游戏更加用户友好。5表示中间,7表示右上角,6表示右侧,等等.

代码语言:javascript
复制
from random import randint, choice
from os import system as bash
from time import time


def intInput(StringToDisplay):
    # Simply checks that input is valid integer
    while True:
        try:
            x = int(input(StringToDisplay))
            return x
            break
        except ValueError:
            print('Input integer number, please')
        except Exception:
            print('Unexpected error or keyboard interrupt')


def drawBoard():
    print('\
 ╔═══╦═══╦═══╗\n\
 ║ {0} ║ {1} ║ {2} ║\n\
 ╠═══╬═══╬═══╣\n\
 ║ {3} ║ {4} ║ {5} ║\n\
 ╠═══╬═══╬═══╣\n\
 ║ {6} ║ {7} ║ {8} ║\n\
 ╚═══╩═══╩═══╝ '.format(
               board_status[7], board_status[8], board_status[9],
               board_status[4], board_status[5], board_status[6],     
               board_status[1], board_status[2], board_status[3]))


def askPlayerLetter():
    # Function that asks which letter player wants to use
    print('Do you want to be X or O?')
    Letter = input().upper()
    while Letter != 'X' and Letter != 'O':
        print('Please type appropriate symbol')
        Letter = input('Prompt: ').upper()
    if Letter == 'X':  # then X will be used by player; O by computer
        return ['X', 'O']
    else:
        return ['O', 'X']


def whoGoesFirst():
    # Timer used to count 0.75 seconds while displaying who goes first
    if randint(0, 1) == 0:
        CurrentTime, Timer = time(), time() + 0.75
        print('You go first')
        while Timer > CurrentTime:
            CurrentTime = time()
        return 'player'
    else:
        CurrentTime, Timer = time(), time() + 0.75
        print('Computer goes first')
        while Timer > CurrentTime:
            CurrentTime = time()
        return 'computer'


def makeMove(Board, Move, Letter):
    Board[Move] = Letter


def isSpaceFree(Board, Move):
    return Board[Move] == ' '


def playerMove():
    Move = 0
    while not (0 < Move < 10) or not (isSpaceFree(board_status, int(Move))):
        Move = intInput('Enter your move: ')
    return int(Move)


def isWinner(brd, lttr):
    # Returns a boolean value. brd (board) and lttr (letter) used to make
    # code block compact.
    return ((brd[7] == lttr and brd[8] == lttr and brd[9] == lttr) or
            (brd[4] == lttr and brd[5] == lttr and brd[6] == lttr) or
            (brd[1] == lttr and brd[2] == lttr and brd[3] == lttr) or
            (brd[7] == lttr and brd[5] == lttr and brd[3] == lttr) or
            (brd[9] == lttr and brd[5] == lttr and brd[1] == lttr) or
            (brd[7] == lttr and brd[4] == lttr and brd[1] == lttr) or
            (brd[8] == lttr and brd[5] == lttr and brd[2] == lttr) or
            (brd[9] == lttr and brd[6] == lttr and brd[3] == lttr))


def computerMove():
    '''
    Simple AI that checks
    1)Can computer win in the next move
    2)Can player win in the next move
    3)Is there any free corner
    4)Is center is free
    5)Is there any free side
    And returns a move digit

    '''


    for i in range(1, 10):
        Copy = board_status.copy()
        if isSpaceFree(Copy, i):
            makeMove(Copy, i, ComputerLetter)
            if isWinner(Copy, ComputerLetter):
                return i

    for i in range(1, 10):
        Copy = board_status.copy()
        if isSpaceFree(Copy, i):
            makeMove(Copy, i, PlayerLetter)
            if isWinner(Copy, PlayerLetter):
                return i

    move = randomMoveFromList([7, 9, 1, 3])
    if move is not None:
        return move

    if isSpaceFree(board_status, 5):
        return 5

    move = randomMoveFromList([8, 4, 2, 6])
    if move is not None:
        return move


def randomMoveFromList(MovesList):
    PossibleMoves = []
    for i in MovesList:
        if isSpaceFree(board_status, i):
            PossibleMoves.append(i)
    if len(PossibleMoves) != 0:
        return choice(PossibleMoves)
    else:
        return None


def isBoardFull():
    for i in range(1, 10):
        if isSpaceFree(board_status, i):
            return False
    return True


def playAgain():
    print('Do you want to play again? [y/N]')
    PlayAgainInput = input().lower()
    return (PlayAgainInput.startswith('y') or PlayAgainInput == '')

# "bash('clear')" function simply clears the screen of the terminal.
# If you want run this script on system that uses other shell then
# substitute "clear" with a command that your shell uses to clear the screen
# P.S. for windows it is "cls".

bash('clear')
print('Welcome to Tic Tac Toe')
PlayAgainWish = True
print('To win, you have to place 3 X-s or O-s in a row.\n\
Use NumPad to enter your move (!). Here is the key map.')
board_status = ['', 1, 2, 3, 4, 5, 6, 7, 8, 9]
drawBoard()
print('You have to be sure that you are making move to a free cell.\n\n')
PlayerLetter, ComputerLetter = askPlayerLetter()
while PlayAgainWish:
    bash('clear')
    board_status = 10 * [' ']
    turn = whoGoesFirst()
    while True:
        if turn == 'player':
            bash('clear')
            print('   YOUR MOVE')
            drawBoard()
            move = playerMove()
            makeMove(board_status, move, PlayerLetter)
            turn = 'computer'
            if isWinner(board_status, PlayerLetter):
                bash('clear')
                print('Hooray, you have won the game!')
                drawBoard()
                PlayAgainWish = playAgain()
                break
            elif isBoardFull():
                bash('clear')
                print("It's a tie!")
                drawBoard()
                PlayAgainWish = playAgain()
                break
        else:
            # All this dots and timers are used to make animation of
            # computer moving. You will understand if you will run the script.
            for i in ['', '.', '..', '...']:
                bash('clear')
                print(' Computer is making move' + i)
                drawBoard()
                CurrentTime, Timer = time(), time() + 0.15
                while Timer > CurrentTime:
                    CurrentTime = time()
                if i == '..':
                    move = computerMove()
                    makeMove(board_status, move, ComputerLetter)
                    turn = 'player'
            if isWinner(board_status, ComputerLetter):
                bash('clear')
                print('Oops, you lose!')
                drawBoard()
                PlayAgainWish = playAgain()
                break
            elif isBoardFull():
                bash('clear')
                print("It's a tie!")
                DrawBoard()
                PlayAgainWish = playAgain()
                break
EN

回答 1

Code Review用户

发布于 2017-01-06 18:57:18

少数观察:

  1. 在任何地方插入\ns都会使您的代码看起来有些混乱。相反,使用Python对原始字符串的支持,形式为r"..."。注意双引号前面的r前缀。这就是将字符串指定为原始字符串的原因。在原始字符串中,每个字符都存储WYSIWYG,这意味着字符串中的换行符将被保留。
  2. 避免脚本用户选择正确的清除屏幕命令的负担。可以通过:>>> import os >>> os.name检测Python中的操作系统--这将导致'nt' for Windows,而'posix'用于POSIX系统,就像任何Unix派生(包括Linux )一样。使用上述数据,您可以决定是使用system('clear')还是system('cls')。然后,您可以考虑将导入重命名为bash以外的其他内容,或者根本不重命名它(正如我所展示的)。
  3. 减少代码中无法解释的“魔术数字”的数量。您可以为诸如行数或列数等内容硬编码10。用声明的常量或函数参数替换它们,并遵循PEP8命名约定。
  4. 您硬编码了很多检查,从而阻止了对较大网格的可伸缩性。使用循环和布尔累加器来检查条件,特别是对于isWinner(),可以帮助达到这个目的。循环也可用于生成输出所需的格式字符串。
  5. 也许你应该包括一些命令行的帮助(特别是关于如何玩)?

风格

这些都是基于PEP8风格指南的建议。

  1. 对于三引号字符串,请始终使用双引号以与PEP 257中的docstring约定保持一致。
  2. 在Python中,接受的样式是使用以大写字母开头的名称作为类名和类型名称,因此变量应该是:方法名称和实例变量使用函数命名规则:小写,必要时用下划线分隔单词,以提高可读性。
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/151871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档