首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >第一个合适的程序,Tic Tac Toe

第一个合适的程序,Tic Tac Toe
EN

Code Review用户
提问于 2019-05-18 21:15:14
回答 1查看 64关注 0票数 2

我对编程还是很陌生的,只做了一周。我只是想知道我是否犯了什么明显的错误或者任何可以改进代码的地方?

代码语言:javascript
运行
复制
import random

the_board = []
players = [{'type': 'player', 'piece': 'X'},
           {'type': 'player', 'level': 'smart', 'piece': 'O'}]


def print_board(board):
    for i in range(3):
        print(board[i * 3] + '|' + board[i * 3 + 1] + '|' + board[i * 3 + 2], end='')
        print('   ' + str(i * 3) + '|' + str(i * 3 + 1) + '|' + str(i * 3 + 2))
        if i < 2:
            print('-+-+-' + '   ' + '-+-+-')
    print()


def is_win(bo, player):
    # 0 1 2
    # 3 4 5
    # 6 7 8

    for i in range(3):
        return (bo[i * 3] == player and bo[i * 3 + 1] == player and bo[i * 3 + 2] == player) or \
               (bo[i] == player and bo[i+3] == player and bo[i+6] == player) or \
                (i <= 1 and (bo[i*2] == player and bo[4] == player and bo[8-(i*2)] == player))


def check_board(move, player):
    global the_board
    board_copy = the_board.copy()
    board_copy[move] = players[player]['piece']
    print('win')
    return is_win(board_copy, players[player]['piece'])


def ai():
    global players, the_board
    possible_moves = []
    final_move = None

    for i in range(9):
        if the_board[i] == ' ':
            possible_moves.append(i)

    if the_board[4] == ' ' and players[1]['level'] == 'smart':
        the_board[4] = players[1]['piece']
        return

    for i in range(len(possible_moves)):
        board_copy = the_board.copy()
        board_copy[possible_moves[i]] = players[1]['piece']
        if check_board(possible_moves[i], 1):
            the_board[possible_moves[i]] = players[1]['piece']
            print('win')
            return
        elif check_board(possible_moves[i], 0):
            print('lose')
            final_move = possible_moves[i]
        elif players[1]['level'] == 'smart' and final_move is None:
            if possible_moves[i] in [0, 2, 6, 8]:
                print('random')
                final_move = possible_moves[i]
    else:
        if final_move is not None:
            print('other')
            the_board[final_move] = players[1]['piece']
            return
        print('final')
        the_board[possible_moves[random.randint(0, len(possible_moves))]] = players[1]['piece']



def input_validation(option_type, options, choice):
    global the_board
    if option_type == 'number_range':
        if not str.isdigit(choice):
            print('It has to be a number')
            return False
        else:
            choice = int(choice)
        if choice < options[0] or choice > options[1]:
            print('You have to choose a number between 0 and 8')
            return False
        elif (the_board[choice] == 'X' or the_board[choice] == 'O'):
            print('There is already a move there, please try again.')
            return False
        else:
            return True

    if option_type == 'string':
        for i in range(len(options)):
            if choice == options[i]:
                return True
        else:
            print('That is not a valid option, your choices are:')
            for i in range(len(options)):
                print(options[i])
            else:
                print()
            return False


def player_options():
    valid = False
    global players

    while not valid:
        print('Do you want to play the cpu or player?')
        choice = input()
        choice = choice.lower()
        if input_validation('string', ['cpu', 'player'], choice):
            players[1]['type'] = choice
            break

    while not valid and players[1]['type'] == 'cpu':
        print('Do you want smart or dumb ai?:')
        choice = input()
        choice = choice.lower()
        if input_validation('string', ['smart', 'dumb'], choice):
            if choice == 'dumb':
                players[1]['level'] = choice
            break

    # while not valid:
    #     print('Player 1, do you want to be X or O?:')
    #     choice = input()
    #     choice = choice.upper()
    #     if input_validation('string', ['X', 'O'], choice):
    #         if choice == 'O':
    #             players[1]['piece'] = choice
    #         break


def game():
    move = 0
    turn = random.choice([True, False])

    for i in range(9):
        the_board.insert(i, ' ')

    for i in range(9):
        valid = False

        print_board(the_board)
        if is_win(the_board, players[turn]['piece']):
            print_board(the_board)
            print('Player ' + players[turn]['piece'] + ' is the winner!')
            return

        turn ^= True


        if turn == 0 or (players[1]['type'] == 'player' and turn == 1):
            while not valid:
                move = (input('Turn for ' + players[turn]['piece'] + '. Move on which space?: '))
                if input_validation('number_range', [0, 8], move):
                    move = int(move)
                    valid = True
                    the_board[move] = players[turn]['piece']
        elif players[1]['type'] == 'cpu' and turn == 1:
            ai()
    print_board(the_board)
    print('It is a tie!')

def retry():
    valid = False
    while not valid:
        print('Do you want to play again with the same settings? Y or N')
        choice = input()
        choice = choice.upper()
        if input_validation('string', ['Y', 'N'], choice):
            if choice == 'Y':
                game()
            else:
                player_options()
                game()


player_options()
game()
retry()
```
代码语言:javascript
运行
复制
EN

回答 1

Code Review用户

发布于 2019-05-21 14:35:50

让我们对其进行点到点的升级,并在最后得到更好的代码:

0。我试着运行您的程序,发现了一些用户端的不良行为:

U1。许多不必要的指纹:

代码语言:javascript
运行
复制
Do you want to play the cpu or player?
cpu
Do you want smart or dumb ai?:
smart
 | |    0|1|2
-+-+-   -+-+-
 | |    3|4|5
-+-+-   -+-+-
 | |    6|7|8

 | |    0|1|2
-+-+-   -+-+-
 |O|    3|4|5
-+-+-   -+-+-
 | |    6|7|8

Turn for X. Move on which space?: 4
There is already a move there, please try again.
Turn for X. Move on which space?: 5
 | |    0|1|2
-+-+-   -+-+-
 |O|X   3|4|5
-+-+-   -+-+-
 | |    6|7|8

win
win
random
win
win
win
win
win
win
win
win
win
win
win
win
other
O| |    0|1|2
-+-+-   -+-+-
 |O|X   3|4|5
-+-+-   -+-+-
 | |    6|7|8

Turn for X. Move on which space?:

其中许多是在ai()函数中的:

代码语言:javascript
运行
复制
    for i in range(len(possible_moves)):
        board_copy = the_board.copy()
        board_copy[possible_moves[i]] = players[1]['piece']
        if check_board(possible_moves[i], 1):
            the_board[possible_moves[i]] = players[1]['piece']
            print('win')
            return
        elif check_board(possible_moves[i], 0):
            print('lose')
            final_move = possible_moves[i]
        elif players[1]['level'] == 'smart' and final_move is None:
            if possible_moves[i] in [0, 2, 6, 8]:
                print('random')
                final_move = possible_moves[i]

我们会把他们移走。如果需要,可以导入logging模块并将其记录到logging.debug(...)调试流中。

U2。你不能就这么手动退出游戏。因此,让我们修改retry函数:

代码语言:javascript
运行
复制
def retry():
    valid = False
    while not valid:
        print('Do you want to play again with the same settings? Y or N (Q to exit)')
        choice = input()
        choice = choice.upper()
        if input_validation('string', ['Y', 'N', 'Q'], choice):
            if choice == 'Y':
                game()
            elif choice == 'Q':
                return
            else:
                player_options()
                game()

U3。这场比赛随机崩溃,对获胜位置没有反应。

看看您的is_win()代码:

代码语言:javascript
运行
复制
def is_win(bo, player):
    # 0 1 2
    # 3 4 5
    # 6 7 8

    for i in range(3):
        return (

return语句立即退出函数,其值为您要返回的值。因此,这段代码只适用于i == 0。如果您想检查所有内容并返回到任何地方的True,您应该像这样修改代码(并且,请使用一致的变量!如果您正在使用board,请在任何地方使用它作为板。不要在不同的地方使用boardbo和smth之类的b ):

代码语言:javascript
运行
复制
def is_win(board, player):
    # 0 1 2
    # 3 4 5
    # 6 7 8

    for i in range(3):
        if (
            (board[i * 3] == player and
             board[i * 3 + 1] == player and
             board[i * 3 + 2] == player)
            or
            (board[i] == player and
             board[i+3] == player and
             board[i+6] == player)
            or
            (i <= 1 and
             (board[i*2] == player and
              board[4] == player and
              board[8-(i*2)] == player))
        ):
            return True
    return False

现在我们直接讨论代码:

  1. 避免全局变量!在99.99%,你不需要他们,可以很容易地工作没有他们。全局变量可能(而且经常会)导致非常难以调试的错误。我们将通过创建TicTac类并将所有函数转换为类函数(非常多的代码,稍后会看到)来消除全局变量。
  2. 干(不要重复)。代码中的任何地方都有像players[1]['piece']players[1]['level']这样的变量。您可以创建新的短变量(特别是因为我们创建了一个类)并在任何地方使用它。如果您将更改您的player结构(例如,对于第三名玩家),您将不必更改代码中的所有内容。我们将用self.ai_levelself.ai_X替换它们
  3. ai()函数中,有一行:

self.the_board[possible_moves[random.randint(0, len(possible_moves))]] = self.ai_X

random.randint可以返回边界(例如,random.randint(0, 5)可以返回0或5),因此这一行有时会引发错误(当您试图获得random.randint的最后一个元素时)。您可以将右绑定定义为len(possible_moves) - 1,也可以只使用random.choice

self.the_board[random.choice(possible_moves)] = self.ai_X

  1. 一些小的改进,如:
代码语言:javascript
运行
复制
for i in range(9):
    self.the_board.insert(i, ' ')

self.the_board = [' '] * 9

而且很喜欢。

所以我们有了最后的密码。老实说,从头开始重写整个游戏会更好,但几年后你才会意识到:)这段代码仍然不太理想,还有很多地方需要改进,但它比以前更好了。

代码语言:javascript
运行
复制
import random

class TicTac(object):
    def __init__(self):
        self.the_board = [' '] * 9
        self.players = [
            {'type': 'player', 'piece': 'X'},
            {'type': 'player', 'level': 'smart', 'piece': 'O'}
        ]
        self.ai_level = None
        self.ai_X = None

    def print_board(self, board):
        for i in range(3):
            print(board[i * 3] + '|' + board[i * 3 + 1] + '|' + board[i * 3 + 2], end='')
            print('   ' + str(i * 3) + '|' + str(i * 3 + 1) + '|' + str(i * 3 + 2))
            if i < 2:
                print('-+-+-' + '   ' + '-+-+-')
        print()

    def is_win(self, board, player):
        # 0 1 2
        # 3 4 5
        # 6 7 8

        for i in range(3):
            if (
                (board[i * 3] == player and
                 board[i * 3 + 1] == player and
                 board[i * 3 + 2] == player)
                or
                (board[i] == player and
                 board[i+3] == player and
                 board[i+6] == player)
                or
                (i <= 1 and
                 (board[i*2] == player and
                  board[4] == player and
                  board[8-(i*2)] == player))
            ):
                return True
        return False

    def check_board(self, move, player):
        board_copy = self.the_board.copy()
        board_copy[move] = self.players[player]['piece']
        return self.is_win(board_copy, self.players[player]['piece'])

    def ai(self):
        possible_moves = []
        final_move = None

        for i in range(9):
            if self.the_board[i] == ' ':
                possible_moves.append(i)

        if self.the_board[4] == ' ' and self.ai_level == 'smart':
            self.the_board[4] = self.ai_X
            return

        for i in range(len(possible_moves)):
            board_copy = the_board.copy()
            board_copy[possible_moves[i]] = self.ai_X
            if self.check_board(possible_moves[i], 1):
                self.the_board[possible_moves[i]] = self.ai_X
                return
            elif self.check_board(possible_moves[i], 0):
                final_move = possible_moves[i]
            elif self.ai_level == 'smart' and final_move is None:
                if possible_moves[i] in [0, 2, 6, 8]:
                    final_move = possible_moves[i]
        else:
            if final_move is not None:
                self.the_board[final_move] = self.ai_X
                return
            self.the_board[random.choice(possible_moves)] = self.ai_X

    def input_validation(self, option_type, options, choice):
        if option_type == 'number_range':
            if not str.isdigit(choice):
                print('It has to be a number')
                return False
            else:
                choice = int(choice)
            if choice < options[0] or choice > options[1]:
                print('You have to choose a number between 0 and 8')
                return False
            elif (self.the_board[choice] == 'X' or self.the_board[choice] == 'O'):
                print('There is already a move there, please try again.')
                return False
            else:
                return True

        if option_type == 'string':
            for i in range(len(options)):
                if choice == options[i]:
                    return True
            else:
                print('That is not a valid option, your choices are:')
                for i in range(len(options)):
                    print(options[i])
                else:
                    print()
                return False

    def player_options(self):
        valid = False

        while not valid:
            print('Do you want to play the cpu or player?')
            choice = input()
            choice = choice.lower()
            if self.input_validation('string', ['cpu', 'player'], choice):
                self.players[1]['type'] = choice
                break

        while not valid and self.players[1]['type'] == 'cpu':
            self.ai_X = self.players[1]['piece']
            print('Do you want smart or dumb ai?:')
            choice = input()
            choice = choice.lower()
            if self.input_validation('string', ['smart', 'dumb'], choice):
                if choice == 'dumb':
                    self.players[1]['level'] = choice
                    self.ai_level = choice
                break

    def game(self):
        move = 0
        turn = random.choice([True, False])

        for i in range(9):
            valid = False

            self.print_board(self.the_board)
            if is_win(self.the_board, self.players[0]['piece']) or \
                    is_win(self.the_board, self.players[1]['piece']):
                self.print_board(self.the_board)
                print('Player ' + self.players[turn]['piece'] + ' is the winner!')
                return

            turn ^= True

            if turn == 0 or (self.players[1]['type'] == 'player' and turn == 1):
                while not valid:
                    move = (input('Turn for ' + self.players[turn]['piece'] + '. Move on which space?: '))
                    if self.input_validation('number_range', [0, 8], move):
                        move = int(move)
                        valid = True
                        self.the_board[move] = self.players[turn]['piece']
            elif self.players[1]['type'] == 'cpu' and turn == 1:
                self.ai()
        print('It is a tie!')

    def retry(self):
        valid = False
        while not valid:
            print('Do you want to play again with the same settings? Y or N (Q to exit)')
            choice = input()
            choice = choice.upper()
            if input_validation('string', ['Y', 'N', 'Q'], choice):
                if choice == 'Y':
                    self.game()
                elif choice == 'Q':
                    return
                else:
                    self.player_options()
                    self.game()

game = TicTac()
game.player_options()
game.game()
game.retry()
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

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

复制
相关文章

相似问题

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