三子棋
实现的逻辑
test.c
主函数mian()
int main()
{
srand((unsigned int)time(NULL));//产生一个随机数,以供电脑下棋
int input = 0;
//菜单
meun();
do
{
printf("请选择数字>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
此处需要注意的是要用到rand()这个函数,关于这个函数的使用可以参考rand()
而使用这个函数必须首先用srand()
至于为什么在函数一开始就写srand(),是因为要产生一个随机数给电脑,以便电脑下棋。值得注意的是不能把srand()放在包含rand()函数的的前面,不然这个随机数就不再随机。
菜单meum()
void meun()
{
printf("*************************\n");
printf("**** 1.Play 0.Exit *****\n");
printf("*************************\n");
}
调用meum(),让玩家知道如何开始
游戏逻辑game()
game()这个函数主要包括
初始化棋盘Init_board()
//棋盘是一个二维数组,首先申请一个二维数组
char board[ROW][COL] = { 0 };
//初始化棋盘
Init_board(board, ROW, COL);
打印棋盘Display_board()
Display_board(board, ROW, COL);
玩家下棋Player()
Player(board, ROW, COL);
电脑下棋Computer()
Computer(board, ROW, COL);
判断输赢 is_winner()
//这里的ret是为了接受返回字符
//返回‘#’玩家赢
//返回‘*’玩家赢
//返回‘E’平局
//返回‘K'游戏继续
ret = is_winner(board, ROW, COL);
if (ret != 'K')
{
//不是继续游戏,就表示有人赢或平局,那就退出循环
break;
}
test.c的全部代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void meun()
{
printf("*************************\n");
printf("**** 1.Play 0.Exit *****\n");
printf("*************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘
Init_board(board, ROW, COL);
//打印棋盘
Display_board(board, ROW, COL);
//下棋
while (1)
{
//玩家下棋
Player(board, ROW, COL);
//判断输赢
ret = is_winner(board, ROW, COL);
if (ret != 'K')
{
break;
}
Display_board(board, ROW, COL);
//电脑下棋
Computer(board, ROW, COL);
//判断输赢
ret = is_winner(board, ROW, COL);
if (ret != 'K')
{
break;
}
Display_board(board, ROW, COL);
}
if (ret == '#')
{
printf("玩家赢\n");
}
else if (ret == '*')
printf("电脑赢\n");
else
{
printf("平局\n");
}
Display_board(board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
//菜单
meun();
do
{
printf("请选择数字>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
功能的实现
game.c
Init_board()的实现
//传一个二维数组,行,列
//使棋盘都为空格
void Init_board(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] = ' ';
}
}
}
Display_board()的实现
我们把圈起来的看成一行
值得注意的是,这一行包含两个部分。
第一部分:
一个空格一个字符再加一个空格 # 在加一条 |
第二部分
三个 — 在加一个 |
首先我们打印第一部分,然后换行,在打第二部分
void Display_board(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");
}
}
}
这里来解释为什么有 if(j<col-1) 我们注意最后一列我们是不需要 | 所以增加一个判断
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
而这里的**if(i<row-1)**是因为我们最后一行是不需要打印分割线的
//打印分割线
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
Player()的实现
//玩家下棋
void Player(char board[ROW][COL], int row, int col)
{
//玩家输入坐标
int x = 0;
int y = 0;
while (1)
{
printf("玩家请下棋>");
scanf("%d %d", &x, &y);
//判断坐标是否合法
if ((x > 0 && x <= row) && (y > 0 && y <= col))
{
//该坐标是否被占用
//因为玩家不知道数组是从0开始的,所以x-1,y-1,就相当于下在**数组的第一行第一列**的位置
if (board[x - 1][y - 1] == ' ')
{
//玩家下棋,输入‘ # ’,并跳出while()
board[x - 1][y - 1] = '#';
break;
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
Computer()的实现
void Computer(char board[ROW][COL], int row, int col)
{
printf("电脑下棋>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
//电脑下棋输入' * '
board[x][y] = '*';
break;
}
}
}
使用rand()产生随机数,这里不懂,可以看看上文,至于为什么处于row和col,是因为是为了得到符合棋盘的范围,可以试着除一下,产生0~2的随机数,
is_winner()的实现
这里实现了动态的判断输赢
//返回‘#’玩家赢
//返回‘*’玩家赢
//返回‘E’平局
//返回‘K’游戏继续
行的判断
//行
for (i = 0; i < row; i++)
{
for (j = 0; j < col-1; j++)
{
if ((board[i][j] == board[i][j + 1]) && (board[i][j + 1] != ' '))
{
if (j == col - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
}
for循环中的j<col-1是因为,board[i][j] == board[i][j + 1]这个代码可以保证这一行都可以检测到,假如是三子棋,
当j=0的时候,检测第一列和第二列,当j=1的时候,检测了第一列和第二列。
注意 if (j == col - 2)
{
return board[i][j];
}
还是假如是一个三子棋当j=1的时候,这一行都检测完了,就可以返回这个字符了。
列的判断
列和行的思想差不多,这里不再叙述
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 1; i++)
{
if((board[i][j] == board[i + 1][j]) && (board[i + 1][j] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
}
对角线的判断
return的思想和行列都是一样的,
左对角线,坐标11 22 33;
右对角线对角线13 22 31
//左对角线
for (i = 0; i < row-1; i++)
{
j = i;
if ((board[i][j] == board[i + 1][j + 1]) && (board[i + 1][j + 1] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
//右对角线
for(i = 0; i < row; i++)
{
//举例当第一行的时候坐标是1 3
//在数组的位置就是0 2
j = col - 1 - i;
if ((board[i][j] == board[i + 1][j - 1]) && (board[i + 1][j - 1] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
平局的判断
if (IsFull(board, row, col))
{
//‘E’代表平局
return 'E';
}
这里创建了一个IsFull()的函数,如果棋盘满了返回1,否则返回0;
//判断棋盘是否满
//满了返回1
//没满返回0
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
游戏继续
//游戏继续
return 'K';
game.c全部代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘
void Init_board(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 Display_board(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(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家请下棋>");
scanf("%d %d", &x, &y);
if ((x > 0 && x <= row) && (y > 0 && y <= col))
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '#';
break;
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
//电脑下棋
void Computer(char board[ROW][COL], int row, int col)
{
printf("电脑下棋>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '*';
break;
}
}
}
//判断棋盘是否满
//满了返回1
//没满返回0
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
//判断输赢
char is_winner(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//行
for (i = 0; i < row; i++)
{
for (j = 0; j < col-1; j++)
{
if ((board[i][j] == board[i][j + 1]) && (board[i][j + 1] != ' '))
{
if (j == col - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
}
//列
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 1; i++)
{
if((board[i][j] == board[i + 1][j]) && (board[i + 1][j] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
}
//左对角线
for (i = 0; i < row-1; i++)
{
j = i;
if ((board[i][j] == board[i + 1][j + 1]) && (board[i + 1][j + 1] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
//右对角线
for(i = 0; i < row; i++)
{
j = col - 1 - i;
if ((board[i][j] == board[i + 1][j - 1]) && (board[i + 1][j - 1] != ' '))
{
if (i == row - 2)
{
return board[i][j];
}
}
else
{
break;
}
}
//棋盘满了,平局
if (IsFull(board, row, col))
{
return 'E';
}
//游戏继续
return 'K';
}
头文件game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
//声明棋盘
void Init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void Display_board(char board[ROW][COL], int row, int col);
//玩家下棋
void Player(char board[ROW][COL], int row, int col);
//电脑下棋
void Computer(char board[ROW][COL], int row, int col);
//判断输赢
char is_winner(char board[ROW][COL], int row, int col);
#define ROW 3
#define COL 3
是为了动态设计棋盘,根据玩家,自己的想法修改棋盘大小;
自此三子棋小游戏写完了,希望能够有所帮助大家,点个赞呗!友友们!