当前位置:网站首页>轻松玩转三子棋
轻松玩转三子棋
2022-07-04 12:33:00 【天黑再醒】
三子棋最终运行的界面:
三子棋的思路步骤:
首先建game.h,game.c和test.c
game.h 用来函数的声明
game.c 游戏的实现
test.c 测试游戏的逻辑
因为玩游戏,得让玩家有次体验感,这是就得用到do.....while的用法
先把主函数写出来:
int main()
{
test();
return 0;
}
再从test函数里嵌套:
上来就是do...while,游戏得有界面,可直接用printf打印
void menu()
{
printf("***************************\n");
printf("****** 1.play ***********\n");
printf("****** 0.exit ***********\n");
printf("***************************\n");
}
接着要进入,选项有多样,可以用switch语句选择,选择1就开始游戏,选择0就结束游戏,如果输入其他是数值,可以用default。
void test()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
单纯的这样运行会出现报错,,要在game.c,test.c中都得包含头文件:
#include"game.h"
为了棋盘的可玩性,如果想玩10×10或者5×5的,那board[3][3]就实现不了,可以借用全局变量来完成,在game.h中定义:
#define ROW 3 #define COL 3
第一步:初始化棋盘:
在test.c的game()函数中打出
InitBoard(board, ROW, COL);
其次在game.h中声明函数:
void InitBoard(char board[ROW][COL],int row,int col);
在game.c中编写棋盘初始化的函数,可以用for循环来写:
void InitBoard(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++) { board[i][j] = ' '; } } }
使棋盘上的数据为空格,这样打印出来只是空白,什么也看不了。这时候就就进行下一步,将棋盘的外形“打造”出来。
第二部打印棋盘:
在test.c中的game()函数里输入
Displayboard(board, ROW, COL);
在game.h中声明函数:
void Displayboard(char board[ROW][COL], int row, int col);
接着在game.c中写出函数
void Displayboard(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++) { 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"); } } }
为了确保棋盘是这种格式的
在for的内循环里把 空格%c空格( %c ) 看成一个整体这样的写是为了与下面的---相对应,达到一种匀称的感觉,接着打印竖杠(|)但内循环是j<col,就会导致每一行的最后面也有个竖杠(|),这时候用if语句来化解 if(j<col-1) ,打印完一行后,要换行printf("\n");打印---的时候也是同理,不过就是if (i < row - 1)了。
第三步:玩家下棋
在test.c源文件里的game()函数里输入:
player_move(board, ROW, COL);
接着在game.h中声明函数:
void player_move(char board[ROW][COL], int row, int col);
最后在game.c里写出函数:
void player_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("玩家下棋\n"); while (1) { printf("请输入坐标:"); scanf_s("%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"); } } else { printf("坐标不合法,请重新输入\n"); } } }
因为是为了让玩家体验游戏,设置2个变量,来供玩家输入,玩家不一定知道数组的下标是从0开始的,所以得
if (x >= 1 && x <=row && y >= 1 && y <=col)
现在编写的是3×3的,输入坐标的时候,横纵坐标都是从1到3,但数组的下标是从0到2,相差1,所以得
board[x - 1][y - 1]
因为是三子棋游戏,下棋前得确定所输入的坐标位置是不是空格,否则就会出现“悔棋”的现象,如果还是空格就可以
board[x - 1][y - 1] = '*';
然后break跳出,如果被占据,就else
else { printf("该坐标被占用,请重新输入\n"); }
这样就完事了吗???
不!不!不!
如果玩家输入的坐标不是或者超出范围,程序就无法运行,因此还要再次else
else { printf("坐标不合法,请重新输入\n"); }
第四步:电脑下棋
首先在test.c中的game()函数中输入:
Displayboard(board, ROW, COL);
接着在game.h中声明这个函数:
void computer_move(char board[ROW][COL], int row, int col);
最后在game.c中编写函数:
void computer_move(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("电脑下棋\n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] = ' ') { board[x][y] = '#'; break; } } }
因为是电脑下棋为了简单点,让电脑随机输入坐标。rand取余row得到的就是row-1。rand函数是给出随机值。srand函数的参数类型为无符号整型,它的作用是定义rand的起始部分,函数头文件stdlib.h。以时间戳函数time()的返回值作为参数可以增大随机度,函数头文件time.h。srand配合时间戳使用,只定义一次才可以保证随机度最大,于是我们放到主函数里面定义srand。所以在test函数里
srand((unsigned int)time(NULL));
在game.h里加入头文件
#include<stdlib.h> #include<time.h>
此时玩家和电脑下棋的函数编写出来,游戏就是有来有往,玩家下过,电脑下,电脑下过,玩家下.......往下循环下去,这时候应该在test.c源文件里用while循环来执行
while (1) { //玩家下棋 player_move(board, ROW, COL); Displayboard(board, ROW, COL); //电脑下棋 computer_move(board, ROW, COL);//随机下棋 Displayboard(board, ROW, COL); }
第五步:判断输赢
游戏是过程,最终得有个输赢,结果有:玩家赢,电脑赢,平局
然后输出结果,为了方便:
玩家赢 输出 *
电脑赢 输出 #
平局 输出 Q
如果还想接着玩就输出 C
在test.c中while的循环里进行变动,经过刚开始的博弈后,玩家再下一次的时候进行判断,判断玩家是否赢了,如果赢了就break跳出,输出 * ; 如果玩家没赢,电脑下一次,判断电脑是不是赢了,如果是电脑赢了,也是break跳出,输出 # 。如果最后下满了,都没赢输出 Q 。所以要写一个判断输赢的函数:
再test.c中game()函数里编写
ret=is_win(board,ROW,COL);
接着再game.h中声明函数:(因为输出的是字符,所以返回类型应该是char)
char is_win(char board[ROW][COL], int row, int col);
再game.c函数里编写函数:
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
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][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线
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];
}
//判断平局
if (if_full(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
为了判断输赢,三子棋游戏赢的情况无非三种:一行相同,一列相同,对角线相同
先看第一种:一行相同
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][1];
}
}
保证相邻的相同而且不是空格,这时候就是玩家赢,这时候要输出*了,但如果玩家不想用*玩,想用其他字符来代替,这个时候返回*就不成立了,但,我们可以返回相同行的其中的一个就可以。
接着第二种:一列相同
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
保证相邻的相同而且不是空格,这时候就是电脑赢,这时候要输出#了,但如果电脑也有小脾气哈,不想用#玩,想用其他字符来代替,这个时候返回#就不成立了,但,我们可以返回相同行的其中的一个就可以。
最后第三种:对角线相同
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];
}
对角线有两条,要写两个if语句,保证对角线相连的相同就可以。
还有平局的情况
if (if_full(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
则是判断棋盘上是不是不在是空格,这时候又得写一个函数来判断棋盘是不是下满了。因为要结束了,不想再麻烦,可以直接在game.c中编写函数,编写一个只属于它的情况,这时候可以用到局部变量static的用法
static int if_full(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] == ' ')
{
return 0; //没满
}
}
}
return 1; //满了
}
如果满了返回1,如果没满返回2,如果还想玩就返回C。
完整代码如下:
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
printf("***************************\n");
printf("****** 1.play ***********\n");
printf("****** 0.exit ***********\n");
printf("***************************\n");
}
void game()
{
char ret = 0;
//存放下棋的数据
char board[ROW][COL]={0};
//初始化棋盘为空格
InitBoard(board, ROW, COL);
//打印棋盘
Displayboard(board, ROW, COL);
while (1)
{
//玩家下棋
player_move(board, ROW, COL);
Displayboard(board, ROW, COL);
//判断输赢
ret=is_win(board,ROW,COL);
if (ret != 'C')
{
break;
}
//电脑下棋
computer_move(board, ROW, COL);//随机下棋
Displayboard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢了\n");
}
else if (ret == '#')
{
printf("电脑赢了\n");
}
else
{
printf("平局\n");
}
}
//结局
//玩家赢 *
//电脑赢 #
//平局 Q
//继续 C
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
void Displayboard(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++)
{
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("玩家下棋\n");
while (1)
{
printf("请输入坐标:");
scanf_s("%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");
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] = ' ')
{
board[x][y] = '#';
break;
}
}
}
static int if_full(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] == ' ')
{
return 0; //没满
}
}
}
return 1; //满了
}
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断行
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][1];
}
}
//判断列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线
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];
}
//判断平局
if (if_full(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
game.h:
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL],int row,int col);
//打印棋盘
void Displayboard(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);
欢迎大家试玩!
边栏推荐
- How to use "bottom logic" to see the cards in the world?
- The latest idea activation cracking tutorial, idea permanent activation code, the strongest in history
- [Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 7
- How do std:: function and function pointer assign values to each other
- 【数据聚类】第四章第一节3:DBSCAN性能分析、优缺点和参数选择方法
- Ultimate bug finding method - two points
- French Data Protection Agency: using Google Analytics or violating gdpr
- [Chongqing Guangdong education] National Open University spring 2019 2727 tax basis reference questions
- Bottom Logic -- Mind Map
- Clockwise rotation method of event arrangement -- PHP implementation
猜你喜欢
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 11
The database connection code determines whether the account password is correct, but the correct account password always jumps to the failure page with wrong account password
Star leap plan | new projects are continuously being recruited! MSR Asia MSR Redmond joint research program invites you to apply!
Azure solution: how can third-party tools call azure blob storage to store data?
The detailed installation process of Ninja security penetration system (Ninjitsu OS V3). Both old and new VM versions can be installed through personal testing, with download sources
The frost peel off the purple dragon scale, and the xiariba people will talk about database SQL optimization and the principle of indexing (primary / secondary / clustered / non clustered)
Btrace tells you how to debug online without restarting the JVM
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 16
Practical dry goods: deploy mini version message queue based on redis6.0
Leetcode: 408 sliding window median
随机推荐
[ES6] template string: `string`, a new symbol in es2015
Guava ImmutableSet. Builder source code analysis, shift original code, complement code, reverse code review
Entitas learning [iv] other common knowledge points
C语言:求100-999是7的倍数的回文数
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 5
IIS error, unable to start debugging on the webserver
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 7
Recommend a cool geospatial data visualization tool with low code
Review of week 278 of leetcode II
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 18
The database connection code determines whether the account password is correct, but the correct account password always jumps to the failure page with wrong account password
Global and Chinese market for naval vessel maintenance 2022-2028: Research Report on technology, participants, trends, market size and share
Googgle guava ImmutableCollections
03_ Armv8 instruction set introduction load and store instructions
Method of setting default items in C # ComboBox control code
BCD code Baidu Encyclopedia
Realize cross tenant Vnet connection through azure virtual Wan
priority_ queue
Cadence physical library lef file syntax learning [continuous update]
The detailed installation process of Ninja security penetration system (Ninjitsu OS V3). Both old and new VM versions can be installed through personal testing, with download sources