C语言三子棋游戏进阶版详解(包括多子棋)
目录
一,总体思路介绍
二,具体思路的实现
1.初始化游戏界面
2.初始化棋盘
3.打印棋盘
4.玩家移动
5.电脑移动
6.判断输赢
三,源码展示
game.h
game.c
test.c
一,总体思路介绍
对于三子棋相信大家都不陌生,今天我们来用c语言完成三子棋的进阶版也就是多子棋游戏的实现。我的思路主要由六步构成,首先是完成选择进行游戏的初始化界面,选择玩三子棋游戏后,我们想既然要玩棋盘类游戏,那肯定就需要有一个棋盘在,所以就有了第二步初始化棋盘。但是棋盘初始化后,是要展示在玩家面前的,于是为了展示棋盘好方便下棋,就有了第三步打印棋盘。在棋盘展示在玩家面前之后,玩家要开始下棋,输入相应的坐标,于是就有了第四步玩家移动。玩家移动完之后需要第五步电脑移动,就这样双方来回移动。但是就这样双来回的移动这个游戏就未免显得太无聊了,所以也就需要在双方每次移动之后,系统需要判断游戏的结果。这也就到了第六步判断输赢环节。
二,具体思路的实现
1.初始化游戏界面
我们可以先打印出一个选择菜单由玩家选择是否进行游戏,输入的内容进入swich case语句中进行判断并执行,分为三种“开始游戏”,“退出游戏”,“选择错误重新选择”。为防止玩家玩的不够尽兴,需要在整个语句外加上循环语句。以下是具体代码:
void menu()
{printf("**************\n");printf("****1.play****\n");printf("****0.exit****\n");printf("**************\n");}
int main()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择》");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误请重新选择》\n");break;}} while (input);return 0;}
2.初始化棋盘
在开始游戏后需要初始化棋盘,既然是个棋盘就会有x,y两个坐标。这就可以构造一个二维数组board[][]来存放这些坐标,而为了以后方便更改棋盘的大小,二维数组的行和列坐标,不能直接用常数作为参数放入,而是在头文件中用#define定义标识符常量ROW,COL,然后将两者放入二维数组的行和列坐标中。
#define ROW 5
#define COL 5char board[ROW][COL] = { 0 };
在创建完二位数组之后,将该数组传入初始化函数中进行初始化,初始化的目的是为了打印出来更加直观,因此要将数组的每一个元素初始化为空格。如下:
int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
3.打印棋盘
为了打印出上图所示的棋盘,我们需要将数组传入打印函数中进行打印。我选择的是一行一行的打印,而每一行又可分为两小行,第一行是由多个“ board[i][j] |”符号组成,要注意在打印该行中最后一个该符号时,“|”符号不需要打印。第二行是由多个“---|”符号组成,也要注意的是打印该行中最后一个该符号时,“|”符号不需要打印。我们一行一行的打印相同的符号,当我们打印到最后一行时,最后一行的第二小行不需要打印。通过两层循环嵌套使用便可以完整的打印出整个棋盘。要注意每行的最后一列和每列的最后一行都不需要打印。代码如下:
int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){printf(" %c ",board[i][j]);if(j<col-1)printf("|");}printf("\n");if (i < row - 1){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
4.玩家移动
玩家移动是通过输入坐标到相应的棋盘位置上标记为玩家下的棋“*”,首先是玩家坐标的合法性,必须在数组的行和列坐标范围内,然后由于玩家不一定知道数组下标从0开始,因此每次将玩家输入的坐标对应到相应的数组坐标时都要减1。如果玩家输入的坐标对应的位置是“ ”,说明该位置还没有被占用,该位置可以标记为玩家下的棋,否则需要玩家重新输入。代码如下:
int x = 0;int y = 0;printf("请输入坐标》");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;}elseprintf("该坐标已被占用,请重新输入!\n");}elseprintf("坐标错误,请重新输入!\n");}
5.电脑移动
、电脑的移动需要产生随机数坐标,为了产生随机数需要在主函数中调用srand()函数和time()函数,以及引相应的头文件。
#include<stdlib.h>
#include<time.h>
srand((unsigned int)time(NULL));
x = rand() % row;
y = rand() % col;
产生随机数坐标后要通过运算使x,y坐标在,数组行和列范围内。然后再判断该坐标对应位置是不是已被其他标记占用,如果没有则电脑用符号“#”标记此处,如果有则电脑再循环产生一组随机数坐标继续判断,直到找到没有被标记占用的位置。代码如下:
int x = 0;int y = 0;while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
6.判断输赢
这是整个游戏实现的最重要的一步。在玩家和电脑来回下棋的过程中,会出现输赢。再每次玩家移动或者电脑移动后,都会打印棋盘,然后再判断输赢。那我们该如何判断每次移动后的输赢呢?我们可以创建一个判断输赢的函数is_win(),并创建一个变量ret来接收其返回值,不同返回值对应不同的游戏结果:
char ret = 0;ret = is_win(board, ROW, COL);
//is_win='c'表示继续//is_win='*'表示玩家赢//is_win='#'表示电脑赢//is_win='f'表示平局
要注意每次玩家或电脑移动后都需要打印一次棋盘,并判断一次输赢。在整个电脑和玩家下棋的循环过程的最前面,可以加一个清理屏幕的命令。代码如下:
while (1){system("cls");print(board, ROW, COL);//棋盘打印printf("玩家移动\n");player_move(board, ROW, COL);//玩家移动print(board, ROW, COL);//棋盘打印ret = is_win(board, ROW, COL);if (ret != 'c')break;printf("电脑移动\n");computer_move(board, ROW, COL);//电脑移动print(board, ROW, COL);//棋盘打印ret = is_win(board, ROW, COL);if (ret!='c')break;}if (ret =='*')printf("玩家赢!\n");if (ret == '#')printf("电脑赢!\n");if (ret== 'f')printf("平局!\n");print(board, ROW, COL);//棋盘打印
接着就是该函数的实现了:
1.首先是对每行进行判断,创建一个变量count,每行中的每一列中不同的数组元素对应着不同的count的变化,当遍历完每一行中的所有元素后,对count的值进行判断,如果count的值等于COL,那么说明该行所有元素相等都为“*”或“#”,然后返回该元素。否则将count置0继续遍历下一行的所有元素,直到遍历完所有行。
for (i = 0; i < row; i++){count = 0;for (j = 0; j < col; j++){if (board[i][j] == '*'){count++;}if (board[i][j] == '#'){count--;}}if (count == col || count == -col){return board[i][j-1];}}
2.然后是列判断,与上述行判断类似,创建变量count,每列中的每一行中不同的数组元素对应着不同的count变化,当遍历完每一行中的所有元素后,对count的值进行判断,如果count的值等于ROW,那么说明该列所有元素相等都为“*”或“#”,然后返回该元素。否则将count置0继续遍历下一列的所有元素,直到遍历完所有列。
for (j = 0; j < col; j++){count = 0;for (i = 0; i < row; i++){if (board[i][j] == '*'){count++;}if (board[i][j] == '#'){count--;}}if (count == col || count == -col){return board[i - 1][j];}}
3.接着是主对角线判断
仍然需要变量count,只需遍历一遍数组主对角线上的元素,不同的元素对应着count的变化。如果count等于ROW或COL,那么说明主对角线上所有元素相等都为“*”或“#”,然后返回该元素。否则进行下一个判断。代码如下:
count = 0;for (i = 0; i < row; i++){if (board[i][i] == '*'){count++;}if (board[i][i] == '#'){count--;}}if (count == col || count == -col){return board[i][i];}
4.副对角线判断
与上述主对角线相似,仍然需要变量count,只需遍历一遍数组副主对角线上的元素,不同的元素对应着count的变化。如果count等于ROW或COL,那么说明主对角线上所有元素相等都为“*”或“#”,然后返回该元素。否则进行下一个判断。代码如下:
count = 0;for (i = 0; i < row; i++){if (board[i][col - i - 1] == '*'){count++;}if (board[i][col - i - 1] == '#'){count--;}}if (count == col || count == -col){return board[i][col - i - 1];}
5.平局判断
在is_win()函数中嵌套调用函数is_full(),如果判断是平局is_full()返回1,否则返回0.其返回值可以创建变量ret来接收。如果ret等于1,则返回“f”,否则结束该判断。重点是is_full()函数的实现:在该函数中我们需要遍历数组中的所有元素,只要有元素为“ ”,说明该数组还有位置没有被标记,该函数直接返回0;如果遍历完所有元素都没有找到“ ”,说明该数组所有位置都被标记了,该函数返回1.代码如下:
int is_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;
}
int ret = 0;
ret = is_full(board, ROW, COL);
if (ret == 1){return 'f';}
6.如果上述任何一种判断都没有返回值,则返回“c”,说明游戏继续。
return 'c';
三,源码展示
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 5
#define COL 5void init(char board[ROW][COL], int row, int col);
void print(char board[ROW][COL], int row, int col);
void player_move(char board[ROW][COL], int row, int col);
void computer_move(char board[ROW][COL], int row ,int col);
char is_win(char board[ROW][COL], int row, int col);
game.c
#include"game.h"
void init( 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 print(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++){printf(" %c ",board[i][j]);if(j<col-1)printf("|");}printf("\n");if (i < row - 1){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}
void player_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("请输入坐标》");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;}elseprintf("该坐标已被占用,请重新输入!\n");}elseprintf("坐标错误,请重新输入!\n");}}
void computer_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;while (1){x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}
int is_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 is_win(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;int ret = 0;int count = 0;ret = is_full(board, ROW, COL);//三子棋游戏判断//for (i = 0; i < row; i++)//{// // if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')// return board[i][0];//}//for (j = 0; j < col; j++)//{// if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')// return board[0][j];//}//if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')// return board[1][1];//if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')// return board[1][1];//多子棋游戏判断for (i = 0; i < row; i++){count = 0;for (j = 0; j < col; j++){if (board[i][j] == '*'){count++;}if (board[i][j] == '#'){count--;}}if (count == col || count == -col){return board[i][j-1];}}for (j = 0; j < col; j++){count = 0;for (i = 0; i < row; i++){if (board[i][j] == '*'){count++;}if (board[i][j] == '#'){count--;}}if (count == col || count == -col){return board[i - 1][j];}}count = 0;for (i = 0; i < row; i++){if (board[i][i] == '*'){count++;}if (board[i][i] == '#'){count--;}}if (count == col || count == -col){return board[i][i];}count = 0;for (i = 0; i < row; i++){if (board[i][col - i - 1] == '*'){count++;}if (board[i][col - i - 1] == '#'){count--;}}if (count == col || count == -col){return board[i][col - i - 1];}if (ret == 1){return 'f';}return 'c';}
test.c
#include"game.h"
void menu()
{printf("**************\n");printf("****1.play****\n");printf("****0.exit****\n");printf("**************\n");}
void game()
{char board[ROW][COL] = { 0 };char ret = 0;init(board, ROW, COL);//棋盘初始化print(board, ROW, COL);//棋盘打印while (1){system("cls");print(board, ROW, COL);//棋盘打印printf("玩家移动\n");player_move(board, ROW, COL);//玩家移动print(board, ROW, COL);//棋盘打印ret = is_win(board, ROW, COL);if (ret != 'c')break;printf("电脑移动\n");computer_move(board, ROW, COL);//电脑移动print(board, ROW, COL);//棋盘打印ret = is_win(board, ROW, COL);if (ret!='c')break;}if (ret =='*')printf("玩家赢!\n");if (ret == '#')printf("电脑赢!\n");if (ret== 'f')printf("平局!\n");print(board, ROW, COL);//棋盘打印//is_win='c'表示继续//is_win='*'表示玩家赢//is_win='#'表示电脑赢//is_win='f'表示平局}
int main()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择》");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("选择错误请重新选择》\n");break;}} while (input);return 0;}
C语言三子棋游戏进阶版详解(包括多子棋)相关推荐
- 三子棋游戏(超级详解,附加电脑下棋优化)
目录 前言 一,游戏规则 二,游戏步骤 三,游戏实现 3.1游戏构思和框架 3.2 棋盘的初始化和打印 3.3 玩家和电脑下棋的实现 3.4 判断输赢 3.5 游戏平局 3.6 游戏头文件game.h ...
- C语言—实现扫雷游戏(注释详解)
文章目录 前言 一.游戏规则介绍 二.基本思路流程介绍 三.代码实现 1.用户交互菜单(Menu函数) 2. Game函数 3.放雷函数(SetMines函数) 4.扫雷展示面板(ShowBoard函 ...
- 动物棋c语言程序,斗兽棋游戏手机版|斗兽棋游戏下载 v0.2C 安卓版_最火软件站...
斗兽棋android手机版,动物对战棋,回味童年的棋牌休闲游戏,登陆android手机,整个游戏画面是分为两块区域,中间有河流分割两块区域,有桥梁可以让彼此的动物过河,要取得胜利,必须占领那一边动物的 ...
- 关于三子棋游戏的简易实现与N子棋胜利判断方法
关于三子棋游戏的简易实现与N子棋胜利判断方法 要实现三子棋游戏,主要需要实现以下几个要求:> 需要一个棋盘,既然需要一个棋盘,棋盘是在一个平面上的,所以我们需要创建一个二维数组 棋盘的打印 玩家 ...
- 区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-熊丽兵-专题视频课程...
区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-103人已学习 课程介绍 区块链开发技术进阶-深入详解以太坊智能合约语言 solidity视频培训教程:本课程是 ...
- switch怎么一个账号绑定各种服务器,任天堂switch主副机器介绍,ns数字版游戏共享操作详解...
原标题:任天堂switch主副机器介绍,ns数字版游戏共享操作详解 任天堂在日前推送了switch主机的6.0系统,其网络会员服务Switch Online也正式上线,值得一提的是此次更新引入了主副机 ...
- 《Android_3D游戏开发技术详解与典型案例》PDF版电子书下载
点击下载: <Android_3D游戏开发技术详解与典型案例> 内容简介: <Android 3D游戏开发技术详解与典型案例(附盘)>,本书分为两篇共22章,第一篇以简单易懂的 ...
- Android 3D游戏开发技术详解与典型案例
下载地址 <Android3D游戏开发技术详解与典型案例>主要以Android平台下3D游戏的开发为主题,并结合真实的案例向读者详细介绍了OpenGL ES的基础 知识及3D游戏程序开发的 ...
- 《Unity 3D 游戏开发技术详解与典型案例》——1.1节Unity 3D基础知识概览
本节书摘来自异步社区<Unity 3D 游戏开发技术详解与典型案例>一书中的第1章,第1.1节Unity 3D基础知识概览,作者 吴亚峰 , 于复兴,更多章节内容可以访问云栖社区" ...
最新文章
- linux 查看某一个进程的socket连接数
- JAVA的三种常量池
- 分析数据时,一定要避开这5大误区!
- WebRTC 的 log 系统实现分析
- 210板wince键盘驱动分析和移植
- 基于nginx实现缓存功能及uptream模块详细使用方法
- mybatis mysql selectkey_Mybatis示例之SelectKey的应用
- 2.python中的矩阵、多维数组----numpy
- 吉林大学研究生课程-面向对象方法2020考试复习资料
- java学生成绩管理系统源码
- Alpha测试 / Beta测试 / 黑盒测试 /白盒测试概述
- ARM嵌入式核心板介绍
- [ Laravel 5.5 文档 ] 快速入门 —— 使用 Laragon 在 Windows 中搭建 Laravel 开发环境
- 电商平台--Mysql主从搭建(2)
- 基于树莓派的微型气象台
- JEECMS 自定义标签
- 一步一步来:MQTT服务器搭建、MQTT客户端使用
- 韩信点兵C语言实现的几种方法
- [Mysql] 多表连接查询
- 天梯赛真题L3-008: 喊山(BFS + 数据结构)
热门文章
- 最新信管/资管/博易大师软件源码+通达信配资/外汇模拟
- 看完这篇文章知道有什么英语录音翻译成中文的软件
- MacOS中不使用XQuartz/X11构建OpenGL程序的方法
- 输出Tecplot格式的数据文件
- javawebJAVAJSP客户关系管理系统jsp会员信息管理系统jsp客户管理系统jsp客户登记系统
- python人工智能入门零基础_零基础如何入门人工智能?
- 【Element】element-ui 进行表格数据的可修改及某一行可删除
- simplify-path
- 液晶屏MIPI接口与LVDS接口区别(总结)
- 节点网络计划图计算机,网络计划图教程