zoukankan      html  css  js  c++  java
  • 大爽Python入门教程 69 实例演示三 控制台——井字棋游戏(TicTacToe)

    大爽Python入门公开课教案 点击查看教程总目录

    1 游戏介绍

    实现一个控制台版本的井字棋小游戏, 英文名叫Tic-Tac-Toe。
    代码量:100行左右。

    面板展示效果

       |   |   
    ---+---+---
       |   |   
    ---+---+---
       |   |   
    

    两种棋子,
    一种用"X"来表示,
    另一种用"O"表示。

    流程说明

    觉得流程描述罗嗦,可以直接看运行效果部分。

    1. 进入游戏,展示欢迎语,
    2. 展示井字棋面板,
      提醒当前玩家输入落子位置。
    3. 检查输入,是否符合位置格式,且对应位置是否为空,
      不满足则展示原因,并再次读取输入。
      满足则落子成功。
    4. 落子成功后,检查是否胜利(有三个字连成一条线),
      未胜利则切换到另一个玩家,
      然后重复上述步骤123
    5. 落子成功后,如果胜利,则直接展示面板,恭喜当前玩家,然后结束游戏。

    运行效果

    运行示例中的输入为

    1, 1
    1,0
    0, 0
    1,1
    123
    2,2
    0,2
    0,1
    2,0
    

    运行的效果为

    Welcome to Tic-Tac-Toe!
       |   |   
    ---+---+---
       |   |   
    ---+---+---
       |   |   
    X's turn. Enter row index and column index to place (ri, ci):
    1, 1
       |   |   
    ---+---+---
       | X |   
    ---+---+---
       |   |   
    O's turn. Enter row index and column index to place (ri, ci):
    1,0
       |   |   
    ---+---+---
     O | X |   
    ---+---+---
       |   |   
    X's turn. Enter row index and column index to place (ri, ci):
    0, 0
     X |   |   
    ---+---+---
     O | X |   
    ---+---+---
       |   |   
    O's turn. Enter row index and column index to place (ri, ci):
    1,1
    The place is already occupied.
     X |   |   
    ---+---+---
     O | X |   
    ---+---+---
       |   |   
    O's turn. Enter row index and column index to place (ri, ci):
    123
    Invalid command.
     X |   |   
    ---+---+---
     O | X |   
    ---+---+---
       |   |   
    O's turn. Enter row index and column index to place (ri, ci):
    2,2
     X |   |   
    ---+---+---
     O | X |   
    ---+---+---
       |   | O
    X's turn. Enter row index and column index to place (ri, ci):
    0,2
     X |   | X
    ---+---+---
     O | X |   
    ---+---+---
       |   | O
    O's turn. Enter row index and column index to place (ri, ci):
    0,1
     X | O | X
    ---+---+---
     O | X |   
    ---+---+---
       |   | O
    X's turn. Enter row index and column index to place (ri, ci):
    2,0
     X | O | X
    ---+---+---
     O | X |   
    ---+---+---
     X |   | O
    X win!
    

    2 初步分析

    大概步骤,在流程说明中,其实就分析的差不多了。
    所以可以直接思考如何设计函数。

    同时本章第四节部分已经实现了井字棋的胜利的检测。
    这里可以直接拿来用(简单修改下更好)。

    函数初步设计

    需要微调的函数

    • check_bunch_match(bunch, symbol): 检查一串棋子bunch是否全都都是symbol对应的棋
    • get_ttt_winner(board):: 得出谁是赢家

    对应的,需要以下几个函数

    • generate_board: 生成井字格棋盘(3x3二维列表)
    • show_board: 展示井字格棋盘(以可读性高的形式)
    • parse_rc: 从用户输入中解析出行列位置坐标。
    • main: 主函数或者说主逻辑

    分析与调整

    • check_bunch_match(bunch, symbol) 不用调整

    微调

    • get_ttt_winner(board) 调整成check_win(board, symbol), 检查symbol对应的棋子是否胜利。
      因为每次落子后只需要检查当前棋子是否能够练成一条线。

    其他新的函数需要哪些参数

    • generate_board(): 无需参数
    • show_board(board): board为井字格棋盘(3x3二维列表)
    • parse_rc(cmd): cmd为用户输入的落子坐标(字符串)。
    • main(): 无需参数

    3 逐步实现

    字符串定义

    先在代码开头定义要用的的字符串。

    WELCOME = "Welcome to Tic-Tac-Toe!"
    ENTER  = "%s's turn. Enter row index and column index to place (ri, ci):\n"
    Invalid = "Invalid command."
    Used = "The place is already occupied."
    

    函数声明

    把要用到的函数先声明

    def generate_board():
        return
    
    def show_board(board):
        pass
    
    def parse_rc(cmd):
        return -1, -1
    
    def check_bunch_match(bunch, symbol):
        return False
    
    def check_win(board, symbol):
        return False
    
    def main():
        pass
    

    这里先实现generate_board,然后再去实先main

    generate_board

    代码如下

    def generate_board():
        board = [
            [" " for ci in range(3)] for ri in range(3)
        ]
    
        return board
    

    main

    代码如下

    def main():
        board = generate_board()
        print(WELCOME)
    
        turn = "X"
        while True:
            show_board(board)
    
            cmd = input(ENTER % turn)
            ri, ci = parse_rc(cmd)  # 解析出命令中的行列位置
    
            if ri >= 0:  # 检查输入是否有效
                if board[ri][ci] == " ":  # 检查是否是空格子
                    board[ri][ci] = turn  # 直接放入棋子
    
                    # 检查是否胜利,胜利则展示面板与结果并退出
                    if check_win(board, turn):
                        show_board(board)
                        print("%s win!" % turn)
                        return
    
                    # 切换玩家
                    if turn == "X":
                        turn = "O"
                    else:
                        turn = "X"
                else:
                    print(Used)
            else:
                print(Invalid)
    

    show_board

    代码如下

    def show_board(board):
        for ri, row in enumerate(board):
    
            row_str = ""
            for ci, cell in enumerate(row):
                row_str += " %s " % cell
                if ci != 2:
                    row_str += "|"
            print(row_str)
    
            if ri != 2:
                print("---+---+---")
    

    parse_rc

    代码如下

    def parse_rc(cmd):
        rc = cmd.split(",")
        if len(rc) == 2:
            ri, ci = rc
            ri = ri.strip()
            ci = ci.strip()
            if ci.isdigit() and ri.isdigit():
                ci = int(ci)
                ri = int(ri)
                if 0 <= ci < 3 and 0 <= ri < 3:
                    return ri, ci
    
        return -1, -1
    

    check_bunch_match

    check_bunch_match直接复制过来就行
    代码如下

    def check_bunch_match(bunch, symbol):
        res = True
        for one in bunch:
            if one != symbol:
                res = False
                break
    
        return res
    

    check_win

    微调后代码如下

    def check_win(board, symbol):
        r, c = len(board), len(board[0])
        for ri in range(r):
            row = board[ri]
            if check_bunch_match(row, symbol):
                return True
    
        for ci in range(c):
            column = [board[ri][ci] for ri in range(r)]
            if check_bunch_match(column, symbol):
                return True
    
        diagonal_1 = [board[ri][ri] for ri in range(r)]
        diagonal_2 = [board[ri][c-ri-1] for ri in range(r)]
        if check_bunch_match(diagonal_1, symbol):
            return True
        if check_bunch_match(diagonal_2, symbol):
            return True
    
        return False
    

    调用代码

    main()
    

    4 最终代码

    最终代码如下(运行效果第一部分已展示,不再额外展示)。

    WELCOME = "Welcome to Tic-Tac-Toe!"
    ENTER  = "%s's turn. Enter row index and column index to place (ri, ci):\n"
    Invalid = "Invalid command."
    Used = "The place is already occupied."
    
    
    def generate_board():
        board = [
            [" " for ci in range(3)] for ri in range(3)
        ]
    
        return board
    
    
    def show_board(board):
        for ri, row in enumerate(board):
    
            row_str = ""
            for ci, cell in enumerate(row):
                row_str += " %s " % cell
                if ci != 2:
                    row_str += "|"
            print(row_str)
    
            if ri != 2:
                print("---+---+---")
    
    
    def parse_rc(cmd):
        rc = cmd.split(",")
        if len(rc) == 2:
            ri, ci = rc
            ri = ri.strip()
            ci = ci.strip()
            if ci.isdigit() and ri.isdigit():
                ci = int(ci)
                ri = int(ri)
                if 0 <= ci < 3 and 0 <= ri < 3:
                    return ri, ci
    
        return -1, -1
    
    
    def check_bunch_match(bunch, symbol):
        res = True
        for one in bunch:
            if one != symbol:
                res = False
                break
    
        return res
    
    
    def check_win(board, symbol):
        r, c = len(board), len(board[0])
        for ri in range(r):
            row = board[ri]
            if check_bunch_match(row, symbol):
                return True
    
        for ci in range(c):
            column = [board[ri][ci] for ri in range(r)]
            if check_bunch_match(column, symbol):
                return True
    
        diagonal_1 = [board[ri][ri] for ri in range(r)]
        diagonal_2 = [board[ri][c-ri-1] for ri in range(r)]
        if check_bunch_match(diagonal_1, symbol):
            return True
        if check_bunch_match(diagonal_2, symbol):
            return True
    
        return False
    
    
    def main():
        board = generate_board()
        print(WELCOME)
    
        turn = "X"
        while True:
            show_board(board)
            cmd = input(ENTER % turn)
            ri, ci = parse_rc(cmd)
            if ri >= 0:
                if board[ri][ci] == " ":
                    board[ri][ci] = turn
    
                    if check_win(board, turn):
                        show_board(board)
                        print("%s win!" % turn)
                        return
    
                    if turn == "X":
                        turn = "O"
                    else:
                        turn = "X"
                else:
                    print(Used)
            else:
                print(Invalid)
    
    
    main()
    
  • 相关阅读:
    URL中#号(井号)的作用
    Sublime Text2 快捷键汇总
    Sublime Text2 使用及插件配置
    Sumblime Text 2 常用插件以及安装方法
    CSS禁止选择文本功能(兼容IE,火狐等浏览器)
    JavaScript 判断 URL
    纯真IP数据库格式读取方法(JAVA/PHP/Python)
    Sublime Text 2 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux
    base64:URL背景图片与web页面性能优化
    数独DFS实现
  • 原文地址:https://www.cnblogs.com/BigShuang/p/15647498.html
Copyright © 2011-2022 走看看