三子棋

  • test.c部分
    • main函数
    • test函数
  • game.h部分
  • game.c部分
    • 游戏菜单
    • 棋盘的初始化
    • 棋盘的打印
    • 玩家下棋
    • 电脑下棋
    • 判断输赢
    • 游戏引擎
  • 完整代码
  • 结语

test.c部分

main函数

int main()
{test();     //test可以测试该游戏的全部功能return 0;
}

一个程序的运行是从main函数开始,main函数结尾的,在写程序代码的时候尽量减少main函数中的代码,这样做的目的是使代码封装在函数内部,这样会使程序更加简洁,更清晰,容易修改,这样写代码是一个好的代码习惯。

test函数

//定义一个输入,代表游戏的开始或者退出
int input = 0;//测试三子棋的函数
void test()
{srand((unsigned int)time(NULL));do{menu();  //打印一个菜单,提示 1开始 0退出again:   //防止输入错误时打印多份菜单printf("请输入:>");scanf("%d", &input);switch (input)   //使用switch分几种不同输入时进入不同的函数{case 0:printf("退出游戏\n");break;case 1:case 2:system("cls");   //当进入一次游戏时,清一次屏幕game();break;default:printf("输入错误,重新输入!\n");goto again;break;}} while (input);    //当input=0时刚好退出,放在这里很合理
}

当程序执行时,我们要先设计一个菜单,给用户提供选择,我们要将用户选择的值存放起来,调用相对应的函数,在这里我用了一个switch语句来进行选择,把input设置为全局变量是因为我这里有三个选择,双人版,单人版,和退出。方便后面再双人版和单人版的逻辑实现。

game.h部分

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3    //棋盘的行
#define COL 3    //棋盘的列//游戏菜单
void menu();//游戏实现
void game();

在这里引入整个工程所需要的头文件,其它的.c文件包含这个头文件,就可以实现该头文件里面包含的内容。
ROW 是游戏棋盘的行,COL 是列,这里使用宏定义是为了方便后期改成五子棋,四子棋之类的。
在这个头文件中同时也包含了game.c里面的部分函数声明。

game.c部分

游戏菜单

//游戏菜单
void menu()
{printf("**********************\n");printf("****  三  子  棋  ****\n");printf("****   1.双人对决 ****\n");printf("****   2.人机对决 ****\n");printf("****   0.退出     ****\n");printf("**********************\n");
}


在主函数里面会调用此游戏菜单,供用户选择。

棋盘的初始化

void Initmap(char arr[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){arr[i][j] = ' ';}}
}

游戏的数据我们这里选择一个字符型二维数组来进行存放,开始初始化数组内容全部为’ '空格,这样设置后面棋盘打印的比较美观。

棋盘的打印

void Print(char arr[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c |", arr[i][j]);}printf("\b \n");    //注意退格符要与空格搭配使用if (i < row - 1){for (j = 0; j < col; j++){printf("---|");}printf("\b \n");}}
}

这里我设置的为三子棋,所以只打印三行三列,但是在这里我们打印了5行,第一行打印数组的第一行内容,每打印一个符号后面跟一个|当分隔符,但是这样会多出来一个|,在这里我们就要使用\b退格符要搭配空格使用才起作用,就可以消除最后面的那个|,第二行打印一行下划线,用于区分每一行的,以此类推,但是这样也会多打印一行下滑线,这里我们用if语句进行判断,当打印到最后一行时,不打印下划线。

玩家下棋

void Input(char map[ROW][COL], int row, int col, char ret, char* gamer)
{int x, y;printf("%s输入:>", gamer);while (1){scanf("%d %d", &x, &y);if (x > row || y > col || x <= 0 || y <= 0){printf("非法输入,重新输入:>");}else{if (map[x - 1][y - 1] != ' '){printf("位置重复占用,重新输入:>");}else{map[x - 1][y - 1] = ret;break;}}}
}

void Input(char map[ROW][COL], int row, int col, char ret, char* gamer)
该函数有四个参数第一个是我们传进去的棋盘,第二个是行数,第三个是列数,第四个是要存的符号,就是二维数组中保存的符号,方便后面双人版的实现。
1.首先我们要提示玩家下棋;
2.当玩家下完棋之后,我们要判断位置的合法性,有没有越界或者已经下过棋子;
3.当以上条件都成立时,我们将玩家输入的坐标,在二维数组中存放数据,在这里玩家下棋输入的下标,认为都是从1开始的,但是数组的下标是从0开始的,所以要-1。

电脑下棋

void ComperInput(char map[ROW][COL], int row, int col)
{// *while (1){int x = rand() % row;int y = rand() % col;if (map[x][y] == ' '){map[x][y] = '*';break;}}
}

void ComperInput(char map[ROW][COL], int row, int col);
该函数有三个参数;
第一个是二维数组,第二个是行数,第三个是列数;
1.电脑下棋不用提示;
2.电脑下棋的坐标我们用随机数函数生成,控制取值范围在:0~2之内;
3.这里只需用判断该坐标是否有棋子;

判断输赢

//‘D’表示平局,'A'表示玩家1胜,'B'表示玩家2胜,
// ‘C’表示游戏继续
//输入坐标为(1,1)时,实际在数组中的坐标是(0,0)
char is_win(char map[ROW][COL], int row, int col)
{int i, j;//A和B只能在进入函数时初始化一次int A = 1, B = 1;//记录下棋的次数count++;//行判断for (i = 0; i < row; i++){for (j = 0; j < col - 1; j++){if (map[i][j] != map[i][j + 1]){A = 0;B = 0;break;/*if (map[i][j] == '#' && map[i][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i][j + 1] == ' '){A = 0, B = 0;break;}*/}else{if (map[i][j] == '#' && map[i][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i][j + 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}}//列判断for (i = 0; i < row; i++){for (j = 0; j < col - 1; j++){if (map[j][i] != map[j + 1][i]){A = 0;B = 0;break;/*if (map[j][i] == '#' && map[j][i + 1] == '#'){A = 1;}if (map[j][i] == '*' && map[j][i + 1] == '*'){B = 1;}if (map[j][i] == ' ' || map[j][i + 1] == ' '){A = 0, B = 0;break;}*/}else{if (map[j][i] == '#' && map[j + 1][i] == '#'){A = 1;}if (map[j][i] == '*' && map[j + 1][i] == '*'){B = 1;}if (map[j][i] == ' ' || map[j + 1][i] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}}//左对角线判断for (i = 0,j = 0; i < row - 1,j < col - 1; i++, j++){if (map[i][j] != map[i + 1][j + 1]){A = 0;B = 0;break;/*if (map[j][i] == '#' && map[j + 1][i + 1] == '#'){A = 1;}if (map[j][i] == '*' && map[j + 1][i + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j + 1] == ' '){A = 0, B = 0;}*/}else{if (map[i][j] == '#' && map[i + 1][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j + 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}//右对角线判断for (i = 0, j = col - 1; (j >= 1 && i < row - 1); j--, i++){if (map[i][j] != map[i + 1][j - 1]){A = 0;B = 0;break;/*if (map[i][j] == '#' && map[i + 1][j - 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j - 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j - 1] == ' '){A = 0, B = 0;}*/}else{if (map[i][j] == '#' && map[i + 1][j - 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j - 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j - 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}//判断棋盘是否已满if (count == row * col){//这里要将A和B置为0,否则出去A和B都等于1A = 0, B = 0;return 'D';}return 'C';
}

1.行判断,判断一行是否都是一个符号;
2.列判断,判断一列是否都是一个符号;
3.左对角线判断,判断对角线上的符号是否相同;
4.右对角线判断,判断对角线上的符号是否相同;
5.用返回的参数决定游戏谁赢谁输或者游戏结束,
//‘D’表示平局,'A’表示玩家1胜,'B’表示玩家2胜,
// ‘C’表示游戏继续

游戏引擎

void game()
{char ret = 0;   //用于记录输赢的符号char map[ROW][COL];  //用一个二维数组存储输入的数据Initmap(map, ROW, COL);    //初始化棋盘Print(map, ROW, COL);   //打印游戏棋盘count = 0;//下棋过程while (1){//玩家1下棋Input(map, ROW, COL, '#', "玩家1");//清除上一次的棋盘system("cls");//下一次棋,打印一次棋盘Print(map, ROW, COL);   //打印游戏棋盘//判断游戏是否结束//返回值是C时游戏继续if ((ret = is_win(map, ROW, COL)) != 'C'){break;}//玩家2下棋switch (input){case 1:Input(map, ROW, COL, '*', "玩家2");break;case 2:ComperInput(map, ROW, COL);break;}system("cls");Print(map, ROW, COL);   //打印游戏棋盘//判断游戏是否结束//返回值是C时游戏继续if ((ret = is_win(map, ROW, COL)) != 'C'){break;}}if (ret == 'A'){printf("玩家1胜!\n");}else if (ret == 'B'){printf("玩家2胜!\n");}else if (ret == 'D'){printf("平局\n");}
}

该函数是整合了上面的函数功能来实现我们想要的功能。
调用此函数就可以驱动游戏的核心。

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 3    //棋盘的行
#define COL 3    //棋盘的列//定义一个输入,代表游戏的开始或者退出
int input = 0;//记录判断的次数,等于下棋的个数
int count = 0;//游戏菜单
void menu()
{printf("**********************\n");printf("****  三  子  棋  ****\n");printf("****   1.双人对决 ****\n");printf("****   2.人机对决 ****\n");printf("****   0.退出     ****\n");printf("**********************\n");
}void Print(char arr[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c |", arr[i][j]);}printf("\b \n");    //注意退格符要与空格搭配使用if (i < row - 1){for (j = 0; j < col; j++){printf("---|");}printf("\b \n");}}
}void Initmap(char arr[ROW][COL], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){arr[i][j] = ' ';}}
}//玩家下棋用#,电脑下棋用*
void Input(char map[ROW][COL], int row, int col, char ret, char* gamer)
{int x, y;printf("%s输入:>", gamer);while (1){scanf("%d %d", &x, &y);if (x > row || y > col || x <= 0 || y <= 0){printf("非法输入,重新输入:>");}else{if (map[x - 1][y - 1] != ' '){printf("位置重复占用,重新输入:>");}else{map[x - 1][y - 1] = ret;break;}}}
}//电脑下棋
void ComperInput(char map[ROW][COL], int row, int col)
{// *while (1){int x = rand() % row;int y = rand() % col;if (map[x][y] == ' '){map[x][y] = '*';break;}}
}//‘D’表示平局,'A'表示玩家1胜,'B'表示玩家2胜,
// ‘C’表示游戏继续
//输入坐标为(1,1)时,实际在数组中的坐标是(0,0)
char is_win(char map[ROW][COL], int row, int col)
{int i, j;//A和B只能在进入函数时初始化一次int A = 1, B = 1;//记录下棋的次数count++;//行判断for (i = 0; i < row; i++){for (j = 0; j < col - 1; j++){if (map[i][j] != map[i][j + 1]){A = 0;B = 0;break;/*if (map[i][j] == '#' && map[i][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i][j + 1] == ' '){A = 0, B = 0;break;}*/}else{if (map[i][j] == '#' && map[i][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i][j + 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}}//列判断for (i = 0; i < row; i++){for (j = 0; j < col - 1; j++){if (map[j][i] != map[j + 1][i]){A = 0;B = 0;break;/*if (map[j][i] == '#' && map[j][i + 1] == '#'){A = 1;}if (map[j][i] == '*' && map[j][i + 1] == '*'){B = 1;}if (map[j][i] == ' ' || map[j][i + 1] == ' '){A = 0, B = 0;break;}*/}else{if (map[j][i] == '#' && map[j + 1][i] == '#'){A = 1;}if (map[j][i] == '*' && map[j + 1][i] == '*'){B = 1;}if (map[j][i] == ' ' || map[j + 1][i] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}}//左对角线判断for (i = 0,j = 0; i < row - 1,j < col - 1; i++, j++){if (map[i][j] != map[i + 1][j + 1]){A = 0;B = 0;break;/*if (map[j][i] == '#' && map[j + 1][i + 1] == '#'){A = 1;}if (map[j][i] == '*' && map[j + 1][i + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j + 1] == ' '){A = 0, B = 0;}*/}else{if (map[i][j] == '#' && map[i + 1][j + 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j + 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j + 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}//右对角线判断for (i = 0, j = col - 1; (j >= 1 && i < row - 1); j--, i++){if (map[i][j] != map[i + 1][j - 1]){A = 0;B = 0;break;/*if (map[i][j] == '#' && map[i + 1][j - 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j - 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j - 1] == ' '){A = 0, B = 0;}*/}else{if (map[i][j] == '#' && map[i + 1][j - 1] == '#'){A = 1;}if (map[i][j] == '*' && map[i + 1][j - 1] == '*'){B = 1;}if (map[i][j] == ' ' || map[i + 1][j - 1] == ' '){A = 0, B = 0;break;}}}if (A == 1){return 'A';}else if (B == 1){return 'B';}//判断棋盘是否已满if (count == row * col){//这里要将A和B置为0,否则出去A和B都等于1A = 0, B = 0;return 'D';}return 'C';
}//游戏实现
void game()
{char ret = 0;   //用于记录输赢的符号char map[ROW][COL];  //用一个二维数组存储输入的数据Initmap(map, ROW, COL);    //初始化棋盘Print(map, ROW, COL);   //打印游戏棋盘count = 0;//下棋过程while (1){//玩家1下棋Input(map, ROW, COL, '#', "玩家1");//清除上一次的棋盘system("cls");//下一次棋,打印一次棋盘Print(map, ROW, COL);   //打印游戏棋盘//判断游戏是否结束//返回值是C时游戏继续if ((ret = is_win(map, ROW, COL)) != 'C'){break;}//玩家2下棋switch (input){case 1:Input(map, ROW, COL, '*', "玩家2");break;case 2:ComperInput(map, ROW, COL);break;}system("cls");Print(map, ROW, COL);   //打印游戏棋盘//判断游戏是否结束//返回值是C时游戏继续if ((ret = is_win(map, ROW, COL)) != 'C'){break;}}if (ret == 'A'){printf("玩家1胜!\n");}else if (ret == 'B'){printf("玩家2胜!\n");}else if (ret == 'D'){printf("平局\n");}
}//测试三子棋的函数
void test()
{srand((unsigned int)time(NULL));do{menu();  //打印一个菜单,提示 1开始 0退出again:   //防止输入错误时打印多份菜单printf("请输入:>");scanf("%d", &input);switch (input)   //使用switch分几种不同输入时进入不同的函数{case 0:printf("退出游戏\n");break;case 1:case 2:system("cls");   //当进入一次游戏时,清一次屏幕game();break;default:printf("输入错误,重新输入!\n");goto again;break;}} while (input);    //当input=0时刚好退出,放在这里很合理
}int main()
{test();return 0;
}

结语

到这里这篇博客已经结束啦。
这份博客

三子棋(双人对决+人机对战)相关推荐

  1. 三子棋游戏(人机对战)

    1.打印棋盘 采用二维数组打印元素,先初始化棋盘中元素为' '(空格字符),在打印棋盘元素的同时加上边框 2.玩家落子9(棋子用字符'x'表示) 3.电脑落子(棋子用字符'o'表示) 用rand函数设 ...

  2. C语言实现三子棋plus版本(困难人机电脑不会输,支持双人对战)

    目录 一.功能描述 二.游戏部分功能介绍 三.代码实现 1. main()代码 2.游戏菜单代码 3.playgame()代码 3.模式菜单和难度菜单 4.初始化棋盘 5.打印棋盘 6.玩家下棋 7. ...

  3. 哥们哥们,人机大战晓得吧玩家对战晓得吧,简易三子棋,呕心沥血500行代码手把手带你制作第一个小游戏,可以保存收藏以后接着看哟,最后有源码哦

    目录 前言 一.游戏想要有意思,函数不可少,整活的函数 二.三子棋的游戏界面 三.三子棋的功能步骤分析      1.菜单     2.三子棋实现的总体框架     3.棋盘创建     4.棋盘初始 ...

  4. C语言实现简易三子棋,支持双人对战,电脑可拦截

    在学习二维数组后我们加以应用能写出三子棋这样一个小游戏.具体实现并不复杂. 基本思路: 游戏首先打印菜单,由我们选择单人游戏,双人游戏或退出游戏. 三子棋需要一个棋盘,我们可以通过循环打印来构造一个简 ...

  5. 【C语言五子棋、三子棋人机对战篇的详细介绍】

    C语言--五子棋.井字棋人机对"战" 针对 "[C语言实现五子棋.三子棋人机对战,包含电脑人工智能对战(可攻可守)](非标题党)" 的详细介绍 五子棋.三子棋人 ...

  6. 【C语言实现五子棋、三子棋人机对战,包含电脑人工智能对战(可攻可守)】(非标题党)

    C语言--五子棋.井字棋人机对"战" 针对C语言学习过程中的五子棋.三子棋实现记录 五子棋人机对战 C语言--五子棋.井字棋人机对"战" 实际效果 一.头文件( ...

  7. 三子棋小游戏,实现人机对战,电脑可做简单拦截(C语言版)

    前言 相信很多同学在学了一小部分C语言之后,总是对自己的能力有疑问,不知道自己现在是什么水平,大家可以尝试一下博主的简易的三子棋游戏,大家可以去练练手.下面是博主的三子棋游戏实现的主要步骤(博主的篇幅 ...

  8. Qt、C++实现五子棋人机对战与本地双人对战

    1.基本介绍 软件基于Qt5.6.1,利用C++语言进行编写. 五子棋有两种游戏模式:人机对战和双人对战. 在进入游戏时玩家选择游戏模式. 选择人机对战玩家会执黑棋.电脑执白棋进行对决.选择双人对战会 ...

  9. 人机对战初体验:Python基于Pygame实现四子棋游戏

    人机对战初体验-四子棋游戏 继去年3月人机大战引发全球瞩目以来,围棋AI(人工智能)再度引发跨领域的关注:一个叫Master的围棋AI,几天时间,面对中日韩顶尖职业围棋选手,已取得60胜0败的恐怖战绩 ...

最新文章

  1. 框架+重量级+轻量级
  2. 【Win7 Oracle 10G rman迁移恢复到Linux 32bit oracle 10G实战】
  3. saltstack配置管理之YAML(二)
  4. Python: Python中的AttributeError错误
  5. 使用html() undefined_SweetAlert2使用教程
  6. mysql 执行存储过程_MySQL存储过程的3种循环
  7. PCB常用度量衡单位
  8. Linux基于升序链表的定时器
  9. 躲开Xilinx官网龟速的下载器
  10. 超全opencv常见图像处理操作总结及效果展示(附python代码)
  11. steam host修改
  12. 高斯光束及其MATLAB仿真
  13. 让微积分穿梭于工作与学习之间(7):我自认为牛逼的成果之三:直接用定义求正切函数的导数
  14. 【Linux】循序渐进学运维-学习方法篇
  15. 《世界500强企业员工的50条生存法则》(Yanlz+Unity+SteamVR+5G+AI+VR云游戏+生存法则+潜规则+提升竞争力+术业有专攻+卓越理念+立钻哥哥+==)
  16. 类与对象的基本语法+练习题
  17. Oracle WebLogic Server 12c: Node Manager配置与使用
  18. 【Cocos游戏】《天天炫斗》:在手机上感受街机狂潮
  19. 金融经济学期末梳理(王江)第二、三章
  20. 《自私的基因》理查德道金斯 epub+mobi+azw3

热门文章

  1. css--盒子的尺寸
  2. Python | P站壁纸爬取
  3. 华为Mate 20 Pro拆解、iPhone XR 拆解、iPhone XS/XS Max拆解
  4. Al-learing数学基础,平均差,方差,协方差
  5. python绘制三维矢量图_开源图形库 c语言-图形图像库 集合
  6. Android——SVG图片转成安卓能用的vector矢量图
  7. 【pytorch】 grad、grad_fn、requires_grad()、with torch.no_grad() 、net.train()、net.eval():记录一次奇怪的debug经历
  8. [XJTUSE 算法设计与分析] 第三章 动态规划 3.2 动态规划典型例题与解题思路(一)
  9. 微型计算机输出设备 写出六种,2017计算机一级考试强化训练
  10. 折线分割平面(图文解析)