目录

一,总体思路介绍

二,具体思路的实现

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语言三子棋游戏进阶版详解(包括多子棋)相关推荐

  1. 三子棋游戏(超级详解,附加电脑下棋优化)

    目录 前言 一,游戏规则 二,游戏步骤 三,游戏实现 3.1游戏构思和框架 3.2 棋盘的初始化和打印 3.3 玩家和电脑下棋的实现 3.4 判断输赢 3.5 游戏平局 3.6 游戏头文件game.h ...

  2. C语言—实现扫雷游戏(注释详解)

    文章目录 前言 一.游戏规则介绍 二.基本思路流程介绍 三.代码实现 1.用户交互菜单(Menu函数) 2. Game函数 3.放雷函数(SetMines函数) 4.扫雷展示面板(ShowBoard函 ...

  3. 动物棋c语言程序,斗兽棋游戏手机版|斗兽棋游戏下载 v0.2C 安卓版_最火软件站...

    斗兽棋android手机版,动物对战棋,回味童年的棋牌休闲游戏,登陆android手机,整个游戏画面是分为两块区域,中间有河流分割两块区域,有桥梁可以让彼此的动物过河,要取得胜利,必须占领那一边动物的 ...

  4. 关于三子棋游戏的简易实现与N子棋胜利判断方法

    关于三子棋游戏的简易实现与N子棋胜利判断方法 要实现三子棋游戏,主要需要实现以下几个要求:> 需要一个棋盘,既然需要一个棋盘,棋盘是在一个平面上的,所以我们需要创建一个二维数组 棋盘的打印 玩家 ...

  5. 区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-熊丽兵-专题视频课程...

    区块链技术进阶-深入详解以太坊智能合约语言 solidity(含源码)-103人已学习 课程介绍         区块链开发技术进阶-深入详解以太坊智能合约语言 solidity视频培训教程:本课程是 ...

  6. switch怎么一个账号绑定各种服务器,任天堂switch主副机器介绍,ns数字版游戏共享操作详解...

    原标题:任天堂switch主副机器介绍,ns数字版游戏共享操作详解 任天堂在日前推送了switch主机的6.0系统,其网络会员服务Switch Online也正式上线,值得一提的是此次更新引入了主副机 ...

  7. 《Android_3D游戏开发技术详解与典型案例》PDF版电子书下载

    点击下载: <Android_3D游戏开发技术详解与典型案例> 内容简介: <Android 3D游戏开发技术详解与典型案例(附盘)>,本书分为两篇共22章,第一篇以简单易懂的 ...

  8. Android 3D游戏开发技术详解与典型案例

    下载地址 <Android3D游戏开发技术详解与典型案例>主要以Android平台下3D游戏的开发为主题,并结合真实的案例向读者详细介绍了OpenGL ES的基础 知识及3D游戏程序开发的 ...

  9. 《Unity 3D 游戏开发技术详解与典型案例》——1.1节Unity 3D基础知识概览

    本节书摘来自异步社区<Unity 3D 游戏开发技术详解与典型案例>一书中的第1章,第1.1节Unity 3D基础知识概览,作者 吴亚峰 , 于复兴,更多章节内容可以访问云栖社区" ...

最新文章

  1. linux 查看某一个进程的socket连接数
  2. JAVA的三种常量池
  3. 分析数据时,一定要避开这5大误区!
  4. WebRTC 的 log 系统实现分析
  5. 210板wince键盘驱动分析和移植
  6. 基于nginx实现缓存功能及uptream模块详细使用方法
  7. mybatis mysql selectkey_Mybatis示例之SelectKey的应用
  8. 2.python中的矩阵、多维数组----numpy
  9. 吉林大学研究生课程-面向对象方法2020考试复习资料
  10. java学生成绩管理系统源码
  11. Alpha测试 / Beta测试 / 黑盒测试 /白盒测试概述
  12. ARM嵌入式核心板介绍
  13. [ Laravel 5.5 文档 ] 快速入门 —— 使用 Laragon 在 Windows 中搭建 Laravel 开发环境
  14. 电商平台--Mysql主从搭建(2)
  15. 基于树莓派的微型气象台
  16. JEECMS 自定义标签
  17. 一步一步来:MQTT服务器搭建、MQTT客户端使用
  18. 韩信点兵C语言实现的几种方法
  19. [Mysql] 多表连接查询
  20. 天梯赛真题L3-008: 喊山(BFS + 数据结构)

热门文章

  1. 最新信管/资管/博易大师软件源码+通达信配资/外汇模拟
  2. 看完这篇文章知道有什么英语录音翻译成中文的软件
  3. MacOS中不使用XQuartz/X11构建OpenGL程序的方法
  4. 输出Tecplot格式的数据文件
  5. javawebJAVAJSP客户关系管理系统jsp会员信息管理系统jsp客户管理系统jsp客户登记系统
  6. python人工智能入门零基础_零基础如何入门人工智能?
  7. 【Element】element-ui 进行表格数据的可修改及某一行可删除
  8. simplify-path
  9. 液晶屏MIPI接口与LVDS接口区别(总结)
  10. 节点网络计划图计算机,网络计划图教程