Tic-Tac-Toe人机对弈程序(python实现)

news2024/9/23 19:24:47

目录

1. 前言

2. 处理流程

3. 代码

4. 代码说明

4.1 棋盘显示

4.2 初始化

4.3 人类棋手的下一步

4.4 AI棋手的下一步

4.5 终局及胜负判断

5. 棋局示例


1. 前言

        前面几篇博客(以循序渐进的方式)实现了Tic-Tac-Toe游戏的棋局搜索、遍历以及所有可能棋局数和盘面状态数的计算,参见:

        Tic-Tac-Toe可能棋局搜索的实现(python)

        Tic-Tac-Toe可能棋局遍历的实现(python)

        Tic-Tac-Toe有多少种不同棋局和盘面状态(python实现)

        本文先实现一个简单的Tic-Tac-Toe人机对弈程序,为下一步实现基于minimax算法的Tic-Tac-Toe人机对弈程序做一个准备。

2. 处理流程

3. 代码

# Tic Tac Toe
# Created by chenxy in 2017-06-23, with only drawBoard() copied from <<inventwithpython>>
# 2023-01-04 refined
import random
import sys

def drawBoard(board, initFlag = 0):
    # This function prints out the board that it was passed.

    brd_copy = board.copy()
    if initFlag:
        brd_copy = ['0','1','2','3','4','5','6','7','8','9']

    # "board" is a list of 10 strings representing the board (ignore index 0)
    print('=============')
    # print('   |   |')
    print(' ' + brd_copy[7] + ' | ' + brd_copy[8] + ' | ' + brd_copy[9])
    # print('   |   |')
    print('-----------')
    # print('   |   |')
    print(' ' + brd_copy[4] + ' | ' + brd_copy[5] + ' | ' + brd_copy[6])
    # print('   |   |')
    print('-----------')
    # print('   |   |')
    print(' ' + brd_copy[1] + ' | ' + brd_copy[2] + ' | ' + brd_copy[3])
    # print('   |   |')
    print('=============')
    print()

def askGameStart():
    # Ask human start a game or not;
    print('Do you want to start a game? Y or y to start; Others to exit');
    inputWord = input().lower();
    if inputWord.startswith('y'):
        startNewGame = True;
    else:
        startNewGame = False;
    return(startNewGame);    

# Decide whether the number human input for the next move has been already used or not.
# It can be decided by whether the corrsponding element is empty or not.
def isValidInput(board, humanNextMove):
    isValid = 1;
    if humanNextMove == 0:
        print('Please input 1~9, 0 is not an valid input for the next move!');
        isValid = 0;
    elif board[humanNextMove] != ' ':
        print('The space has already been used! Please select an empty space for the next move');
        isValid = 0;    
    return(isValid);    

# Ask the human player for the next move.
def askNextMove(board):
    while True:
        print('Please input the next move!');
        c = input()
        if not c.isdigit():
            print('Invalid input! Please input [1-9]!');
            continue
        nextMove = int(c);
        if board[nextMove] == ' ':
            break;
        else:
            continue;
    isValid = isValidInput(board, nextMove)
    return isValid,nextMove
        
def gameRsltDisplay(winner):    
    if   'A' == winner:
        print('AI win!');
    elif 'H' == winner:
        print('Human win!');
    else:    
        print('A tie game!');        

# Decide AI's next move.
# Decide whether the three input are all the same
def isTripleGoalReachedNext(board,idx1, idx2, idx3, role):
    in1 = board[idx1];
    in2 = board[idx2];
    in3 = board[idx3];
    
    if   in1 == ' ' and in2 == in3 and in2 == role:
        return idx1;
    elif in2 == ' ' and in1 == in3 and in3 == role:
        return idx2;
    elif in3 == ' ' and in1 == in2 and in1 == role:
        return idx3;
    else:
        return 0;   # Invalid space index.

def isGoalReachedNext(board, role):

    nextMove        = 0;
        
    nextMove  = isTripleGoalReachedNext(board, 1, 4, 7, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 1, 2, 3, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 1, 5, 9, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 2, 5, 8, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 3, 5, 7, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 3, 6, 9, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 4, 5, 6, role);
    if nextMove > 0:
        return True, nextMove
    nextMove  = isTripleGoalReachedNext(board, 7, 8, 9, role);
    if nextMove > 0:
        return True, nextMove

    return False, nextMove;
    
def aiNextMove(board, gameRole):

    # Temporarily, select the first empty space.
    # 1. First, check whether AI will reach the goal in the next step.
    #    gameRole[0] represents AI's role.
    goalReachedNext, nextMove = isGoalReachedNext(board, gameRole[0]);
    
    if goalReachedNext == True:
        return nextMove;

    # 2. Secondly, check whether Human will reach the goal in the next step.
    #    gameRole[1] represents Human's role.
    #    Of course, AI should take the next move to blocking Human player to reach the goal.
    goalReachedNext, nextMove = isGoalReachedNext(board, gameRole[1]);
    
    if goalReachedNext == True:
        return nextMove;
    
    # Randomly selected from the left spaces for the next move.
    spaces = []
    for k in range(1,9):    
        if board[k] == ' ':
            spaces.append(k)
        else:
            continue;
    nextMove = random.choice(spaces)
    
    return(nextMove);

# Decide whether the three input are all the same
def isTripleSame(in1, in2, in3):
    if in1 == ' ' or in2 == ' ' or in3 == ' ':
        return False
    elif in1 == in2 and in1 == in3:
        return True
    else:
        return False

def gameJudge(board):
    if   isTripleSame(board[1],board[4],board[7]):
        gameOver = True;        winner   = board[1];
    elif isTripleSame(board[1],board[2],board[3]):    
        gameOver = True;        winner   = board[1];
    elif isTripleSame(board[1],board[5],board[9]):        
        gameOver = True;        winner   = board[1];
    elif isTripleSame(board[2],board[5],board[8]):        
        gameOver = True;        winner   = board[2];
    elif isTripleSame(board[3],board[5],board[7]):        
        gameOver = True;        winner   = board[3];
    elif isTripleSame(board[3],board[6],board[9]):        
        gameOver = True;        winner   = board[3];
    elif isTripleSame(board[4],board[5],board[6]):        
        gameOver = True;        winner   = board[4];
    elif isTripleSame(board[7],board[8],board[9]):        
        gameOver = True;        winner   = board[7];
    elif ' ' in board[1:9]:     
        gameOver = False;       winner   = ' ';
    else:
        gameOver = True;        winner   = ' ';
            
    return gameOver, winner
    
whoseTurn = 0;         #  0 : AI's turn;   1:  Human's turn.
gameRole  = ['A','H']; # [0]: AI's role;  [1]: Human's role;
board     = [' ']*10;  #  Note: '*' for string means concatenation.

drawBoard(board,1); # Draw the initial board with numbering

if not askGameStart():
    print('Bye-Bye! See you next time!');
    sys.exit();

while True:
    # Initialization.
    gameOver = 0;
    board    = [' ',' ',' ',' ',' ',' ',' ',' ',' ',' '];
    # Decide who, either human or AI, play first.
    # 0: AI; 1: human.
    role = random.randint(0,1);
    if role == 0:
        whoseTurn   = 0;
    elif role == 1:
        whoseTurn   = 1;

    while(not gameOver):    
        if whoseTurn == 0:
            print('AI\'s turn')
            nextMove = aiNextMove(board,gameRole);
            board[nextMove] = gameRole[0];
            whoseTurn = 1;
        else:
            print('Human\'s turn')
            isValid  = 0;
            while(not isValid):
                isValid, nextMove = askNextMove(board);
            board[nextMove] = gameRole[1];
            whoseTurn = 0;

        drawBoard(board);               
        gameOver,winner = gameJudge(board);     
    
    gameRsltDisplay(winner);

    #startNewGame = askGameStart();
    if not askGameStart():
        print('Bye-Bye! See you next time!');
        sys.exit();
                            

4. 代码说明

4.1 棋盘显示

        为了方便操作,棋盘的格点位置与(人类棋手下棋时输入的)数字的对应关系设计成和计算机键盘右边的小键盘相同,如下图所示。这样的话,比如说棋手输入7的话就表示在棋盘左上角落子,输入3的话表示在棋盘右下角落子,余者类推。

        代码中用一个包含10个元素的(字符:“H”,“A”)数组表示棋盘board,其中board[0]不使用。人类棋手用字母“H”(Human)表示;AI棋手用字母“A”(Artificial Intelligence)表示。比如说,人类棋手输入7的话,表示在左上角落子,则将board[7]赋值为“H”;AI棋手输入1的话,表示在左下角落子,则将board[1]赋值为“A”。。。

        详细参见drawBoard(board, initFlag = 0)函数的实现。

4.2 初始化

        初始棋盘显示。游戏开始时的初始棋盘显示中,显示的是上图所示棋盘各个位置对应的数字,方便玩家参考。在游戏过程中,各棋盘格子中显示的是“H”或者“A”或者空格(还没有落子的格子)。

        猜先。调用askGameStart()开始游戏并进行猜先。

4.3 人类棋手的下一步

askNextMove ():询问人类棋手的下一步。应该输入1~9中的一个数字

isValidInput():用于判断棋手输入的合法性。如果输入0或者非数字的话,程序会要求棋手再次输入。

4.4 AI棋手的下一步

        本程序中目前只实现了一个傻傻的AI,只比完全随机落子聪明一点点。

        AI决定落子时,首先检查是否有能够终结棋局的下一手,如果有的话就选择那一手(如果有多个下一手可以终结棋局的话则选择找到的第一手);如果没有能够终结棋局的下一手时就从余下的空格中随机选择一手。很显然,将来优化这个AI时就应该从此处着手。

        aiNextMove(board, gameRole):AI agent。决定AI的下一手。

        isGoalReachedNext(board, role):AI决定下一手时首先遍历空的棋格看是否存在能够终结棋局的下一手。

        isTripleGoalReachedNext(board,idx1, idx2, idx3, role):用于确定指定的三个棋格(在再下一手的条件下)是否满足终结棋局的条件。

4.5 终局及胜负判断

        gameJudge():

        终局及胜负判断。如果已经出现排成一条直线的三个棋格相同的终结棋局的局面,则判定棋局结束且判定胜者为谁;如果棋盘已满但是没有出现“排成一条直线的三个棋格相同”的情况,则判定平局;否则,棋局仍将继续。

        isTripleSame():

        用于确定指定的三个棋格是否满足终结棋局的条件。注意它与isTripleGoalReachedNext()的区别。

5. 棋局示例

        以下为一局棋的运行过程示例。

(base) E:\TicTacToe>python tictactoe.py
=============
 7 | 8 | 9
-----------
 4 | 5 | 6
-----------
 1 | 2 | 3
=============

Do you want to start a game? Y or y to start; Others to exit
y
Human's turn
Please input the next move!
7
=============
 H |   |
-----------
    |   |
-----------
    |   |
=============

AI's turn
=============
 H |   |
-----------
    |   |
-----------
 A |   |
=============

Human's turn
Please input the next move!
3
=============
 H |   |
-----------
    |   |
-----------
 A |   | H
=============

AI's turn
=============
 H |   |
-----------
    | A |
-----------
 A |   | H
=============

Human's turn
Please input the next move!
9
=============
 H |   | H
-----------
    | A |
-----------
 A |   | H
=============

AI's turn
=============
 H |   | H
-----------
    | A | A
-----------
 A |   | H
=============

Human's turn
Please input the next move!
8
=============
 H | H | H
-----------
    | A | A
-----------
 A |   | H
=============

Human win!
Do you want to start a game? Y or y to start; Others to exit

Next Step:

        实现基于完全minimax的unbearable TicTacToe AI

        实现TicTacToe GUI 

        。。。

        后记(2023-01-05):调研学习alphaGo论文中,想先写一个Tic-Tac-Toe的游戏程序,以此为基础学习minimax,alphabeta,MCTS等算法概念。然后翻了翻计算机中的文件发现自己居然在2017年就写过一个,完全没有印象了^-^。整理了一下先发出来以免自己再次忘记。

参考文献:

AL SWEIGART, Invent Your Own Computer Games with Python(4th)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141011.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

植物大战僵尸:寻找阳光掉落Call调用

通过遍历阳光产生的时间,寻找阳光产生的本地Call,使用代码注入器注入,自定义生成阳光 阳光CALL遍历技巧&#xff1a; 进入植物大战僵尸-> 当出现阳光后->马上搜索未知初始数值返回游戏-> 马上切回CE-> 搜索减少的数值-> 掉一点搜一点最后排查出它的掉落地址-&…

Eureka Server 开启Spring Security Basic认证

概 述 Eureka Server 在实际使用过程中必须考虑安全问题&#xff0c;比如 未认证的用户 不允许其随意调用 Eureka Server的 API&#xff1b;还有一个则是 未认证的 Eureka Client 也禁止其注册到 Eureka Server中来&#xff0c;这些都是可以在工程中进行配置的&#xff0c;当然…

蓝桥杯寒假集训第七天(修改数组)

没有白走的路&#xff0c;每一步都算数&#x1f388;&#x1f388;&#x1f388; 题目描述&#xff1a; 给定一个已知长度的数组&#xff0c;要求出由其变换而来的一组没有重复数据的数组。假定有一个数组A[0,1,2,3,4]。要求如果A[i]在之前的数组A[0,1,2,3..i-1]之中若出现过&…

关于win11 21H2 升22H2及安装安卓子系统的记载

前言 电脑是i7 7700的&#xff0c;没有TPM2.0。但是喜欢折腾&#xff0c;喜欢win11任务栏的居中&#xff0c;之前win10的时候&#xff0c;会用插件折腾。既然有原生的了&#xff0c;自然更好了。 win11系统升级 关于win11系统下载 直接百度搜索win11系统下载&#xff0c;然…

【数据结构】(牛客)链表的回文结构,LeetCode相交链表,LeetCode环形链表

目录 一、链表的回文结构 1、题目说明 2、题目解析 二、相交链表 1、题目说明 2、题目解析 三、环形链表 1、题目说明 2、题目解析 一、链表的回文结构 1、题目说明 题目链接&#xff1a;链表的回文结构 对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度…

RHCE-ssh服务设置

目录 要求&#xff1a; 1.两台机器&#xff1a;第一台机器作为客户端&#xff0c;第二台机器作为服务器&#xff0c;在第一台使用rhce用户免密登录第二台机器 2.禁止root用户远程登录和设置三个用户sshuser1, sshuser2, sshuser3 3&#xff0c; 只允许sshuser3登录&#xff…

Java开发入门到精通之Java的数据库访问

一、前言 在应用程序开发中&#xff0c;需要使用数据库管理和存储各种数据。在Java中&#xff0c;提供了一个JDBC技术(Java Database Connectivity&#xff0c;JDBC&#xff0c;Java数据库连接)&#xff0c;它的作用是连接数据库并访问。接下来小编带大家一起来学习JDBC技术! …

天猫汽车商详页的SSR改造实践

由于汽车业务的特殊性&#xff0c;天猫汽车基于 Rax 多页应用自建了商品详情的 H5 页面。自定义商详承载了众多业务能力和投放场景。随着业务的发展和页面承载内容的增多&#xff0c;开始出现白屏时间太长等体验问题。前端性能优化算是个老生常谈的问题&#xff0c;我们的页面已…

DBeaver安装教程

软件安装包官网地址https://dbeaver.io/但一般由于网络问题&#xff0c;我们是很慢才连接上&#xff0c;或者连接不上这里提供压缩包链接&#xff0c;解压可直接用&#xff0c;亲测链接&#xff1a;https://pan.baidu.com/s/14KGY0JakRTOHQVkiRUWc7g?pwdcxda 提取码&#xff1…

2022年第十二届APMCM亚太杯1月增赛E题思路分享

2022年亚洲及太平洋地区建模数学竞赛问题E 有多少颗核弹可以摧毁地球? 题目回顾&#xff1a; 1.基本数据分析 a) 哪些国家曾经拥有过核武器? b) 在过去的20年中&#xff0c;哪个国家的核武器库存减少或增加得最多? c) 在哪五年早&#xff0c;核武器试验发生的次数最多…

【笔记:模拟CMOS集成电路】噪声——分析基础(1)

【笔记&#xff1a;模拟CMOS集成电路】噪声——分析基础&#xff08;1&#xff09;前言1噪声的定义2噪声的描述2.1统计特性&#xff08;1&#xff09;平均功率&#xff08;2&#xff09;功率谱密度&#xff08;PSD&#xff09;2.2噪声相关指标&#xff08;1&#xff09;SNR&…

【C++】vector用法简单模拟实现

文章目录1.vector的介绍及使用1.1 vector基本概念1.2 vector的使用1.2.1 vector的定义 (构造函数)1.2.2 vector的迭代器使用1.2.3 vector 增删查改1.2.4 vector 迭代器失效问题&#xff08;重点&#xff09;1.2.5 vector 空间增长问题2. vector的模拟实现2.1 SGI版vector实现示…

Logback的使用

文章目录概述使用配置文件详解<appender>ConsoleAppenderFileAppenderRollingFileAppender滚动策略<root><encoder>日志级别概述 Logback是一个实现了Slf4j 规范的实现框架&#xff0c;log4j的作者实现了Logback。 下面这是Logback官网的介绍&#xff1a; …

排序算法之插入排序

目录 排序算法介绍 插入排序 算法流程 算法实现 python C 插入排序与冒泡排序 排序算法介绍 《Hello算法》是GitHub上一个开源书籍&#xff0c;对新手友好&#xff0c;有大量的动态图&#xff0c;很适合算法初学者自主学习入门。而我则是正式学习算法&#xff0c;以这本…

云原生丨DBSwitch数据迁移实践

文章目录一、前言一、部署1. 环境准备2. 安装包部署二、使用1.登录2. 使用步骤-gauss迁移到gauss3. 使用步骤-MySQL迁移到gauss三、postgres和 gauss差异说明一、前言 DBSwitch是一个异构数据库迁移工具&#xff0c;能够提供源端数据库向目的端数据库的批量迁移同步功能&#…

Spring的体系结构介绍

Spring框架采用的是分层架构&#xff0c;它一系列的功能要素被分成20个模块&#xff0c;这些模块大体分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation、Messaging和Test。 上图中&#xff0c;包含了Spring框架的所有模…

windows 安装docker使用教程

一、win10上安装docker注册docker账号配置虚拟化启用 bios 虚拟化&#xff0c;是否已启用可以通过任务管理器查看如果没有启动请看&#xff0c;否则可以直接跳到2开启 Hyper-V进行后续操作&#xff1a;irtualization Technology(VT)&#xff0c;中文译为虚拟化技术&#xff0c;…

LabVIEW拓扑

LabVIEW拓扑交换机拓扑是交换机模块上通道和继电器的组织表示形式。拓扑通常显示模块上继电器的默认连接&#xff0c;并标记通道名称。某些交换机模块可以使用多个拓扑或拓扑的变体。某些接线端子或附件可能会强制交换机模块使用给定的拓扑或拓扑集。NI-开关 支持 以下 拓扑&am…

009-Ensp-实验-VLAN间互联

实验要求 实现两台不同vlan的设备可以互联 实验结构 实验步骤 1. PC1 /PC2 配置ip /gateway 2. LSW4 新增两个VLAN e0/0/2 - e0/0/3 设置为access类型 加入到不同的vlan e0/0/1 设置为trunk类型 允许所有tag经过 3. LSW3 新增两个VLAN g0/0/1 设置为trunk 允许所有tag经过…

Http Https TCP/IP理解

一、 TCP Http Https UDP IP 介绍TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff0c;传输控制协议/网际协议&#xff09;是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议&#xff0c;而是指一个由FTP、SM…