当前位置:网站首页>轻松玩转三子棋
轻松玩转三子棋
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);
欢迎大家试玩!
边栏推荐
- When synchronized encounters this thing, there is a big hole, pay attention!
- Realize cross tenant Vnet connection through azure virtual Wan
- vim 出现 Another program may be editing the same file. If this is the case 的解决方法
- Lecture 9
- Ml and NLP are still developing rapidly in 2021. Deepmind scientists recently summarized 15 bright research directions in the past year. Come and see which direction is suitable for your new pit
- Force buckle 142 Circular linked list II
- 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
- Review of week 278 of leetcode II
- Servlet learning notes
- ASP. Net razor – introduction to VB loops and arrays
猜你喜欢
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 15
Ultimate bug finding method - two points
13、 C window form technology and basic controls (3)
DDS-YYDS
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 19
22 API design practices
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 7
记一次 Showing Recent Errors Only Command /bin/sh failed with exit code 1 问题
Practice of retro SOAP Protocol
How to realize the function of Sub Ledger of applet?
随机推荐
R语言--readr包读写数据
Uva536 binary tree reconstruction tree recovery
IIS error, unable to start debugging on the webserver
Complementary knowledge of auto encoder
[notes] in depth explanation of assets, resources and assetbundles
Possible to restore a backup of SQL Server 2014 on SQL Server 2012?
Introduction to random and threadlocalrandom analysis
Openssl3.0 learning 20 provider KDF
Communication tutorial | overview of the first, second and third generation can bus
C语言:求100-999是7的倍数的回文数
When synchronized encounters this thing, there is a big hole, pay attention!
C语言:围圈报号排序问题
VBA, JSON interpretation, table structure -json string conversion
Iterm tab switching order
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)
Anti clockwise rotation method of event arrangement -- PHP implementation
Global and Chinese market of ice water machines 2022-2028: Research Report on technology, participants, trends, market size and share
Flet教程之 02 ElevatedButton高级功能(教程含源码)(教程含源码)
ASP. Net razor – introduction to VB loops and arrays
Entity framework calls Max on null on records - Entity Framework calling Max on null on records