鹏哥-C语言-三子棋(不写死)的实现(小菜的c之路1)

用c语言实现人机对战的三子棋(多子琪),代码无写死,可通过宏定义灵活改动,但是电脑下棋并不够智能,需要自己加一些算法来训练电脑,出奇制胜。

首先需要先写一个菜单函数,不管我们玩不玩都会先执行一遍,所以采用的do、while,再执行switch,判断玩家选择的是什么分支,执行无错误之后再开始改动。

接着写我们的初始化面板函数和展示面板函数,实现实时打印面板状态。

接着编写我们的玩家/电脑下棋函数,玩家下棋需要先判断输入的坐标是否在范围内,且是否为空,电脑下棋需要rand函数结合srand函数产生随机数在空位置随机下棋。

判断输赢函数,在每次下棋之后执行,最后完成了我们的三子棋程序。

最后,美化代码,为我们的代码添加注释,方便日后阅读。

test.c文件

#include "game.h"

void menu()
{
    printf("******************************\n");
    printf("*******1. play 0. exit********\n");
    printf("******************************\n");
}

void game()
{
    int ret = 0;
    char Board[ROW][COL] = { 0 };
    InitBoard(Board, ROW, COL);  // 初始化游戏棋盘
    DisplayBoard(Board, ROW, COL);  // 显示初始游戏棋盘
    while (1)
    {
        PlayerMove(Board, ROW, COL);  // 玩家进行移动
        ret = IsWin(Board, ROW, COL);  // 检查是否有玩家胜利
        if (ret != 'C')
        {
            break;  // 如果有胜利者,则退出游戏循环
        }
        DisplayBoard(Board, ROW, COL);  // 显示更新后的游戏棋盘
        ComputerMove(Board, ROW, COL);  // 计算机进行移动
        ret = IsWin(Board, ROW, COL);  // 检查是否有计算机胜利
        if (ret != 'C')
        {
            break;  // 如果有胜利者,则退出游戏循环
        }
        DisplayBoard(Board, ROW, COL);  // 显示更新后的游戏棋盘
    }
    if (ret == '*')
    {
        printf("The Winner is Player\n");  // 打印玩家获胜信息
    }
    else if (ret == '#')
    {
        printf("The Winner is Computer\n");  // 打印计算机获胜信息
    }
    else
    {
        printf("Game Tie\n");  // 打印平局信息
    }
    DisplayBoard(Board, ROW, COL);  // 最终显示游戏棋盘
}


int main()
{
    srand((unsigned int)time(NULL));  // 设置随机数种子
    int input = 0;
    do
    {
        menu();  // 显示游戏菜单
        printf("Please Enter a Number > ");
        scanf("%d", &input);  // 获取用户输入的数字
        switch (input)
        {
        case 1:
            game();  // 开始游戏
            break;
        case 0:
            printf("Successfully Exited the Game!\n");  // 输出退出游戏信息
            break;
        default:
            printf("Instruction Exception!Please Re-enter!\n");  // 输出指令异常信息
            break;
        }
    } while (input);  // 循环直到用户输入 0 退出游戏
    return 0;
}
 

game.h文件

#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define ROW 3 // 定义棋盘的行数
#define COL 3 // 定义棋盘的列数

void InitBoard(char Board[ROW][COL], int row, int col); // 初始化游戏棋盘
void DisplayBoard(char Board[ROW][COL], int row, int col); // 显示游戏棋盘
void PlayerMove(char Board[ROW][COL], int row, int col); // 玩家进行移动
void ComputerMove(char Board[ROW][COL], int row, int col); // 计算机进行移动
char IsWin(char Board[ROW][COL], int row, int col); // 检查游戏是否有胜者
int IsFull(char Board[ROW][COL], int row, int col); // 检查游戏棋盘是否已满

game.c文件

#pragma once
#include "game.h"

void InitBoard(char Board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;

    // 使用嵌套循环遍历棋盘的每个元素
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            // 将每个元素初始化为空格字符
            Board[i][j] = ' ';
        }
    }
}

void DisplayBoard(char Board[ROW][COL], int row, int col)
{
    int i = 0;

    // 使用循环遍历棋盘的每一行
    for (i = 0; i < row; i++)
    {
        int j = 0;

        // 打印每行的棋盘元素及分隔线
        for (j = 0; j < col; j++)
        {
            // 打印棋盘元素
            printf(" %c ", Board[i][j]);

            // 如果不是该行的最后一个元素,打印竖线分隔符
            if (j < col - 1)
            {
                printf("|");
            }
        }

        printf("\n");

        // 如果不是最后一行,打印横向分隔线
        if (i < row - 1)
        {
            int j = 0;
            for (j = 0; j < col; j++)
            {
                printf("---");
                // 如果不是该行的最后一个元素,打印竖线分隔符
                if (j < col - 1)
                {
                    printf("|");
                }
            }
            printf("\n");
        }
    }
}


void PlayerMove(char Board[ROW][COL], int row, int col)
{
    int x = 0;
    int y = 0;

    printf("Player chess > \n"); // 提示玩家下棋

    while (1) // 无限循环,直到玩家输入合法且空闲的坐标位置
    {
        printf("Please enter coordinates > \n");
        scanf("%d%d", &x, &y); // 接收玩家输入的坐标

        // 检查输入的坐标是否在合法范围内
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            // 检查输入的坐标是否为空闲的位置
            if (Board[x - 1][y - 1] == ' ')
            {
                Board[x - 1][y - 1] = '*'; // 在棋盘上标记玩家的棋子
                break; // 退出循环
            }
            else
            {
                printf("This location is already occupied,Please re-enter!\n"); // 坐标位置已被占用提示
            }
        }
        else
        {
            printf("Abnormal coordinates!Please re-enter!\n"); // 坐标输入不合法提示
        }
    }
}

void ComputerMove(char Board[ROW][COL], int row, int col)
{
    int x = 0;
    int y = 0;

    printf("Computer chess > \n"); // 提示计算机下棋

    while (1) // 无限循环,直到计算机找到合法且空闲的坐标位置
    {
        x = rand() % row; // 随机生成行坐标
        y = rand() % col; // 随机生成列坐标

        // 检查生成的随机坐标是否为空闲的位置
        if (Board[x][y] == ' ')
        {
            Board[x][y] = '#'; // 在棋盘上标记计算机的棋子
            break; // 退出循环
        }
    }
}

int IsFull(char Board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            if (Board[i][j] == ' ') // 检查棋盘中是否还有空闲位置
            {
                return 0; // 如果有空闲位置,返回0表示棋盘未满
            }
        }
    }
    return 1; // 如果没有空闲位置,返回1表示棋盘已满
}

char IsWin(char Board[ROW][COL], int row, int col)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < row; i++) // 检查每一行是否有相同的棋子
    {
        if (Board[i][0] != ' ') // 如果第一个格子不为空
        {
            char first = Board[i][0]; // 记录第一个格子的棋子类型
            int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
            for (j = 1; j < col; j++)
            {
                if (Board[i][j] == first) // 如果当前格子的棋子类型与第一个相同
                {
                    count++; // 增加相同棋子的数量
                    if (count == col) // 如果一整行都是相同的棋子
                    {
                        return first; // 返回获胜的棋子类型
                    }
                }
                else
                {
                    break; // 如果遇到不同的棋子类型,结束内循环
                }
            }
        }
    }

    for (j = 0; j < col; j++) // 检查每一列是否有相同的棋子
    {
        if (Board[0][j] != ' ') // 如果第一行的某个格子不为空
        {
            char first = Board[0][j]; // 记录第一个格子的棋子类型
            int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
            for (i = 1; i < row; i++)
            {
                if (Board[i][j] == first) // 如果当前格子的棋子类型与第一个相同
                {
                    count++; // 增加相同棋子的数量
                    if (count == row) // 如果一整列都是相同的棋子
                    {
                        return first; // 返回获胜的棋子类型
                    }
                }
                else
                {
                    break; // 如果遇到不同的棋子类型,结束内循环
                }
            }
        }
    }

    if (Board[0][0] != ' ') // 检查从左上到右下的对角线是否有相同的棋子
    {
        char first = Board[0][0]; // 记录左上角第一个格子的棋子类型
        int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
        for (i = 1; i < row; i++)
        {
            if (Board[i][i] == first) // 如果当前格子的棋子类型与第一个相同
            {
                count++; // 增加相同棋子的数量
                if (count == row) // 如果一整条对角线都是相同的棋子
                {
                    return first; // 返回获胜的棋子类型
                }
            }
            else
            {
                break; // 如果遇到不同的棋子类型,结束内循环
            }
        }
    }

    if (col - 1 >= 0 && Board[0][col - 1] != ' ') // 检查从右上到左下的对角线是否有相同的棋子
    {
        char first = Board[0][col - 1]; // 记录右上角第一个格子的棋子类型
        int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
        for (i = 1; i < row; i++)
        {
            if (col - 1 - i >= 0 && Board[i][col - 1 - i] == first) // 如果当前格子的棋子类型与第一个相同
            {
                count++; // 增加相同棋子的数量
                if (count == row) // 如果一整条对角线都是相同的棋子
                {
                    return first; // 返回获胜的棋子类型
                }
            }
            else
            {
                break; // 如果遇到不同的棋子类型,结束内循环
            }
        }
    }

    if (IsFull(Board, row, col)) // 如果棋盘已满且没有任何一方获胜
    {
        return 'Q'; // 返回平局标志
    }
    return 'C'; // 如果棋盘未满且没有任何一方获胜,返回继续游戏标志
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值