当前位置:网站首页>轻松玩转三子棋
轻松玩转三子棋
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);
欢迎大家试玩!
边栏推荐
- Communication tutorial | overview of the first, second and third generation can bus
- [notes] in depth explanation of assets, resources and assetbundles
- When synchronized encounters this thing, there is a big hole, pay attention!
- Classification and application of AI chips
- [Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 13
- Source code analysis of the implementation mechanism of multisets in guava class library
- C语言数组
- Globalsign's SSL certificate products
- Global and Chinese market of piston rod 2022-2028: Research Report on technology, participants, trends, market size and share
- Memory computing integration: AI chip architecture in the post Moorish Era
猜你喜欢
16.内存使用与分段
Memory computing integration: AI chip architecture in the post Moorish Era
Complementary knowledge of auto encoder
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 6
TCP slicing and PSH understanding
DDS-YYDS
[solve the error of this pointing in the applet] SetData of undefined
How to use "bottom logic" to see the cards in the world?
How to judge the advantages and disadvantages of low code products in the market?
It's hard to hear C language? Why don't you take a look at this (V) pointer
随机推荐
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 20
Servlet learning notes
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 22
Iterm tab switching order
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
Introduction to random and threadlocalrandom analysis
Uva536 binary tree reconstruction tree recovery
Map container
Force buckle 142 Circular linked list II
Langue C: trouver le nombre de palindromes dont 100 - 999 est un multiple de 7
22 API design practices
How to judge the advantages and disadvantages of low code products in the market?
vim 出现 Another program may be editing the same file. If this is the case 的解决方法
Decrypt the advantages of low code and unlock efficient application development
First knowledge of spark - 7000 words +15 diagrams, and learn the basic knowledge of spark
Global and Chinese markets of NOx analyzers 2022-2028: Research Report on technology, participants, trends, market size and share
asp. Core is compatible with both JWT authentication and cookies authentication
R语言--readr包读写数据
03_ Armv8 instruction set introduction load and store instructions
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 24