C语言三子棋,五子棋,n子棋的代码实现

news/2024/10/20 11:32:46/

C语言三子棋,五子棋,n子棋的代码实现

  • 这里以五子棋为例,来说明开发过程
  • 开发思路
  • 菜单打印
  • 棋盘的打印
  • 棋子的打印
  • 电脑下棋(随机数)
  • 判断输赢
  • 代码整合
  • 注意事项

在这里插入图片描述

这里以五子棋为例,来说明开发过程

其中该项目包含3个文件,一个.h文件声明所用的函数,两个.c文件进行主要的代码书写。
在这里插入图片描述

项目效果展示:
在这里插入图片描述
在这里插入图片描述

开发思路

  • 菜单打印
  • 棋盘的打印(二维数组)
  • 棋子打印(下标)
  • 电脑下棋(随机数)
  • 判断输赢(竖,横,左斜,右斜…)

大致的思路就是这些,看过开发思路,脑海里应该就大致有了想法,有了主意。
接着,我们一步一步的进行开发。

菜单打印

菜单我们可以设计简单一些,同时把其放在一个函数中,这样便于调用。
该函数如下所示:

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

这里我们要不断的接收用户的输入,当为1时,进入游戏,为0时,退出程序
直接就想到了 条件语句判断,这里我们用switch

不断的:用户完成游戏后,可以再次打印菜单供用户选择

这个操作当然是项目的核心部分了,放在 main()函数里

int main()
{srand((unsigned int)time(NULL));// 设置随机数的生成起点(利用时间)  后面会讲随机数的使用int input = 0;do{menu();//打印菜单printf("请选择->\n");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("输入错误!!!\n");break;}} while (input);return 0;
}

棋盘的打印

我们是利用二维数组打印棋盘,观察效果展示后可以发现,打印棋子的地方上 空格,然后用 “|”和“_” 装饰地图

首先打印出空格,为了便于控制棋盘行列数量,我们直接定义一个变量,之后对其进行赋值操作。
row col

void Initboard(char board[Row][Col], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
}

同时在 game.h头文件中声明其函数,并定义变量的值

#pragma once#include <stdio.h>
#define Row 10
#define Col 10// 初始化棋盘
void Initboard(char board[Row][Col], int row, int col);
// 打印棋盘
void displayboard(char board[Row][Col], int row, int col);

最后,对棋盘进行装饰

void displayboard(char board[Row][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){// 打印数据//printf(" %c | %c | %c | %c | %c \n", //board[i][0], board[i][1]......board[i][4]);int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");// 打印分割信息//printf("---|---|---|---|---\n");if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}printf("\n");}}
}

棋子的打印

棋子的打印分为两部分:
1.玩家输入棋子坐标进行下棋
2.电脑根据随机数进行下棋

首先,进行玩家下棋
思路:
让用户输入二维数组下标进行判断
如果是空格,就可以用一个字符代替棋子进行占用。
若不为空格,则说明该位置上有棋子,则让玩家重新输入坐标

void paly_move(char board[Row][Col], int row, int col)
{// 玩家输入其坐标int x = 0, y = 0;printf("请玩家输入坐标(例如:1 1):\n");while (1){printf("请输入坐标->\n");scanf("%d %d", &x, &y);// 坐标的合法性判断  1.范围  2.是否被占用if (x >= 1 && x <= row && y >= 1 && y <= col){// 玩家输入的1 1 ,在二维数组中对应的为0 0// 二维数组坐标从0开始if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("坐标已被占用,不能下棋,请选择其他位置\n");}}else{printf("坐标非法,请重新输入->\n");}}
}

电脑下棋(随机数)

思路:
电脑下棋就是产生随机数–>随机坐标下棋
然后,判断该位置是否有棋子,若无则打印,若有则再次随机产生

随机数
利用srand()time()函数
用法如下:

	#include <time.h>srand((unsigned int)time(NULL));

unsigned int 可以理解为自然数

这里是利用变化的时间作为种子,来进行产生随机数(:如果调用的间隙过短,则是产生相同的值)
对应rand()的随机数范围是0~32767

void computer_move(char board[Row][Col], int row, int col)
{printf("电脑下棋->\n");int x = 0, y = 0;// 判断并下棋while (1){// 利用随机数       返回test.c设置随机数的起点x = rand() % row;// rand()的随机数范围是0~32767 模上row(5) 就是0~5y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}

判断输赢

在循环下棋中,每次都去进行判断,所以有四种情况
我们可以 让其返回的值不同,然后就可以直接对返回值进行判断,进而判断输赢

  • 玩家赢 (返回值):*

  • 电脑赢 #

  • 平局 Q

  • 继续下棋 C

定义一个函数,判断棋盘是否满子
满子返回 1
未满返回 0

int full_board(char board[Row][Col], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;
}

判断:

char who_win(char board[Row][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){// 行if (board[i][j] == board[i][j+1] && board[i][j+1] == board[i][j+2] && board[i][j+2] == board[i][j+3] && board[i][j+3] == board[i][j+4] && board[i][j+3] != ' '){return board[i][j+2];}// 列if (board[i][j] == board[i+1][j] && board[i+1][j] == board[i+2][j] && board[i+2][j] == board[i+3][j] && board[i+3][j] == board[i+4][j] && board[i+4][j] != ' '){return board[i+1][j];}// 右斜if(board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4] && board[i + 3][j + 3] != ' '){return board[i + 2][j + 2];}// 左斜if (board[i][j + 4] == board[i + 1][j + 3] && board[i + 1][j + 3] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 1] && board[i + 3][j + 1] == board[i + 4][j] && board[i + 2][j + 2] != ' '){return board[i][j + 4];}}}// 棋盘满了,未分出胜负if (full_board(board, row, col)){return 'Q';}// 游戏继续return 'C';
}

到这里,整个项目的核心代码我们都已经分解好了,现在只剩下去整合了
我这里就直接上完整代码了

代码整合

test.c

# define _CRT_SECURE_NO_WARNINGS
#include "game.h"
#include <time.h>void menu()
{printf("*********************\n");printf("*** 1.play 0.exit ***\n");printf("*********************\n");
}
void game()
{char ret;char board[Row][Col] = { 0 };//初始化棋盘Initboard(board, Row, Col);displayboard(board, Row, Col);//下棋while (1){//玩家paly_move(board,Row, Col);//判断输赢ret = who_win(board, Row, Col);if (ret != 'C'){break;}//     打印棋盘displayboard(board, Row, Col);//电脑computer_move(board, Row, Col);ret = who_win(board, Row, Col);if (ret != 'C'){break;}//      打印棋盘displayboard(board, Row, Col);}if (ret == '*'){printf("玩家赢\n");}else if (ret == '#'){printf("电脑赢\n");}else{printf("平局\n");}
}
int main()
{srand((unsigned int)time(NULL));// 设置随机数的生成起点(利用时间)int input = 0;do{menu();//打印菜单printf("请选择->\n");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("退出游戏\n");break;default:printf("输入错误!!!\n");break;}} while (input);return 0;
}

game.h

#pragma once#include <stdio.h>
#define Row 10
#define Col 10// 初始化棋盘
void Initboard(char board[Row][Col], int row, int col);// 打印棋盘
void displayboard(char board[Row][Col], int row, int col);// 玩家下棋
void paly_move(char board[Row][Col], int row, int col);// 电脑下棋
// 找个空白的地方下棋
void computer_move(char board[Row][Col], int row, int col);// 判断棋盘形式
// 可以设置其对应的返回值,便于判断,以及继续执行程序
// 玩家赢    电脑赢     平局    继续下棋        (四种情况)
//  *          #          Q       C           字符char who_win(char board[Row][Col], int row, int col);

game.c

# define _CRT_SECURE_NO_WARNINGS#include "game.h"void Initboard(char board[Row][Col], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';}}
}void displayboard(char board[Row][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){// 打印数据//printf(" %c | %c | %c | %c | %c \n", board[i][0], board[i][1]......board[i][4]);int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1){printf("|");}}printf("\n");// 打印分割信息//printf("---|---|---|---|---\n");if (i < row - 1){int j = 0;for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}printf("\n");}}
}void paly_move(char board[Row][Col], int row, int col)
{// 玩家输入其坐标int x = 0, y = 0;printf("请玩家输入坐标(例如:1 1):\n");while (1){printf("请输入坐标->\n");scanf("%d %d", &x, &y);// 坐标的合法性判断  1.范围  2.是否被占用if (x >= 1 && x <= row && y >= 1 && y <= col){// 玩家输入的1 1 ,在二维数组中对应的为0 0// 二维数组坐标从0开始if (board[x - 1][y - 1] == ' '){board[x - 1][y - 1] = '*';break;}else{printf("坐标已被占用,不能下棋,请选择其他位置\n");}}else{printf("坐标非法,请重新输入->\n");}}
}void computer_move(char board[Row][Col], int row, int col)
{printf("电脑下棋->\n");int x = 0, y = 0;// 判断并下棋while (1){// 利用随机数       返回test.c设置随机数的起点x = rand() % row;// rand()的随机数范围是0~32767 模上row(5) 就是0~5y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}}
// 定义一个函数,判断棋盘是否满子
// 满子返回 1
// 未满返回 0
int full_board(char board[Row][Col], int row, int col)
{int i = 0, j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;
}char who_win(char board[Row][Col], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){// 行if (board[i][j] == board[i][j+1] && board[i][j+1] == board[i][j+2] && board[i][j+2] == board[i][j+3] && board[i][j+3] == board[i][j+4] && board[i][j+3] != ' '){return board[i][j+2];}// 列if (board[i][j] == board[i+1][j] && board[i+1][j] == board[i+2][j] && board[i+2][j] == board[i+3][j] && board[i+3][j] == board[i+4][j] && board[i+4][j] != ' '){return board[i+1][j];}// 右斜if(board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4] && board[i + 3][j + 3] != ' '){return board[i + 2][j + 2];}// 左斜if (board[i][j + 4] == board[i + 1][j + 3] && board[i + 1][j + 3] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 1] && board[i + 3][j + 1] == board[i + 4][j] && board[i + 2][j + 2] != ' '){return board[i][j + 4];}}}// 棋盘满了,未分出胜负if (full_board(board, row, col)){return 'Q';}// 游戏继续return 'C';
}

注意事项

整个项目中只能有 一个main()函数和#include <stdio.h>
这里,我把 stdio.h 头文件放在game.h
之后再去调用game.h头文件,stdio.h 头文件也是包含其中的

我们可以控制row,col 的值改变棋盘的大小

在判断输赢里,修改判断语句可以修改为三子棋等等


http://www.ppmy.cn/news/96588.html

相关文章

Vue3的组件通信汇总

目录 自定义属性props&#xff08;父向子&#xff09; 自定义事件&#xff08;子向父&#xff09; ref获取子组件实例 $parent获取父组件实例 作用域插槽向父组件传值 兄弟组件传值 父子双向数据绑定 useAttrs获取父组件传来的属性和事件 深层组件传值 Pinia实现任意…

ChatGPT桌面客户端支持gpt4模型,附使用说明

#软件核心功能&#xff1a; 1、支持OpenAI官方秘钥及API2D双秘钥使用&#xff1b;如果全局魔法&#xff0c;可以自己用官方秘钥&#xff1b;没魔法国内可直接使用API2D秘钥&#xff1b; 2、内置GPT4模型选项&#xff0c;如果你的官方秘钥支持可直接使用&#xff1b;你也可以注册…

【JavaScript】文件分片上传

文章目录 普通文件上传分片上传整体流程技术点分析文件选择方式隐藏input框&#xff0c;自定义trigger拖拽上传 分片动态分片 计算哈希workerrequestIdleCallback抽样 请求并发控制进度展示手动中止/暂停 合并流式并发合并 反思分片命名问题并发控制代码实现的问题 参考文献 普…

驱动开发:内核实现进程汇编与反汇编

在笔者上一篇文章《驱动开发&#xff1a;内核MDL读写进程内存》简单介绍了如何通过MDL映射的方式实现进程读写操作&#xff0c;本章将通过如上案例实现远程进程反汇编功能&#xff0c;此类功能也是ARK工具中最常见的功能之一&#xff0c;通常此类功能的实现分为两部分&#xff…

Solidity基础八

别慌&#xff0c;月亮也在大海某处迷茫 目录 一、Solidity 编程风格 1. 代码布局 2. 代码中各部分的顺序 3. 命名约定 二、Solidity 智能合约编写过程 1. solidity Hello World 2. 版本声明 3. 导入声明 4. 合约声明 三、Solidity 合约结构 智能合约 Test 四、So…

Android 12.0状态栏居中显示时间和修改时间显示样式

1.概述 在12.0的系统rom定制化开发中,在systemui状态栏系统时间默认显示在左边和通知显示在一起,但是客户想修改显示位置,想显示在中间,所以就要修改SystemUI 的Clock.java 文件这个就是管理显示时间的,居中显示的话就得修改布局文件了 效果图如下: 在这里插入图片描述 …

谁能真正替代你?AI辅助编码工具深度对比(chatGPT/Copilot/Cursor/New Bing)

写在开头 这几个月AI相关新闻的火爆程度大家都已经看见了&#xff0c;作为一个被裹挟在AI时代浪潮中的程序员&#xff0c;在这几个月里我也是异常兴奋和焦虑。甚至都兴奋的不想拖更了。不仅仅兴奋于AI对于我们生产力的全面提升&#xff0c;也焦虑于Copilot等AI辅助编码工具&am…

android MutableLiveData与AndroidViewModel避坑小提示,Java

android MutableLiveData与AndroidViewModel避坑小提示&#xff0c;Java import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LifecycleOwner; import androidx.l…