C++ 讲解井字棋

C++ 讲解井字棋

井字棋是一种直观的双人游戏,只要两个玩家都采用最佳策略,游戏总会以平局结束。这个游戏也被称为”圈圈叉叉”或”零和叉”。

可以使用计算机或其他设备来玩井字棋游戏,通常是在纸上画出游戏棋盘。这个经典游戏也为其他游戏(如连四)奠定了基础。

井字棋的历史

公元前一世纪左右,在罗马帝国就有一种原始版本的井字棋游戏。 “terni lapilli” 这个名字意味着每次出三个小石头。在游戏中,罗马废墟上留下了用粉笔画的网格图案。古埃及的废墟也发现了该游戏的证据。

这个游戏在英国被称为 “noughts and crosses”,首次在1864年印刷物中出现。术语 “tick-tack-toe” 首次在1884年的文学作品中出现,尽管它指的是在一个小黑板上玩的儿童游戏。

游戏规则

  • 游戏必须由两名玩家(在这个程序中分别是人类和电脑)进行。
  • 两名玩家都使用字母 “O” 和 “X” 标记自己的格子。
  • 游戏结束当一名玩家用自己的字符(’O’ 或 ‘X’)填满整行、整列或对角线时。
  • 如果没有人获胜,比赛被视为平局。

程序分解

# define COMPUTER 1
# define HUMAN 2
# define SIDE 3 
# define COMPUTERMOVE 'O'
# define HUMANMOVE 'X'

在这里,我们预先定义了游戏中要执行的一些移动。我们将棋盘的长度设定为3,计算机移动将用’O’表示,人类或用户用’X’表示。

void showBoard ( char board [ ] [ SIDE ] )
{
    printf ( " \ n \ n " ) ;
    printf ( " \ t \ t \ t % c | % c | % c \ n " , board [ 0 ] [ 0 ] , board [ 0 ] [ 1 ] , board [ 0 ] [ 2 ] ) ;
    printf ( " \ t \ t \ t -------------- \ n " ) ;
    printf ( " \ t \ t \ t % c | % c | % c \ n " , board [ 1 ] [ 0 ] , board [ 1 ] [ 1 ] , board [ 1 ] [ 2 ] ) ;
    printf ( " \ t \ t \ t -------------- \ n " ) ;
    printf ( " \ t \ t \ t % c | % c | % c \ n \ n " , board [ 2 ] [ 0 ] , board [ 2 ] [ 1 ] , board [ 2 ] [ 2 ] ) ; 
    return ;
}

上述的函数即 void showBoard 将展示我们的一个大小为 3X3 的棋盘的当前状态,并且我们已经初始化它为数字 1 到 9 来表示。

void showInstructions ( )
{
    printf ( " \ t \ t \ t Tic-Tac-Toe \ n \ n " ) ;
    printf ( " Choose a cell numbered from 1 to 9 as below and play \ n \ n " ) ;
    printf ( " \ t \ t \ t 1 | 2 | 3 \ n " ) ;
    printf ( " \ t \ t \ t -------------- \ n " ) ;
    printf ( " \ t \ t \ t 4 | 5 | 6 \ n " ) ;
    printf ( " \ t \ t \ t -------------- \ n " ) ;
    printf ( " \ t \ t \ t 7 | 8 | 9 \ n \ n " ) ; 
    printf ( " - \ t - \ t - \ t - \ t - \ t- \ t - \ t - \ t - \ t - \ n \ n " ) ;
    return ;
}

上述功能即void showInstruction将展示如下的指令,并进行游戏:选择一个从1到9编号的单元格。

void initialize ( char board [ ] [ SIDE ] , int moves [ ] )
{
    // Initiate the random number generator so that
    // the same configuration doesn't arises
    srand ( time ( NULL ) ) ;
    // Initially the board is empty
    for ( int i = 0 ; i < SIDE ; i + + )
    {
        for (int j = 0 ; j < SIDE ; j + + )
            board [ i ] [ j ] =  ' ' ;
    }
    // Fill the moves with numbers
    for ( int i = 0 ; i < SIDE * SIDE ;  i +  + )
        moves [ i ] = I ; 
    // randomise the moves
    random_shuffle ( moves , moves + SIDE * SIDE ) ; 
    return ;
}

上述的函数即void initialize是用于初始化随机数,以避免出现相同的配置,同时初始棋盘为空。

void declareWinner ( int whoseTurn )
{
    if ( whoseTurn == COMPUTER )
        printf ( " COMPUTER has won \ n " ) ;
    else
        printf ( " HUMAN has won \ n " ) ;
    return ;
}

这个函数,即void declareWinner,将宣布游戏的赢家,无论是电脑赢还是人类赢得游戏。

bool rowCrossed ( char board [ ] [ SIDE ] )
{
    for ( int i=0 ; i < SIDE ; i + + )
    {
        if (board [ i ] [ 0 ] == board [ i ] [ 1 ] &&
            board [ i ] [ 1 ] == board [ i ] [ 2 ] &&
            board [ i ] [ 0 ] != ' ' )
            return ( true ) ;
    }
    return ( false ) ;
}

上面的函数即bool rowCrossed,如果任何一行与玩家的移动交叉,将返回true或false。

bool columnCrossed ( char board [ ] [ SIDE ] )
{
    for (int i = 0 ; i < SIDE ; i + + )
    {
        if (board [ 0 ] [ i ] == board [ 1 ] [ i ] &&
            board [ 1 ] [ i ] == board [ 2 ] [ i ] &&
            board [ 0 ] [ i ] != ' ' )
            return ( true ) ;
    }
    return ( false ) ;
}

以上函数即bool columnCrossed,如果任何一列与玩家的移动交叉,将返回true或false。

bool diagonalCrossed(char board[][SIDE])
{
    if (board[0][0] == board[1][1] &&
        board[1][1] == board[2][2] &&
        board[0][0] != ' ')
        return(true); 
    if (board[0][2] == board[1][1] &&
        board[1][1] == board[2][0] &&
        board[0][2] != ' ')
        return(true); 
    return(false);
}

上述函数即bool diagonalCrossed将根据玩家的移动是否与任何对角线相交来返回true或false。

bool gameOver ( char board [ ] [ SIDE ] )
{
    return ( rowCrossed ( board ) || columnCrossed ( board ) || diagonalCrossed ( board ) ) ;
}

上述函数即bool gameOver会在游戏结束时返回true或false。

void playTicTacToe ( int whoseTurn )
{
    // A 3 * 3 Tic-Tac-Toe board for playing
    char board [ SIDE ] [ SIDE ] ;
    int moves [ SIDE * SIDE ] ;
    // Initialise the game
    initialise ( board , moves ) ;
    // Show the instructions before playing
    showInstructions ( ) ;
    int moveIndex = 0 , x , y ;
    // Keep playing till the game is over or it is a draw
    while ( gameOver ( board ) == false &&
            moveIndex != SIDE * SIDE )
    {
        if ( whoseTurn == COMPUTER )
        {
            x = moves [ moveIndex ] / SIDE ;
            y = moves [ moveIndex ] % SIDE ;
            board [ x ] [ y ] = COMPUTERMOVE ;
            printf ( " COMPUTER has put a % c in cell % d \ n " , COMPUTERMOVE , moves [ moveIndex ] + 1 ) ;
            showBoard ( board ) ;
            moveIndex + + ;
            whoseTurn = HUMAN ;
        }
        else if ( whoseTurn == HUMAN )
        {
            x = moves [ moveIndex ] / SIDE ;
            y = moves [ moveIndex ] % SIDE ;
            board [ x ] [ y ] = HUMANMOVE ;
            printf ( " HUMAN has put a % c in cell % d \ n " , HUMANMOVE , moves [ moveIndex] + 1 ) ;
            showBoard ( board ) ;
            moveIndex + + ;
            whoseTurn = COMPUTER ;
        }
    }
    // If the game has drawn
    if ( gameOver ( board ) == false && moveIndex == SIDE * SIDE )
        printf ( " It's a draw \ n " ) ;
    else
    {
        // Toggling the user to declare the actual
        // winner
        if ( whoseTurn == COMPUTER )
            whoseTurn = HUMAN ;
        else if ( whoseTurn == HUMAN )
            whoseTurn = COMPUTER ; 
        // Declare the winner
        declareWinner ( whoseTurn ) ;
    }

上述函数即void playTictacToe将是玩井字游戏的主要函数。

C++中的井字游戏程序

// A C++ Program to play tic-tac-toe
#include 
using namespace std;
#define COMPUTER 1
#define HUMAN 2
#define SIDE 3 // Length of the board
// Computer will move with 'O'
// and human with 'X'
#define COMPUTERMOVE 'O'
#define HUMANMOVE 'X'
// A function to show the current board status
void showBoard(char board[][SIDE])
{
    printf("\n\n");

    printf("\t\t\t %c | %c | %c \n", board[0][0],
           board[0][1], board[0][2]);
    printf("\t\t\t--------------\n");
    printf("\t\t\t %c | %c | %c \n", board[1][0],
           board[1][1], board[1][2]);
    printf("\t\t\t--------------\n");
    printf("\t\t\t %c | %c | %c \n\n", board[2][0],
           board[2][1], board[2][2]);

    return;
}

// A function to show the instructions
void showInstructions()
{
    printf("\t\t\t Tic-Tac-Toe\n\n");
    printf("Choose a cell numbered from 1 to 9 as below"
           " and play\n\n");

    printf("\t\t\t 1 | 2 | 3 \n");
    printf("\t\t\t--------------\n");
    printf("\t\t\t 4 | 5 | 6 \n");
    printf("\t\t\t--------------\n");
    printf("\t\t\t 7 | 8 | 9 \n\n");

    printf("-\t-\t-\t-\t-\t-\t-\t-\t-\t-\n\n");

    return;
}

// A function to initialise the game
void initialise(char board[][SIDE], int moves[])
{
    // Initiate the random number generator so that
    // the same configuration doesn't arises
    srand(time(NULL));

    // Initially the board is empty
    for (int i = 0; i < SIDE; i++)
    {
        for (int j = 0; j < SIDE; j++)
            board[i][j] = ' ';
    }

    // Fill the moves with numbers
    for (int i = 0; i < SIDE * SIDE; i++)
        moves[i] = i;

    // randomise the moves
    random_shuffle(moves, moves + SIDE * SIDE);

    return;
}

// A function to declare the winner of the game
void declareWinner(int whoseTurn)
{
    if (whoseTurn == COMPUTER)
        printf("COMPUTER has won\n");
    else
        printf("HUMAN has won\n");
    return;
}

// A function that returns true if any of the row
// is crossed with the same player's move
bool rowCrossed(char board[][SIDE])
{
    for (int i = 0; i < SIDE; i++)
    {
        if (board[i][0] == board[i][1] &&
            board[i][1] == board[i][2] &&
            board[i][0] != ' ')
            return (true);
    }
    return (false);
}

// A function that returns true if any of the column
// is crossed with the same player's move
bool columnCrossed(char board[][SIDE])
{
    for (int i = 0; i < SIDE; i++)
    {
        if (board[0][i] == board[1][i] &&
            board[1][i] == board[2][i] &&
            board[0][i] != ' ')
            return (true);
    }
    return (false);
}

// A function that returns true if any of the diagonal
// is crossed with the same player's move
bool diagonalCrossed(char board[][SIDE])
{
    if (board[0][0] == board[1][1] &&
        board[1][1] == board[2][2] &&
        board[0][0] != ' ')
        return (true);

    if (board[0][2] == board[1][1] &&
        board[1][1] == board[2][0] &&
        board[0][2] != ' ')
        return (true);

    return (false);
}

// A function that returns true if the game is over
// else it returns a false
bool gameOver(char board[][SIDE])
{
    return (rowCrossed(board) || columnCrossed(board) || diagonalCrossed(board));
}

// A function to play Tic-Tac-Toe
void playTicTacToe(int whoseTurn)
{
    // A 3*3 Tic-Tac-Toe board for playing
    char board[SIDE][SIDE];

    int moves[SIDE * SIDE];

    // Initialise the game
    initialise(board, moves);

    // Show the instructions before playing
    showInstructions();

    int moveIndex = 0, x, y;

    // Keep playing till the game is over or it is a draw
    while (gameOver(board) == false &&
           moveIndex != SIDE * SIDE)
    {
        if (whoseTurn == COMPUTER)
        {
            x = moves[moveIndex] / SIDE;
            y = moves[moveIndex] % SIDE;
            board[x][y] = COMPUTERMOVE;
            printf("COMPUTER has put a %c in cell %d\n",
                   COMPUTERMOVE, moves[moveIndex] + 1);
            showBoard(board);
            moveIndex++;
            whoseTurn = HUMAN;
        }

        else if (whoseTurn == HUMAN)
        {
            x = moves[moveIndex] / SIDE;
            y = moves[moveIndex] % SIDE;
            board[x][y] = HUMANMOVE;
            printf("HUMAN has put a %c in cell %d\n",
                   HUMANMOVE, moves[moveIndex] + 1);
            showBoard(board);
            moveIndex++;
            whoseTurn = COMPUTER;
        }
    }

    // If the game has drawn
    if (gameOver(board) == false &&
        moveIndex == SIDE * SIDE)
        printf("It's a draw\n");
    else
    {
        // Toggling the user to declare the actual
        // winner
        if (whoseTurn == COMPUTER)
            whoseTurn = HUMAN;
        else if (whoseTurn == HUMAN)
            whoseTurn = COMPUTER;

        // Declare the winner
        declareWinner(whoseTurn);
    }
    return;
}

// Driver program
int main()
{
    // Let us play the game with COMPUTER starting first
    playTicTacToe(COMPUTER);

    return (0);
}

输出:

Tic-Tac-Toe

Choose a cell numbered from 1 to 9 as below and play
              1 | 2  | 3  
            - - - - - - - -
              4 | 5  | 6  
            - - - - - - - - 
              7 | 8  | 9  
-    -    -    -    -    -    -    -    -    -
COMPUTER has put a O in cell 6
                |    |    
            - - - - - - - -
                |    | O  
            - - - - - - - -
                |    |    
HUMAN has put a X in cell 7
                |    |    
            - - - - - - - -
                |    | O  
            - - - - - - - -
              X |    |    



COMPUTER has put a O in cell 5
                |    |    
            - - - - - - - -
                | O  | O  
            - - - - - - - -
              X |    |    
HUMAN has put a X in cell 1
              X |    |    
            - - - - - - - -
                | O  | O  
            - - - - - - - -
              X |    |    
COMPUTER has put a O in cell 9
              X |    |    
            - - - - - - - -
                | O  | O  
            - - - - - - - -
              X |    | O  
HUMAN has put a X in cell 8
              X |    |    
            - - - - - - - -
                | O  | O  
            - - - - - - - -
              X | X  | O  

COMPUTER has put a O in cell 4
              X |    |    
            - - - - - - - -
              O | O  | O  
            - - - - - - - -
              X | X  | O  
COMPUTER has won

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程