在学习二维数组后我们加以应用能写出三子棋这样一个小游戏。具体实现并不复杂。

基本思路:

游戏首先打印菜单,由我们选择单人游戏,双人游戏或退出游戏。
三子棋需要一个棋盘,我们可以通过循环打印来构造一个简单的3x3棋盘。

我们需要一个函数在每次下棋子后都打印一次来表示目前的棋盘,于是创建一个二维数组接收棋子后方可遍历打印。我们用 * 和 # 代表两种棋子。
游戏过程中玩家输入下标下棋后电脑下,直到决出胜负或平局。

直接看代码。
我们在写程序的时候要将函数模块化,不把所有函数都堆在一个源文件里。我们新建一个主体源文件main.c用于调用所有函数,新建一个game1.c文件用于函数的实现,即编写函数,新建一个game.h文件用于声明game1.c中的函数。

游戏菜单

void menu()
{printf("################################\n");printf("#########  1.单人游戏 ##########\n");printf("#########  2.双人游戏 ##########\n");printf("#########  3.退出游戏 ##########\n");printf("################################\n");
}

假如进入单人游戏,我们首先创建并初始化一个棋盘:

 #define ROW 3#define COL 3char board[ROW][COL] = { 0 };Initboard(board, ROW, COL);

我们用宏定义两个常量,ROW表示棋盘的行数,COL表示棋盘的列数。
这样做是方便我们一次性修改行数和列数。

初始化:

void Initboard(char board[ROW][COL], int row, int col)
{//char i = 0; char* p = board;//while (i < ROW * COL)//{//    *(p + i++) = ' ';//}//for (int i = 0;i < row;i++)//{//  for (int j = 0;j < col;j++)// {//     board[i][j] = ' ';// }//}memset(board, ' ', row * col);
}

我们有三种初始化的方式:

  1. 是定义一个指向数组的指针,这里因为笔者对指针不够熟悉,因此只定义一个普通的指针指向数组。但结果是可以实现的,因为二维数组在内存中的存储是连续的。
  2. 用循环遍历整个二维数组,将数组的每个元素赋值为空格,这是最直接的方法。
  3. memset函数一步到位。这里不对该函数多做介绍,读者可自行查询。

打印棋盘:

void Displayboard(char board[ROW][COL], int row, int col)
{for (int j = 0;j < col;j++){printf("---|");}printf("\n");for (int i = 0;i < row;i++){for (int j = 0;j < col;j++){printf(" %c ", board[i][j]);printf("|");}printf("\n");for (int j = 0;j < col;j++){printf("---");printf("|");}printf("\n");}
}

棋盘如图
我们可以直接打印棋盘样式,采用循环是因为如果改变行和列数后棋盘无法正常显示。具体实现较为简易。

玩家下棋:

void Player_move(char board[ROW][COL], int row, int col)
{int x = 0, y = 0;while (1){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("该位置已有棋子,重新输入\n");continue;}}else printf("输入错误,重新输入\n");}
}

定义X和Y变量用于接收玩家输入的下标数。之后进行循环,假如成功下子才跳出循环。我们需要判断坐标是否已经有棋子,坐标是否合法,如果输入错误即再进行循环直到输入正确。需要注意的是在赋值时注意数组下标为 X-1,Y-1。例如玩家输入2 2,本意是在中间的位置下棋,但是数组读取的时候下标要-1,即传入数组中的数值应为1 1.

电脑下棋:

void Computer_move(char board[ROW][COL], int row, int col)
{int x = 0, y = 0;while (1){x = rand() % row;y = rand() % col;simplealgorithm(board, row, col, &x, &y);
again:  if (board[x][y] == ' '){board[x][y] = '#';break;}else{x = rand() % row;y = rand() % col;goto again;}}
}

我们需要调用一个随机值来生成电脑下子的位置,于是调用rand函数,且要在main.c文件里先使用srand函数,将时间戳作为随机数种子。在主体函数里添加下列这句代码即可。

srand((unsigned int)time(NULL));

得到随机数后,将随机数%ROW,确保这个值的范围在0~ROW之间,不会越界后赋给X,作为随机的行坐标,同理得到随机的列坐标。之后调用一个极其简单的拦截函数,避免电脑看起来跟个人工智障似的。goto again是避免修改后的坐标因为无法通过判断语句后无法再取随机数后造成死循环。

电脑拦截:

void simplealgorithm(char board[ROW][COL], int row, int col,int *x,int *y)
{for (int i = 0;i <= row;i++)//行{if ((board[i][0] == board[i][1] && board[i][0] == '*')){*x = i;*y = 2;}else if ((board[i][1] == board[i][2] && board[i][1] == '*')){*x = i;*y = 0;}}for (int i = 0;i <= col;i++)//列{if ((board[0][i] == board[1][i] && board[0][i] == '*')){*x = 2;*y = i;}else if ((board[1][i] == board[2][i] && board[1][i] == '*')){*x = 0;*y = i;}}for (int i = 0;i <= col;i++)//对角线{if ((board[i][i] == board[i+1][i+1] && board[i][i] == '*')){if (i == 0){*x = 2;*y = 2;}else if (i == 1){*x = 0;*y = 0;}}else if ((board[i][2] == board[i+1][i+1] && board[i][2] == '*')){if (i == 0){*x = 2;*y = 0;}else if (i == 1){*x = 0;*y = 2;}}}
}

这个函数只是简简单单的判断,并没有什么算法,功能也不齐全,在这不多作介绍,读者可自行研究。进入函数后进行判断,如果坐标需要修改即可修改坐标地址对应的值,所以我们要把函数里的X和Y传址过去。

判断胜负或平局:

char Win(char board[ROW][COL], int row, int col)
{for (int i = 0;i < row;i++)//判断行{if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')return board[i][0];}for (int i = 0;i < col;i++)//判断列{if (board[0][i] == board[1][i] && board[2][i] == board[0][i] && board[0][i] != ' ')return board[0][i];}//判断对角线if (board[0][0] == board[1][1] && board[2][2] == board[0][0] && board[0][0] != ' ')return board[0][0];if (board[0][2] == board[1][1] && board[2][0] == board[0][2] && board[0][2] != ' ')return board[0][2];if (Full(board, row, col)){return 'F';  //Full}else return 'C';
}
int Full(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;}}}return 1;
}

我们需要函数返回一个标志来判断是谁胜谁负或平局,这里函数返回类型设为char,可读性相较int更高。
C表示continue,对局尚未结束,继续游戏。
F表示full,棋盘已满,平局。
*表示 玩家胜,#表示电脑胜。
定义一个字符变量ret用于接收字符后进行判断。
我们通过循环判断行或列或对角线,如果出现三子相等且均不为空格即返回这一线上的任意一个棋子,即是 *或#

主体函数

void body()
{srand((unsigned int)time(NULL));int input = 0;do{menu();scanf("%d", &input);switch (input){case 1:system("cls");game1();break;case 2:system("cls");printf("先手是* 后手是#\n");game2();break;case 3:printf("退出\n");input = 0;break;default:printf("输入错误,请重新选择\n");break;}} while (input);
}

主体函数要做的是通过玩家的输入值判断进入哪个选项。在循环里,input作为判断条件,如果玩家输入的是3,即退出游戏,我们便把input设为0,方跳出循环,游戏终止。接下来我们看2、双人游戏

双人游戏

void game2()
{char ret = 0;char board[ROW][COL] = { 0 };Initboard(board, ROW, COL);while (1){Displayboard(board, ROW, COL);Player_move(board, ROW, COL);Displayboard(board, ROW, COL);ret = Win(board, ROW, COL);if (ret != 'C')break;Player2_move(board, ROW, COL);ret = Win(board, ROW, COL);if (ret != 'C')break;}if (ret == '#'){printf("玩家2赢了\n");}else if (ret == '*'){printf("玩家1赢了\n");}else if (ret == 'F'){printf("平局\n");}
}
void Player2_move(char board[ROW][COL], int row, int col)
{int x = 0, y = 0;while (1){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("该位置已有棋子,重新输入\n");continue;}}else printf("输入错误,重新输入\n");}
}

这里很简单,我们只需要调用一个game2函数,再调用一个玩家2下子的函数后进行游戏即可。逻辑和单人游戏非常相似。

读者可以自行尝试优化代码,因为如果改变了行数和列数,即扩大棋盘,游戏的胜负判断函数和电脑的拦截函数将不可用。不过可以扩大棋盘后双人对战自行肉眼判断,甚至还能把棋盘扩的更大,来一盘快乐的五子棋~
(只是找下标可能是一个令人头疼的问题……)

C语言实现简易三子棋,支持双人对战,电脑可拦截相关推荐

  1. 【三子棋】C语言实现简易三子棋

    前两天新学了数组以及它的简单应用--三子棋,这里,便将它用博客的形式写出来,复习巩固的同时也希望能够帮到你们. 文章目录 一.项目要求 二.项目功能的实现 1.棋盘的初始化及打印 2.玩家下棋 3.电 ...

  2. 用c语言实现简易三子棋

    本篇适用于C语言初学者. 目录 完整代码: 分步介绍: 声明: 代码主体部分: 模块功能实现: 完整代码: #include<stdio.h> #include <stdlib.h& ...

  3. C语言,制作三子棋游戏

    三子棋游戏是一个很好地数组应用实例,在这篇博客中我将分享我在初学C语言时编写三子棋游戏的思路和过程. 1.模块设置 设置一个测试模块test.c和一个函数模块game.c,测试模块放置主函数,函数模块 ...

  4. 【牛客刷题】上手用C语言写一个三子棋小游戏超详解哦(电脑优化)

    作者:[南航科院小张 南航科院小张的博客 专栏:从c语言的入门到进阶 学习知识不只是要懂,还要会用:想要找到好的工作,这里给大家介绍一件可以斩获诸多大厂offer的利器–牛客网 点击免费注册和我一起开 ...

  5. java井字游戏_java井字棋源代码(双人对战版)

    [实例简介] [实例截图] [核心代码] package com.pan.ttt; import java.awt.*; import java.awt.event.*; import javax.s ...

  6. Scratch3.0——助力新进程序员理解程序(难度案例三、五子棋双人对战-电脑需要AI写不出来)

    Scratch3.0--助力新进程序员理解程序(难度案例三.五子棋双人对战-电脑需要AI写不出来) 前言 一般来说,针对6-18岁的少年儿童开展的编程教育,现在,最常见的形式是线上和线下模式相结合的课 ...

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

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

  8. c语言程序设计中三子棋游戏,C语言实现简易版三子棋游戏

    本文实例为大家共享了C语言实现三子棋游戏的详细代码,供大家参考,详细内容如下 什么是多文件? 多数大型的工程的头文件和源文件非常多,我们也不可能把所有的代码都写在同一个文件里,这样也不方便代码的阅读与 ...

  9. C语言一个小时实现简易三子棋,看看你能不能让愚蠢的电脑获胜,还不快上手试试吗(无AI算法)

    今天利用空余时间,便写一写三子棋的实现,可能很多人第一次看到这些东西,心里就会有一点害怕,可能会说:天呐,这得多难啊,我真的能写吗?那么回答是肯定的:能写,并且还很简单.那就让我们来看一看吧! 我们首 ...

最新文章

  1. 27个人类基因被重新命名,只因Excel总把它们自动纠正成日期
  2. getter方法的作用 vuex_Vuex入门篇——基本使用
  3. 当对项目强名时自动构建失败(TeamFoudationServer试用笔记)
  4. 四因素三水平正交试验表_软件测试|正交试验测试用例设计方法
  5. HGE2D引擎按键消息分析(续)
  6. [jQuery原理] jQuery基本结构
  7. sarscape 将dem文件转化成stl_STL文件,一种前处理网格划分技术??
  8. 当SQL Server爱上Linux:AVAILABILITY_MODE 和 DataGuard 的实践差距
  9. ae目标区域_中班区域活动目标
  10. 牛客网--蘑菇街2016研发工程师编程题
  11. 约瑟夫环问题(链表 + 公式)
  12. Cocos2d BMFont解析
  13. P1754 球迷购票问题 (卡特兰数,递推)
  14. Hadoop大数据开发技术
  15. 步进电机和伺服电机的区别
  16. Python数据预处理--Gensim构建语料词典
  17. 集店管家(App名称)技术服务支持
  18. Java将英文句子分解为单词
  19. 网上订餐python_网上订餐管理系统摘要.doc
  20. 解决360/google翻译不能用的问题

热门文章

  1. 启天m420进入不了bios_联想启天M420c装win7及BIOS设置教程(USB驱动可用)
  2. 计算机怎么按根号三的四次方,如何在excel中设置开4次方根号公式 | excle根号3公式...
  3. goahead实现文件下载功能实例详解
  4. 相关系数R-判定系数R方的matlab实现
  5. Linux Ubuntu下载
  6. 笔记 | gamma分布
  7. Ubuntu16.04安装GTX960闭源驱动(Dell XPS 9550)
  8. 《MySQL DBA:SSL连接》
  9. 移动端与PC端设计的几项要点
  10. BZOJ2876: [Noi2012]骑行川藏