欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用c语言写一个简单的三子棋(井字棋)

程序员文章站 2024-03-19 16:47:34
...

用c语言写一个简单的三子棋(井字棋)
emmmm…大致就是这个效果

目录

1.所需的知识

c语言基本语法,二维数组。

2.总体思路

将三子棋看作3x3的一个二维数组,由玩家和电脑分别填充这个数组。当行、列、叉能够达到三连时,就判断输赢。
默认玩家先行且棋子为 ‘ X ’,电脑后手棋子为 ‘ 0 ’。
下面是用到的一些函数。

//game.h
#ifndef __GAME_H__
#define __GAME_H__
#define ROW 3
#define CLO 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>
void menu();                                           //打印菜单
void game(char arr[ROW][CLO], int row, int clo);       //执行菜单   
void play(char arr[ROW][CLO], int row, int clo);       //游戏主体
void InitBoard(char arr[ROW][CLO], int row, int clo);  //打印棋盘
void Pmove(char arr[ROW][CLO], int row, int clo);      //玩家下棋
void Cmove(char arr[ROW][CLO], int row, int clo);      //电脑下棋
int Isfull(char arr[ROW][CLO], int row, int clo);      //检测盘满
int Iswin(char arr[ROW][CLO], int row, int clo);       //判断输赢
#endif

下面是主函数

//test.c
#include"game.h"
int main()
{
    srand((unsigned int)time(NULL)); //产生随机数种子
    char arr[ROW][CLO];
    game(arr,ROW,CLO);
    system("pause");
    return 0;
}

3.详细实现

打印菜单

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

这个函数打印菜单选项。

执行菜单

void game(char arr[ROW][CLO], int row, int clo)
{
    int input = 0;
    do
    {
        menu();
        scanf_s("%d",&input);
        memset(arr, ' ', ROW*CLO * sizeof(arr[0][0]));
        switch (input)
        {
        case 1:
            play(arr, row, clo); break;
        case 2:
            exit(0); break;
        default:printf("你按错键了?\n");
        }
    } while (input);
}

这个函数是菜单执行部分。其中 memset 用来初始化二位字符数组为全‘ 空格 ’。
接着,用switch语句来判断玩家选项。

游戏主体

void play(char arr[ROW][CLO], int row, int clo)
{
    int flag = 0;
    InitBoard(arr, row, clo);
    while (1)
    {
        printf("人类走\n");
        Pmove(arr, row, clo);
        InitBoard(arr, row, clo);
        flag = Iswin(arr, row, clo);
        if (flag == 1)
        {
            printf("玩家赢\n");
            break;
        }
        flag = Isfull(arr, row, clo);
        if (flag == 4)
        {
            printf("棋盘满,游戏结束\n");
            break;
        }
        printf("电脑走\n");
        Cmove(arr, row, clo);
        InitBoard(arr, row, clo);
        flag = Iswin(arr, row, clo);
        if (flag == 1)
        {
            printf("电脑赢\n");
            break;
        }
    }
}

这个函数里面拥有一个 while 死循环,它的跳出条件是 玩家赢 、 电脑赢 、棋盘满。
flag == 1 表示电脑或者玩家获胜,flag == 4 表示棋盘满了。
这里将棋盘满的检测放在玩家行动后,因为只有先手才能使棋盘满。

棋盘打印

void InitBoard(char arr[ROW][CLO], int row, int clo)
{
    int i = 0;
    int j = 0;
    for (j = 0; j < row; j++)
    {
        for (i = 0; i < clo; i++)
        {
            printf(" %c ", arr[j][i]);
            if (i < (clo - 1))
            {
                printf("|");
            }
        }
        printf("\n");
        if (j < row - 1)
        {
            for (i = 0; i < clo; i++)
            {
                printf("---");
                if (i < (clo - 1))
                {
                    printf("|");
                }
            }
        }
        printf("\n");
    }
}

这个棋盘打印函数可以扩展。只要改变ROW 和 CLO 的值就可以改变棋盘大小。
例如: 7x7的棋盘
用c语言写一个简单的三子棋(井字棋)

玩家下棋

void Pmove(char arr[ROW][CLO], int row, int clo)
{
    printf("请输入坐标(空格隔开)\n");
    int m = 0, n = 0;
    while (1)
    {
        scanf_s("%d %d", &m, &n);
        if (((m >= 1) && (m <= 3)) && ((n >= 1) && (n <= 3)))
        {
            if (arr[m - 1][n - 1] == ' ')
            {
                arr[m - 1][n - 1] = 'X';
                break;
            }
            else
            {
                printf("这里可能已经有棋子了\n");
            }
        }
        else
        {
            printf("可能你输错了\n");
        }
    }
}

这个是玩家输入函数。这里注意判断输入是否合法,输入范围1~3,并查看该点是否有棋子。考虑玩家因素,将获取的数字-1,使之成为数组变量。

判断输赢

int Iswin(char arr[ROW][CLO], int row, int clo)
{
    //行
    int i = 0;
    for (i = 0; i < row; i++)
    {
        if (((arr[i][0] == arr[i][1]) && (arr[i][1] == arr[i][2])) && ((arr[i][0] != ' ')))
        {
            return 1;
        }
    }
    //列
    for (i = 0; i < clo; i++)
    {
        if ((arr[0][i] == arr[1][i]) && (arr[1][i] == arr[2][i]) && ((arr[0][i] != ' ') ))
        {
            return 1;
        }
    }
    //叉
    if ((arr[0][0] == arr[1][1]) && (arr[1][1] == arr[2][2]) && ((arr[0][0] != ' ') ))
    {
        return 1;
    }
    if ((arr[0][2] == arr[1][1]) && (arr[1][1] == arr[2][0]) && ((arr[0][2] != ' ')))
    {
        return 1;
    }
    return 0;
}

这个函数判断输赢。由于3行3列,所以用for循环扫描3次。当连续三字相同且不为‘ 空格 ’,那么取得胜利。

电脑下棋(核心)

void Cmove(char arr[ROW][CLO], int row, int clo)
{
    int flag = 0;
    int m = 0, n = 0;
    for (m = 0; m < row; m++)
    {
        for (n = 0; n < row; n++)
        {
            if (arr[m][n] == ' ')
            {
                arr[m][n] = '0';
                flag = Iswin(arr, row, clo);
                if (flag == 0)
                {
                    arr[m][n] = ' ';
                }
                if (flag == 1)
                {
                    break;
                }
            }
        }
        if (flag == 1)
        {
            break;
        }
    }
    if (flag == 0)
    {
        for (m = 0; m < row; m++)
        {
            for (n = 0; n < row; n++)
            {
                if (arr[m][n] == ' ')
                {
                    arr[m][n] = 'X';
                    flag = Iswin(arr, row, clo);
                    if (flag == 0)
                    {
                        arr[m][n] = ' ';
                    }
                    if (flag == 1)
                    {
                        arr[m][n] = '0';
                        break;
                    }
                }
            }
            if (flag == 1)
            {
                break;
            }
        }

        if ((m == 3) && (n == 3))
        {
            while (1)
            {
                m = rand() % 3;
                n = rand() % 3;
                if (arr[m][n] == ' ')
                {
                    arr[m][n] = '0';
                    break;
                }
            }
        }
    }
}

这是个电脑下棋函数。这里动了点歪脑筋。
第一个双层for循环的作用是:依次检测空位。如果是空位,那么先让该空位被’ 0 ‘填充,然后判断能不能获胜。能获胜就跳出 且 flag == 1,不能获胜就把改位再次置成空位。

接上述不能获胜。如果扫描完后发现并不能获胜,那么采取防守策略。

第二个双层for循环也是检测空位。如果是空位,那么让该位被 ’ X ‘填充,(相当电脑伪装成玩家先走一步)。填充后判断输赢,如果能够获胜,那么电脑再将这个位置改为‘ 0 ’,达到阻止玩家取胜的目的。

最后如果既不能取得胜利,也不用阻止玩家获胜。那么,就让电脑随机找位置下棋。

判断盘满

int Isfull(char arr[ROW][CLO], int row, int clo)
{
    int i = 0, j = 0;
    int count = 0;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < clo; j++)
        {
            if (arr[i][j] != ' ')
            {
                count ++;
            }
        }
    }
    if (count == 9)
    {
        return 4;
    }
    return 3;
}

这个函数是判断棋盘是否满。使用count变量计数,扫描棋盘,如果不为‘ 空格 ’的位置有九个,那么就表示棋盘满了。

3.效果演示

会堵人的电脑
用c语言写一个简单的三子棋(井字棋)
会优先自己胜利的电脑
用c语言写一个简单的三子棋(井字棋)
棋盘满效果
用c语言写一个简单的三子棋(井字棋)

PS:先手优势很大,不出意外的话是先手赢,或是平局。
依此类推,五子棋在15x15及其以上的棋盘,先手必胜。
但是电脑获胜算法非常复杂,反正我是写不出来。

相关标签: 三子棋