C语言:三子棋
1.前言
在我们日常生活中,当我们感到无聊时,我们或许会和朋友下一场三子棋来消磨时光,但是在我们C语言中,那我们或许会思考:那我们自己能否通过编程来完成三子棋游戏呢?因此,我来展示用C语言写三子棋的方法
2.准备工作
对于三子棋我们肯定需要一个主函数来包括其主要功能:主要是做出选择
#include <stdio.h>
int main()
{
int choice = 0;
do
{
scanf("%d",&choice);
menu();//游戏菜单
printf("\n");
switch(choice)
{
case 1:
game();//游戏函数
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
}
while(choice);
return 0;
}
这样就把整个游戏的框架完成了,接下来就开始一步一步地细化游戏内容了
3.游戏菜单
作为一个游戏,那必然是需要菜单的,否则玩家无法知道应该怎么办,所以接下来就是改写菜单的内容了,在正常的项目中,项目的主要内容会放在主函数外的另一个源文件中,这可以提高代码的安全性,所以我们将这个源文件名字设为了:game.c,而将主函数的源文件设为:main.c
#include <stdio.h>
void menu()
{
printf("1.play\n");
printf("0.exit\n");
printf("请做出选择:>");
}
当然,这里出来使用三个printf将菜单打印出来,也可以使用一个printf将菜单打印出来
void menu()
{
printf("1.play\n"
"0.exit\n"
"请做出选择:>");
}
但实际上这两种用法都一样,没有所谓的优劣之分,主要看个人习惯
4.设置头文件
当我们在main.c中引用其他源文件中的函数时,可以使用extern来声明,但在日常中,还是以设一个头文件为主,因为这样可以将需要用到的函数都在这个头文件中进行声明,然后对需要那些需要用到该头文件中的内容的地方直接引用该头文件即可,这可以大幅度的增加效率,也可以使该项目的内容比较简洁,让客户易懂,所以这里我们设这个头文件名为:game.h
#pragma once
void menu();
但我们转念一想,毕竟都引用头文件了,那能不能将库函数也通过该头文件来使用呢?答案明显是当然的,因此,我们会将头文件改成下面这样
#pragma once
#include <stdio.h>
void menu();
然后,将game.c和main.c也进行更改
(game.c)
#include "game.h"
void menu()
{
printf("1.play\n");
printf("0.exit\n");
printf("请做出选择:>");
}
(main.c)
#include "game.h"
int main()
{
int choice = 0;
do
{
scanf("%d",&choice);
menu();//游戏菜单
printf("\n");
switch(choice)
{
case 1:
game();//游戏函数
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
}
while(choice);
return 0;
}
这样,之后进行更改就只需要在头文件即可
5.编写游戏内容
接下来就该编写游戏函数的主要内容了
void game()
{
int Board[3][3]={0};
int row=3,col=3;//棋盘三行三列
initialBoard(Board,row,col);//将棋盘初始化
printBoard(Board,row,col);//打印棋盘
while(1)
{
Playermove(Board,row,col);//玩家下棋
printBoard(Board,row,col);//打印棋盘
char ret=Iswin(Board,row,col);//判断输赢
if(ret=='*')
{
printf("玩家赢\n");
}
if(ret=='p')
{
printf("平局\n");
}
Computermove(Board,row,col);//电脑下棋
printBoard(Board,row,col);//打印棋盘
ret=Iswin(Board,row,col);//判断输赢
if(ret=='#')
{
printf("电脑赢\n");
}
if(ret=='p')
{
printf("平局\n");
}
}
}
这里就已经将游戏的函数的框架写出来,我们可以看出,我们首先得有棋盘,然后将棋盘打印出来,然后玩家下棋和电脑下棋,每当玩家或电脑下完棋,就需要我们进行一次判断游戏输赢
1.初始化棋盘
对于棋盘的初始化,我们可以这样
void initialBoard(int Board[3][3],int row,int col)
{
for(int i=0;i<col;i++)//行
{
for(int j=0;j<row;j++)//列
//令棋盘上的每一位都是' ',这样便完成了对于棋盘的初始化
Board[i][j]=' ';
}
}
2.打印棋盘
1.暴力打印
初始化完棋盘后,那接下来的工作就是打印棋盘了,对于打印棋盘,我们可以这样子
//暴力解法
void printBoard(int Board[3][3],int row,int col)
{
printf(" %c | %c | %c \n",Board[0][0],Board[0][1],Board[0][2]);
printf("---|---|---\n");
printf(" %c | %c | %c \n"Board[1][0],Board[1][1],Board[1][2]);
printf("---|---|---\n");
printf(" %c | %c | %c \n",Board[2][0],Board[2][1],Board[2][2]);
}
这一种是最简单粗暴的,但这个方法可拓展性太差了,而且也几乎用不上我们引进的数据,因此,我们还有一个改进方案
void printBoard(int Board[3][3],int row,int col)
{
for(int i=0;i<col;i++)
{
printf(" %c | %c | %c \n",Board[i][0],Board[i][1],Board[i][2]);
if(i==col-1)
continue;
printf("---|---|---\n");
}
}
2.简单优化
但是这似乎拓展性还是太差了,没法将这个棋盘变为五子棋的棋盘,所以,我们还得对这个代码进行优化
void printBoard(int Board[3][3],int row,int col)
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row ; j++)
{
printf(" %c ",Board[i][j]);
if(j < row - 1)
printf("|");
}
printf("\n");
if (i < col - 1)
{
for (int j = 0; j < row; j++)
{
printf("---");
if (j < row - 1)
printf("|");
}
}
printf("\n");
}
}
3.更深的优化
但这依然不能将其很简单地改为五子棋盘,需要我们一个一个修改,这很明显地可以发现其效率很低,这时候我们就得思考怎样能一次性改变即可呢?
通过思考,我们可以联想到上面的头文件,因为头文件内的东西一旦改变,引用头文件的源文件也会发生相应的变化,这时候,我们又进行更深层的思考,可以想到宏定义,因为它也可以一次性改变多个量,那么将这两种结合在一起呢?
所以就有了下面的代码:
(game.h)
#pragma once
#include <stdio.h>
#define ROW 3
#define COL 3
void menu();
void game();
void intialBoard(int Board[ROW][COL],int row,int col);
void printBoard(int Board[ROW][COL],int row,int col);
(game.c)
#include "game.h"
void menu()
{
printf("1.play\n");
printf("0.exit\n");
printf("请做出选择:>");
}
void initialBoard(int Board[ROW][COL],int row,int col)
{
for(int i=0;i<col;i++)//行
{
for(int j=0;j<row;j++)//列
//令棋盘上的每一位都是' ',这样便完成了对于棋盘的初始化
Board[i][j]=' ';
}
}
void printBoard(char Board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row ; j++)
{
printf(" %c ",Board[i][j]);
if(j < row - 1)
printf("|");
}
printf("\n");
if (i < col - 1)
{
for (int j = 0; j < row; j++)
{
printf("---");
if (j < row - 1)
printf("|");
}
}
printf("\n");
}
}
void game()
{
int Board[ROW][COL]={0};
int row=ROW,col=COL;//棋盘三行三列
initialBoard(Board,row,col);//将棋盘初始化
printBoard(Board,row,col);//打印棋盘
while(1)
{
Playermove(Board,row,col);//玩家下棋
printBoard(Board,row,col);//打印棋盘
char ret=Iswin(Board,row,col);//判断输赢
if(ret=='*')
{
printf("玩家赢\n");
}
if(ret=='p')
{
printf("平局\n");
}
Computermove(Board,row,col);//电脑下棋
printBoard(Board,row,col);//打印棋盘
ret=Iswin(Board,row,col);//判断输赢
if(ret=='#')
{
printf("电脑赢\n");
}
if(ret=='p')
{
printf("平局\n");
}
}
}
这样就完成了基本的优化了
3.玩家下棋
那么接下来就是该到玩家下棋了,对于玩家下棋,我们需要注意的是,玩家下棋肯定不会以编程的角度去看这盘棋,所以便没有了下标从0开始,而是从1开始,还有就是不能重复在一个点上落子,所以我们的代码像下面这样
void Playermove(char Board[ROW][COL], int row, int col)
{
while (1)
{
printf("玩家请下棋:>");
scanf("%d %d", &row, &col);
if (Board[row-1][col-1] == ' ')//得确保我们落子的地方得没有子
{
Board[row - 1][col - 1] = '*';//我们设我们的棋是'*'
break;
}
else
{
printf("此处有子,请重新落子\n");
}
}
}
这样,我们的玩家下棋的代码大概就完成了
4.电脑下棋
1.简单落子
玩家下完棋后,那就是该电脑下棋了,该注意的还是,不能重复落在一个位置上
void Computermove(char Board[ROW][COL], int row, int col)
{
if (Board[1][1] == ' ')//有中间位置,就下中间位置,这样能提高胜率
{
Board[1][1] = '#';//设定电脑的棋是'#'
}
else
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row; j++)
{
if (Board[i][j] == ' ')
{
printf("电脑下棋:>%d %d\n",i+1,j+1);
Board[i][j] = '#';
}
}
}
}
}
2.普通落子
有简单就会有普通
void Computermove2(char Board[ROW][COL], int row, int col)
{
//这里会使用随机落子,使用rand之前需要我们引用库函数stdlib
//但这使用通常需要srand(),而()里应该放随机值
//这时候就需要用到时间戳的概念了
//使用时间戳需要引用库函数time
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (Board[x][y] == ' ')
{
printf("电脑下棋:>%d %d\n", x+1, y+1);
Board[x][y] = '#';
break;
}
}
}
3.困难落子
当然,这样的话,电脑下棋就太容易被赢了,所以这时候,我们可以想一想,怎么让电脑变得更厉害些,尽量与我们旗鼓相当,所以就有了下面
void Computermove(char Board[ROW][COL], int row, int col)
{
while (1)
{
if (Board[1][1] == ' ')
{
printf("电脑下棋:>2 2\n");
Board[1][1] = '#';//设电脑的棋时'#'
goto end;//下完棋后就直接下一步,这样就可以不用进行判断了
}
else
{
//随机落子
int x = rand() % row;
int y = rand() % col;
int count1 = 0, count2 = 0;
int a = 0, b = 0;
for (int i = 0, j = 0, count1 = 0, count2 = 0; i < col, j < row; i++, j++)//斜下
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
//Board[i][j]=0时,赋值
a = i;
b = j;
}
if (i == col - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = ROW - 1, j = 0, count1 = 0, count2 = 0; i >= 0, j < COL; i--, j++)//斜上
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (i == 0)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = 0; i < COL; i++)//行
{
int count1 = 0, count2 = 0;
for (int j = 0; j < ROW; j++)
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (j == ROW - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
a = 0, b = 0;
for (int i = 0; i < ROW; i++)//列
{
int count1 = 0, count2 = 0;
for (int j = 0; j < COL; j++)
{
if (Board[j][i] == '*')
{
count1++;
}
else if (Board[j][i] == '#')
{
count2++;
}
else
{
a = j;
b = i;
}
if (j == COL - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
if(Board[x][y]==' ')
{
printf("电脑下棋:>%d %d\n", x + 1, y + 1);
//当都不符合上述的状况时,随机落子
Board[x][y] = '#';
end:
break;
}
}
}
}
当然,我们也可以将上面的简单,普通,困难放到一起中
1.首先将主函数进行修改
#include "game.h"
int main()
{
int choice = 0;
int choice2 = 0;
srand((unsigned int)time(NULL));//创建随机值
do
{
menu();//游戏菜单
scanf("%d", &choice);
switch (choice)
{
case 1:
do
{
menudiff();
scanf("%d", &choice2);
switch (choice2)
{
case 1:
case 2:
case 3:
goto out;
default:
printf("无此选项,请重新选择\n");
}
} while (1);
out:
game(choice2);
continue;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (choice);
return 0;
}
2.对游戏的函数进行改变
void Computermove1(char Board[ROW][COL], int row, int col)
{
if (Board[1][1] == ' ')//有中间位置,就下中间位置,这样能提高胜率
{
Board[1][1] = '#';//设定电脑的棋是'#'
}
else
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row; j++)
{
if (Board[i][j] == ' ')
{
printf("电脑下棋:>%d %d\n",i+1,j+1);
Board[i][j] = '#';
}
}
}
}
}
void Computermove2(char Board[ROW][COL], int row, int col)
{
//这里会使用随机落子,使用rand之前需要我们引用库函数stdlib
//但这使用通常需要srand(),而()里应该放随机值
//这时候就需要用到时间戳的概念了
//使用时间戳需要引用库函数time
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (Board[x][y] == ' ')
{
printf("电脑下棋:>%d %d\n", x+1, y+1);
Board[x][y] = '#';
break;
}
}
}
void Computermove3(char Board[ROW][COL], int row, int col)
{
while (1)
{
if (Board[1][1] == ' ')
{
printf("电脑下棋:>2 2\n");
Board[1][1] = '#';//设电脑的棋时'#'
goto end;//下完棋后就直接下一步,这样就可以不用进行判断了
}
else
{
//随机落子
int x = rand() % row;
int y = rand() % col;
int count1 = 0, count2 = 0;
int a = 0, b = 0;
for (int i = 0, j = 0, count1 = 0, count2 = 0; i < col, j < row; i++, j++)//斜下
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
//Board[i][j]=0时,赋值
a = i;
b = j;
}
if (i == col - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = ROW - 1, j = 0, count1 = 0, count2 = 0; i >= 0, j < COL; i--, j++)//斜上
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (i == 0)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = 0; i < COL; i++)//行
{
int count1 = 0, count2 = 0;
for (int j = 0; j < ROW; j++)
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (j == ROW - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
a = 0, b = 0;
for (int i = 0; i < ROW; i++)//列
{
int count1 = 0, count2 = 0;
for (int j = 0; j < COL; j++)
{
if (Board[j][i] == '*')
{
count1++;
}
else if (Board[j][i] == '#')
{
count2++;
}
else
{
a = j;
b = i;
}
if (j == COL - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
if(Board[x][y]==' ')
{
printf("电脑下棋:>%d %d\n", x + 1, y + 1);
//当都不符合上述的状况时,随机落子
Board[x][y] = '#';
end:
break;
}
}
}
}
3.然后再将头文件进行一次修改即可
(game.h)
#pragma once
#include <stdio.h>
#define ROW 3
#define COL 3
#include <stdlib.h>
#include <time.h>
void menu();
void menudiff();
void game(int choice2);
void intialBoard(int Board[ROW][COL],int row,int col);
void printBoard(int Board[ROW][COL],int row,int col);
void Playermove(int Board[ROW][COL],int row,int col);
void Computermove1(int Board[ROW][COL],int row,int col);
void Computermove2(int Board[ROW][COL],int row,int col);
void Computermove3(int Board[ROW][COL],int row,int col);
5.判断输赢
准备完这些后,就只剩下判断输赢的函数了,而判断输赢,只需要遍历棋盘,检查是否有连在一起的三个子,且都不是 ' ' ,以及平局的情况
char Iswin(char Board[ROW][COL], int row, int col)
{
for (int i = 0, j = 0, count = 0; i < COL - 1, j < ROW - 1; i++, j++)//判断斜下
{
if (Board[i][j] == Board[i + 1][j + 1] && Board[i][j] != ' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = COL - 1, j = 0, count = 0; i >= 1, j < ROW - 1; i--, j++)//判断斜上
{
if (Board[i][j] == Board[i - 1][j + 1] && Board[i][j] != ' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = 0; i < COL; i++)//判断行
{
int count = 0;
for (int j = 0; j < ROW - 1; j++)
{
if (Board[i][j] == Board[i][j + 1]&&Board[i][j]!=' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = 0; i < COL; i++)//判断列
{
int count = 0;
for (int j = 0; j < ROW - 1; j++)
{
if (Board[j][i] == Board[j + 1][i]&&Board[j][i]!=' ')
{
count++;
}
if (count == 2)
{
if (Board[j][i] == '*')
return '*';
else
return '#';
}
}
}
int count1 = 0;
for (int i = 0; i < COL; i++)//判断棋盘是否满了,满了则平局
{
for (int j = 0; j < ROW; j++)
{
if (Board[i][j] != ' ')
{
count1++;
}
else
//当Board[i][j]==' '时,说明棋盘至少有一个空位,可以直接跳出循环
break;
if (count1 == (ROW) * (COL))
{
return 'p';
}
}
}
//当以上一次都没有完成return,说明游戏还没有结束,所以继续
return 'c';
}
}
6.小优化
我们也可以使开局进行随机,随机优先下棋,仅需对游戏函数进行修改即可
(game.c)
void game(int choice2)
{
int s = rand() % 2 + 1;
char Board[ROW][COL] = { 0 };
int row = ROW, col = COL;//棋盘三行三列
initialBoard(Board, row, col);//将棋盘初始化
printBoard(Board, row, col);//打印棋盘
char ret;
while (1)
{
if(s == 1)
{
Playermove(Board, row, col);//玩家下棋
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
if (choice2 == 1)
{
Computermove1(Board, row, col);//电脑下棋
}
else if (choice2 == 2)
{
Computermove2(Board, row, col);//电脑下棋
}
else
{
Computermove3(Board, row, col);//电脑下棋
}
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
}
else
{
if (choice2 == 1)
{
Computermove1(Board, row, col);//电脑下棋
}
else if (choice2 == 2)
{
Computermove2(Board, row, col);//电脑下棋
}
else
{
Computermove3(Board, row, col);//电脑下棋
}
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
Playermove(Board, row, col);//玩家下棋
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
}
}
}
这样就可以达到随机优先权
6.总体
那么接下来就是整个程序了
(game.h)
#pragma once
#include <stdio.h>
#define ROW 3
#define COL 3
#include <stdlib.h>
#include <time.h>
void menu();
void menudiff();
void game(int choice2);
void initialBoard(char Board[ROW][COL], int row, int col);
void printBoard(char Board[ROW][COL], int row, int col);
void Playermove(char Board[ROW][COL], int row, int col);
void Computermove1(char Board[ROW][COL], int row, int col);
void Computermove2(char Board[ROW][COL], int row, int col);
void Computermove3(char Board[ROW][COL], int row, int col);
char Iswin(char Board[ROW][COL], int row, int col);
(game.c)
#include "game.h"
void menu()
{
printf("1.play\n");
printf("0.exit\n");
printf("请做出选择:>");
}
void menudiff()
{
printf("1.easy\n");
printf("2.normal\n");
printf("3.difficult\n");
printf("请选择难度:>");
}
void initialBoard(char Board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)//行
{
for (int j = 0; j < row; j++)//列
//令棋盘上的每一位都是' ',这样便完成了对于棋盘的初始化
Board[i][j] = ' ';
}
}
void printBoard(char Board[ROW][COL], int row, int col)
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row ; j++)
{
printf(" %c ",Board[i][j]);
if(j < row - 1)
printf("|");
}
printf("\n");
if (i < col - 1)
{
for (int j = 0; j < row; j++)
{
printf("---");
if (j < row - 1)
printf("|");
}
}
printf("\n");
}
}
void Playermove(char Board[ROW][COL], int row, int col)
{
while (1)
{
printf("玩家请下棋:>");
scanf("%d %d", &row, &col);
if (Board[row-1][col-1] == ' ')//得确保我们落子的地方得没有子
{
Board[row - 1][col - 1] = '*';//我们设我们的棋是'*'
break;
}
else
{
printf("此处有子,请重新落子\n");
}
}
}
void Computermove1(char Board[ROW][COL], int row, int col)
{
if (Board[1][1] == ' ')//有中间位置,就下中间位置,这样能提高胜率
{
Board[1][1] = '#';//设定电脑的棋是'#'
}
else
{
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row; j++)
{
if (Board[i][j] == ' ')
{
printf("电脑下棋:>%d %d\n",i+1,j+1);
Board[i][j] = '#';
}
}
}
}
}
void Computermove2(char Board[ROW][COL], int row, int col)
{
//这里会使用随机落子,使用rand之前需要我们引用库函数stdlib
//但这使用通常需要srand(),而()里应该放随机值
//这时候就需要用到时间戳的概念了
//使用时间戳需要引用库函数time
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (Board[x][y] == ' ')
{
printf("电脑下棋:>%d %d\n", x+1, y+1);
Board[x][y] = '#';
break;
}
}
}
void Computermove3(char Board[ROW][COL], int row, int col)
{
while (1)
{
if (Board[1][1] == ' ')
{
printf("电脑下棋:>2 2\n");
Board[1][1] = '#';//设电脑的棋时'#'
goto end;//下完棋后就直接下一步,这样就可以不用进行判断了
}
else
{
//随机落子
int x = rand() % row;
int y = rand() % col;
int count1 = 0, count2 = 0;
int a = 0, b = 0;
for (int i = 0, j = 0, count1 = 0, count2 = 0; i < col, j < row; i++, j++)//斜下
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
//Board[i][j]=0时,赋值
a = i;
b = j;
}
if (i == col - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = ROW - 1, j = 0, count1 = 0, count2 = 0; i >= 0, j < COL; i--, j++)//斜上
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (i == 0)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
a = 0, b = 0;
for (int i = 0; i < COL; i++)//行
{
int count1 = 0, count2 = 0;
for (int j = 0; j < ROW; j++)
{
if (Board[i][j] == '*')
{
count1++;
}
else if (Board[i][j] == '#')
{
count2++;
}
else
{
a = i;
b = j;
}
if (j == ROW - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
a = 0, b = 0;
for (int i = 0; i < ROW; i++)//列
{
int count1 = 0, count2 = 0;
for (int j = 0; j < COL; j++)
{
if (Board[j][i] == '*')
{
count1++;
}
else if (Board[j][i] == '#')
{
count2++;
}
else
{
a = j;
b = i;
}
if (j == COL - 1)
{
if ((count1 == 2 || count2 == 2) && count1 + count2 != 3)
{
printf("电脑下棋:>%d %d\n", a + 1, b + 1);
//count1+count2!=3,保证这条线上有空位
//count1=2||count2=2时,说明玩家快赢了,或电脑快赢了
//玩家快赢了,这是电脑应该堵住,电脑快赢了,就直接落子胜利
Board[a][b] = '#';
goto end;
}
}
}
}
if(Board[x][y]==' ')
{
printf("电脑下棋:>%d %d\n", x + 1, y + 1);
//当都不符合上述的状况时,随机落子
Board[x][y] = '#';
end:
break;
}
}
}
}
char Iswin(char Board[ROW][COL], int row, int col)
{
for (int i = 0, j = 0, count = 0; i < COL - 1, j < ROW - 1; i++, j++)//判断斜下
{
if (Board[i][j] == Board[i + 1][j + 1] && Board[i][j] != ' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = COL - 1, j = 0, count = 0; i >= 1, j < ROW - 1; i--, j++)//判断斜上
{
if (Board[i][j] == Board[i - 1][j + 1] && Board[i][j] != ' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = 0; i < COL; i++)//判断行
{
int count = 0;
for (int j = 0; j < ROW - 1; j++)
{
if (Board[i][j] == Board[i][j + 1]&&Board[i][j]!=' ')
{
count++;
}
if (count == 2)
{
if (Board[i][j] == '*')
return '*';
else
return '#';
}
}
for (int i = 0; i < COL; i++)//判断列
{
int count = 0;
for (int j = 0; j < ROW - 1; j++)
{
if (Board[j][i] == Board[j + 1][i]&&Board[j][i]!=' ')
{
count++;
}
if (count == 2)
{
if (Board[j][i] == '*')
return '*';
else
return '#';
}
}
}
int count1 = 0;
for (int i = 0; i < COL; i++)//判断棋盘是否满了,满了则平局
{
for (int j = 0; j < ROW; j++)
{
if (Board[i][j] != ' ')
{
count1++;
}
else
//当Board[i][j]==' '时,说明棋盘至少有一个空位,可以直接跳出循环
break;
if (count1 == (ROW) * (COL))
{
return 'p';
}
}
}
//当以上一次都没有完成return,说明游戏还没有结束,所以继续
return 'c';
}
}
void game(int choice2)
{
int s = rand() % 2 + 1;
char Board[ROW][COL] = { 0 };
int row = ROW, col = COL;//棋盘三行三列
initialBoard(Board, row, col);//将棋盘初始化
printBoard(Board, row, col);//打印棋盘
char ret;
while (1)
{
if(s == 1)
{
Playermove(Board, row, col);//玩家下棋
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
if (choice2 == 1)
{
Computermove1(Board, row, col);//电脑下棋
}
else if (choice2 == 2)
{
Computermove2(Board, row, col);//电脑下棋
}
else
{
Computermove3(Board, row, col);//电脑下棋
}
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
}
else
{
if (choice2 == 1)
{
Computermove1(Board, row, col);//电脑下棋
}
else if (choice2 == 2)
{
Computermove2(Board, row, col);//电脑下棋
}
else
{
Computermove3(Board, row, col);//电脑下棋
}
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '#')
{
printf("电脑赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
Playermove(Board, row, col);//玩家下棋
printBoard(Board, row, col);//打印棋盘
ret = Iswin(Board, row, col);//判断输赢
if (ret == '*')
{
printf("玩家赢\n");
break;
}
if (ret == 'p')
{
printf("平局\n");
break;
}
}
}
}
(main.c)
#include "game.h"
int main()
{
int choice = 0;
int choice2 = 0;
srand((unsigned int)time(NULL));//创建随机值
do
{
menu();//游戏菜单
scanf("%d", &choice);
switch (choice)
{
case 1:
do
{
menudiff();
scanf("%d", &choice2);
switch (choice2)
{
case 1:
case 2:
case 3:
goto out;
default:
printf("无此选项,请重新选择\n");
}
} while (1);
out:
game(choice2);
continue;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (choice);
return 0;
}
7.总结
1.首先
综上所述,写三子棋时需要先设立好主函数的源文件,函数的源文件,以及用于声明和定义的头文件
2.然后
将游戏函数中的内容的框架设置好,比如:棋盘初始化,棋盘的打印,玩家下棋,电脑下棋,判断输赢
3.最后
最后注意像电脑不能重复落子,玩家也是,还有就是玩家的棋盘不是从0开始的,所以也应做些调整,以及判断输赢的时候,注意连在一起的三个子不是' '