我可能写的有些啰嗦,见谅,但我会很详细的讲解每一个步骤。
1,游戏需要菜单
2,需要选项(进入游戏或退出)
3,三子棋需要一个3*3的棋盘
4,需要将棋盘表现(打印出来)
5,玩家要开始下棋(输入坐标)
6,每次落子后都要判断输赢或平局
7,打印目前棋盘的状况
8,电脑开始落子
9,每次落子后都要判断输赢或平局
10,打印目前棋盘的状况
11.判断游戏目前的局面(输或赢,继续落子或者平局)
由于,代码量过大,并且各个函数的设计及作用。并且考虑N子棋的可能。我们需要分模块,分文件来写。
游戏菜单-进入游戏或者退出—分支语句(switch)
还要打印游戏菜单,使用函数。
为了多次play游戏,也包括多次选项输入,考虑do{}while();循环,可以至少进入一次循环。
void option(int input)
{
switch (input)//分支语句
{
case 1:
game();//进入游戏
break;
case 0:
printf("Logon out the game\n");
break;
default:
printf("Input error,please input again\n");
break;
}
}
void menu(void)
{
printf("Welcome to game\n");
printf("\n");
printf("****************\n");
printf("*----1.play----*\n");
printf("*----0.exit----*\n");
printf("****************\n");
}
int main(void)
{
int input;
//srand((unsigned int)time(NULL));时间戳,为电脑落子设定随机数
do
{
menu();//打印游戏菜单
printf("please input option(1/0):>");
scanf("%d", &input);
option(input);//选项判断
} while (input);
return 0;
}
我们要求输入数字1或0,如果输入其他值,就会default结束,并进入while判断,为,int型,再次循环。
1,三子棋需要一个3*3的棋盘
2,需要将棋盘表现(打印出来)
3.玩家要开始下棋(输入坐标)
4.每次落子后都要判断输赢或平局
5,打印目前棋盘的状况
6,电脑开始落子
7,每次落子后都要判断输赢或平局
8,打印目前棋盘的状况
void game(void)
{
char ret;
char board[ROW][COL];//创建二维数组
setboard(board, ROW, COL);//制作棋盘
while (1)
{
player(board);//玩家开始下棋
ret=judgewinner(board);//判断输赢
if (ret != 'C')
break;
computer(board);//电脑开始下棋
ret=judgewinner(board);//判断输赢
if (ret != 'C')
break;
}
if (ret == '*')
printf("The winner is player\n");
else if (ret == '#')
printf("The winner is computer\n");
else if (ret == 'D')
printf("Player and computer draw\n");
}
1,三子棋需要一个3*3的棋盘
毕竟是个3 * 3的棋盘,可以使用二维数组。
char board[3][3]//这两个行列可以使用宏定义常量,方便延申N子棋。
#define ROW 3
#define COL 3
char board[ROW][COL]
2, 打印三子棋棋盘
大概是这样的
二维数组的元素也要被定义为空格。在后面玩家或电脑输入后可以被重新定义为*号或#号。
void setboard(char board[ROW][COL], int row, int col)//制作第一个棋盘
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';//元素被定义为空格
}
}
showboard(board,ROW, COL);//打印棋盘的函数
}
void showboard(char board[ROW][COL], int row, int col)//打印棋盘
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col)
printf("|");
}
if (i < row)
printf("\n---|---|---|\n");
}
}
3,玩家落子
就是输入坐标
void player(char board[ROW][COL])//玩家下棋
{
int x, y;
while (1)
{
printf("please input the coordinate:>");
scanf("%d %d", &x, &y);//输入要落子的坐标
if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判断该坐标处,是否未被输入过
{
if (board[x - 1][y - 1] != ' ')
printf("Coordinates occupied,please input again\n");
else
{
board[x - 1][y - 1] = '*';
break;
}
}
else
printf("Coordinate is illegal,please input again\n");//被使用过,重新输入
}
//printf("*******************\n");
printf("Player\n");
showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
由于玩家并不是程序员不认为,起点是0,所以赋值时要x-1,y-1.。
并且这是多次输入,要保证输入那个坐标处不能已经输入过,就是说要保证该数组元素只能为空格。同时还要保证输入坐标要有效,必须在33的棋盘内,如果两个问题有一个存在,必须要重新输入,所以放入循环内,直到输入正确,才会跳出循环。
4,先不考虑判断输赢,先打印当前棋盘,就是调用showboard(board, ROW, COL);函数,循环打印。
先保证电脑和玩家的棋盘输入输出正确再来判断输赢。
6,电脑开始落子,打印棋盘
暂时先使用随机落子的算法,下次我再写堵截玩家落子的算法
void computer(char board[ROW][COL])//电脑落子
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (board[x][y] == ' ')//判断该坐标处,是否未被输入过
{
board[x][y] = '#';
break;
}
}
printf("Computer\n");
//printf("*******************\n");
showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
前面已经使用srand();,保证了随机数
int x = rand() % ROW;
int y = rand() % COL;
X y,为随机数除以排或列的余数,也就是说xy的值必定小于排,列的值,也就保证了xy,为 0,1,2
这也同样保证了由三子棋走向N子棋的条件。
同样得保证电脑落子的坐标处不能已经使用过,必须得保证坐标元素处为空格,才能输入#。并且调用函数打印当前棋盘。
调用char judgewinner(char board[ROW][COL])函数
char ifdraw(char board[ROW][COL])
{
int i;
for (i = 0; i < ROW; i++)
{
int j;
for (j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'D';
}
char judgewinner(char board[ROW][COL])
{
int count;
//判断一行赢
for (int i = 0; i < ROW; i++)
{
int j,count=0;
for (j = 0; j < COL-1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
if ((count != COL - 1) && (i == ROW - 1))
return ifdraw(board);//平局
}
//判断列赢
for (int i = 0; i < COL; i++)
{
int j, count = 0;
for (j = 0; j < ROW - 1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
if ((count != ROW - 1) && i == COL - 1)
return ifdraw(board);//平局
}
//判断对角线\赢
count = 0;
int i = 0;
int j;
while ((count != COL - 1) && (i <ROW-1))
{
j = i;
if (board[i][j] == board[i + 1][j + 1])
count++;
else if (board[i][j] != board[i + 1][j + 1])
break;
i++;
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
}
return ifdraw(board);//平局}
//对角线/
count=0;
i = ROW - 1;
while (i>0)
{
j=ROW-i-1;
if (board[i][j] == board[i - 1][j + 1])
count++;
else if (board[i][j] = board[i - 1][j + 1])
break;
i--;
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
}
return ifdraw(board);//平局
}
判断一行或者一列的棋子都相等的情况下,我们使用l两个for循环,我们同时定义一个控制变量。外循环,保证每一个行或每列都能覆盖。内循环来确定每一行或每一列上的元素,相邻之间是否相等?如果相等,count加一,不相等就可以确定,不存在决定当前棋局的条件,直接跳出。同样支持N子棋的判断。
对于左斜线以及右斜线上的三指相的条件,这个就比较简单,,不需要一遍遍的遍历,只需要找到特定的三个元素去判断是否相等即可得出条件。
用这些循环条件来判断,只能得出是否是玩家赢还是电脑赢,但是还需要添加一个函数来判断是否是平局或者棋局未满,可以继续落子。
判断平局或继续落子。
用两个for循环去遍历数组只要判断出有一个元素是空格隔那么就返回c就可以直接得出可以继续落子,就需要返回来D来决定已经平局无法再落子。
因为一旦进入这卡数就表明已经判断出无法决定谁胜或者谁负,只能继续走两条路一就是平局,二就是继续落子。
同时,设定了ret来接受judgewinner(char board[ROW][COL])函数的返回值,来判断是否可以继续循环落子。
游戏的规则是行列斜线,三种情况下,只要有一种情况,该线上都归属于三个同样的旗子,即可判断输赢
我们可以考虑循环遍历
依靠循环进入每行每列,每个斜线,进行每个元素的遍历,如果该行该列或该斜线上有两个相同的元素,立马在第三个元素上进行,若无论是否与自己相同.
该思路目前只适用于三字棋,也可延伸到四子棋,4则是两个起步,如果该列该行或该切线上有两个以上的相同元素,就立马在第三或第四个元素中进行落子
以下便是为拆开讲解的全部代码。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include "game.h"
#define ROW 3
#define COL 3
//返回值
//*
//#
//C-继续
//D-平局
void game(void)
{
char ret;
char board[ROW][COL];//创建二维数组
setboard(board, ROW, COL);//制作棋盘
while (1)
{
player(board);//玩家开始下棋
ret=judgewinner(board);//判断输赢
if (ret != 'C')
break;
computer(board);//电脑开始下棋
ret=judgewinner(board);//判断输赢
if (ret != 'C')
break;
}
if (ret == '*')
printf("The winner is player\n");
else if (ret == '#')
printf("The winner is computer\n");
else if (ret == 'D')
printf("Player and computer draw\n");
}
void option(int input)
{
switch (input)//分支语句
{
case 1:
game();
break;
case 0:
printf("Logon out the game\n");
break;
default:
printf("Input error,please input again\n");
break;
}
}
void menu(void)
{
printf("Welcome to game\n");
printf("\n");
printf("****************\n");
printf("*----1.play----*\n");
printf("*----0.exit----*\n");
printf("****************\n");
}
int main(void)
{
int input;
srand((unsigned int)time(NULL));
do
{
menu();//打印游戏菜单
printf("please input option(1/0):>");
scanf("%d", &input);
option(input);//选项判断
} while (input);
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include "game.h"
//void game(void)
//{
// char board[ROW][COL];//创建二维数组
// setboard(board, ROW, COL);//制作棋盘
// player(board);//玩家开始下棋
//
// computer(board);//电脑开始下棋
//
//}
void setboard(char board[ROW][COL], int row, int col)//制作第一个棋盘
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
showboard(board,ROW, COL);
}
void showboard(char board[ROW][COL], int row, int col)//打印棋盘
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col)
printf("|");
}
if (i < row)
printf("\n---|---|---|\n");
}
}
void player(char board[ROW][COL])//玩家下棋
{
int x, y;
while (1)
{
printf("please input the coordinate:>");
scanf("%d %d", &x, &y);//输入要落子的坐标
if (x>=1&&x<=ROW&&y>=1&&y<=COL)//判断该坐标处,是否未被输入过
{
if (board[x - 1][y - 1] != ' ')
printf("Coordinates occupied,please input again\n");
else
{
board[x - 1][y - 1] = '*';
break;
}
}
else
printf("Coordinate is illegal,please input again\n");//被使用过,重新输入
}
//printf("*******************\n");
printf("Player\n");
showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
void computer(char board[ROW][COL])//电脑落子
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (board[x][y] == ' ')//判断该坐标处,是否未被输入过
{
board[x][y] = '#';
break;
}
}
printf("Computer\n");
//printf("*******************\n");
showboard(board, ROW, COL);//打印每次下棋后的棋盘
}
char ifdraw(char board[ROW][COL])
{
int i;
for (i = 0; i < ROW; i++)
{
int j;
for (j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'D';
}
char judgewinner(char board[ROW][COL])
{
int count;
//判断一行赢
for (int i = 0; i < ROW; i++)
{
int j,count=0;
for (j = 0; j < COL-1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
if ((count != COL - 1) && (i == ROW - 1))
return ifdraw(board);//平局
}
//判断列赢
for (int i = 0; i < COL; i++)
{
int j, count = 0;
for (j = 0; j < ROW - 1; j++)
{
if (board[i][j] != board[i][j + 1])
break;
else if (board[i][j] == board[i][j + 1])
count++;
}
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
if ((count != ROW - 1) && i == COL - 1)
return ifdraw(board);//平局
}
//判断对角线\赢
count = 0;
int i = 0;
int j;
while ((count != COL - 1) && (i <ROW-1))
{
j = i;
if (board[i][j] == board[i + 1][j + 1])
count++;
else if (board[i][j] != board[i + 1][j + 1])
break;
i++;
if (count == ROW - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
}
return ifdraw(board);//平局}
//对角线/
count=0;
i = ROW - 1;
while (i>0)
{
j=ROW-i-1;
if (board[i][j] == board[i - 1][j + 1])
count++;
else if (board[i][j] = board[i - 1][j + 1])
break;
i--;
if (count == COL - 1)
{
if (board[i][j] == '*')
return '*';//玩家赢
else if (board[i][j] == '#')
return '#';//电脑赢
}
}
return ifdraw(board);//平局
}
#include
#include
#include
#define ROW 3
#define COL 3
void game(void);//三子棋游戏
void setboard(char board[ROW][COL], int row, int col);//创建棋盘
void showboard(char board[ROW][COL], int row, int col);//打印、展示棋盘
void player(char board[ROW][COL]);//玩家落子
void computer(char board[ROW][COL]);//电脑落子
char judgewinner(char board[ROW][COL]);//判断输赢
char ifdraw(char board[ROW][COL]);//判断是否平局