引言
三子棋是对于函数,数组,循环,判断,以及常量与变量的知识结合,是对于目前初阶C语言的小测试,用来巩固已学的知识和初步了解编程思想。
一、三子棋及多子棋的实现思路:
1.游戏的菜单可视化;
2.获取玩家输入的选项程序响应下一步操作;
3.在一个game()函数中的操作:
1) 获取的值为字符,且为多行多列,故通过二维数组存放棋子的位置,以及谁下的棋子;
2) 对二维数组初始化;
3) 显示棋盘;
4) 获取玩家输入的棋子坐标;
5) 显示棋盘状况;
6) 电脑下棋;
7) 显示棋盘状况;
8) 由于4~7步为循环步骤,直至哪一方获胜或者平局,故需要将4~7循环并且在每一方下完棋后判断是否继续或者胜负或者平局,即在每个显示棋盘状况后添加判断;
9) 判断完胜负或平局后,显示结果。
4.完成一局后,回到菜单,通过玩家输入时候进行下一场游戏,或退出。
二、三子棋的主要功能:
1.游戏的简易菜单menu():
图示:
示例代码:
void menu()
{
printf("**********************\n");
printf("*** 1.开始游戏 ***\n");
printf("*** 0.退出 ***\n");
printf("**********************\n");
}
2.用户进入游戏与退出 :
通过获取用户输入的选项来进行下一步操作,如:进入游戏,退出游戏,检测输入错误,重新输入;
示例代码:
int main()
{
int input = 0;
//srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入选项代表的数字:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误\n");
break;
}
}
while (input);
return 0;
}
3.game()函数的功能:
进入游戏后初始化二维数组,调用函数,判断游戏结果
void game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
Player(board);
DisplayBoard(board, ROW, COL);
ret = Determine(board);
if (ret != 'C')
break;
Computer(board);
DisplayBoard(board, ROW, COL);
ret = Determine(board);
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("\n");
printf("***********\n");
printf("玩家赢!!!!!\n");
printf("\n");
}
if (ret == '#')
{
printf("\n");
printf("***********\n");
printf("电脑赢!!!!!\n");
printf("\n");
}
if (ret == 'Q')
{
printf("\n");
printf("***********\n");
printf("平局!!!!!!\n");
printf("\n");
}
}
4.用户选择进入游戏后,各个游戏功能介绍:
1)初始化棋盘
2)显示棋盘
3)玩家下棋
4)电脑下棋
5)判断游戏的情况
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.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(char board[ROW][COL]);//玩家下棋
void Computer(char board[ROW][COL]);//电脑下棋
//返回值的含义:*--玩家胜 #--电脑胜 Q--退出 C--继续
char Determine(char board[ROW][COL]);//判断游戏进行的情况
5.初始化棋盘:
初始化棋盘为空格,即可默认棋盘为空
void InitBoard(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] = ' ';
}
}
}
6.显示棋盘:
通过for循环嵌套实现棋盘的打印,以及棋子的摆放,通过下划线_以及或符号 | 来美化棋盘,一开始为一个for循环里打印每一行的棋子和如同 ___|___|___,但是过于局限性,故通过for循环嵌套优化
void DisplayBoard(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 - 1)
printf("|");
}
printf("\n");
for (int k = 0; k < col; k++)
{
printf("---");
if (k < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
7.玩家下棋:
通过获取玩家输入的横、纵坐标各减1来用*替换数组相应位置的空格,并且判断坐标输入的有效性
void Player(char board[ROW][COL])
{
int i, j;
printf("玩家下棋\n");
while (1)
{
printf("请输入棋子坐标:>");
scanf("%d %d", &i, &j);
if (i >= 1 && i <= ROW && j <= COL && j >= 1)//合法坐标
{
if (board[i - 1][j - 1] == ' ')//坐标未占用
{
board[i - 1][j - 1] = '*';
break;
}
else
printf("输入坐标被占用\n");
}
else
printf("输入坐标无效\n");
}
}
8.电脑下棋
通过随机数函数来使电脑随机下棋,在game()函数中使用srand()函数来控制rand()函数,而srand()函数中的参数为无符号整型,参数设为(unsigned int)time(NULL)可使rand()函数生成较为随机的随机值,通过%行或列来实现坐标正确位于二维数组。
srand((unsigned int)time(NULL));
void Computer(char board[ROW][ROW])
{
int x, y;
printf("电脑下棋\n");
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
9.判断棋盘状况:
返回char,char可为结果有‘*’,‘#’,‘C’,‘Q’,以此来在game()函数判断循环继续,以及最后结果,若为‘C’游戏继续,直至产生游戏结果。
其中的IsFull函数判断时候棋盘已满,返回0或1,以此来判断未产生胜负结果时,返回‘C’,还是‘Q’;
int IsFull(char board[ROW][COL])
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
char Determine(char board[ROW][COL])
{
int i = 0;
int count2 = 0;
int count3 = 0;
for (i = 0; i < ROW; i++)
{
int j = 0;
int count = COL;
int count1 = COL;
for (j = 0; j < COL; j++)
{
if (board[i][j] == '*'&&board[i][0]=='*')//依据计数来统计行相同数
count++;
else if (board[i][j] == '#'&& board[i][0] == '#')
count--;
if (board[j][i] == '*'&& board[0][i] == '*')//依据计数来统计列相同数
count1++;
else if (board[j][i] == '#'&& board[0][i] == '#')
count1--;
if (board[i][j] == '*' && i == j)//统计对角线相同数
count2++;
else if (board[i][j] == '#' && i == j)
count2--;
if (board[i][j] == '*' && i + j == COL - 1 )//统计反对角线相同数
count3++;
else if (board[i][j] == '#' && i + j == COL - 1 )
count3--;
}
if (count == 2 * COL)//判断行满足胜利条件
return '*';
else if (count == 0)
return '#';
if (count1 == COL * 2)//判断列满足胜利条件
return '*';
else if (count1 == 0)
return '#';
}
if (count2 == COL || count3 == COL)
return '*';
if (count2 == -COL || count3 == -COL)
return '#';
if (IsFull(board) == 1)
return 'Q';
return 'C';
}
三、程序结果及感想:
感想:这篇博客不是写的很好,第一次写,三子棋的实现也几乎是n*n的多子棋的实现,只需把宏定义的常量改为所需要的数字,而三子棋的专属实现有一部分在判断棋盘状况的函数中,只需4个for循环里if语句分别判断行,列,对角线,反对角线的三个元素是否相等且不为空格,并返回其中的某一个元素的字符类型就能判断胜负,而在改进成多子棋的过程中未保存原先的三子棋步骤,故在此不显示。在进行多子棋改进中通过多次调试,才实现多子棋,count,count1只能在最外层,不能放在for循环中,自行尝试;而count2,count3需要放在第一个for循环中,若放在最外层即不在for循环中,则会导致有些对角线和反对角线本该出现胜负的情况却没有出现,原因为count2,count3会在里层for循环中更改,而每次计数在内部的for循环中更改,故需要初始化。
四、源代码:
test.c中:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
Player(board);
DisplayBoard(board, ROW, COL);
ret = Determine(board);
if (ret != 'C')
break;
Computer(board);
DisplayBoard(board, ROW, COL);
ret = Determine(board);
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("\n");
printf("***********\n");
printf("玩家赢!!!!!\n");
printf("\n");
}
if (ret == '#')
{
printf("\n");
printf("***********\n");
printf("电脑赢!!!!!\n");
printf("\n");
}
if (ret == 'Q')
{
printf("\n");
printf("***********\n");
printf("平局!!!!!!\n");
printf("\n");
}
}
void menu()
{
printf("**********************\n");
printf("*** 1.开始游戏 ***\n");
printf("*** 0.退出 ***\n");
printf("**********************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入选项代表的数字:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误\n");
break;
}
}
while (input);
return 0;
}
game.c中:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(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] = ' ';
}
}
}
void DisplayBoard(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 - 1)
printf("|");
}
printf("\n");
for (int k = 0; k < col; k++)
{
printf("---");
if (k < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
void Player(char board[ROW][COL])
{
int i, j;
printf("玩家下棋\n");
while (1)
{
printf("请输入棋子坐标:>");
scanf("%d %d", &i, &j);
if (i >= 1 && i <= ROW && j <= COL && j >= 1)//合法坐标
{
if (board[i - 1][j - 1] == ' ')//坐标未占用
{
board[i - 1][j - 1] = '*';
break;
}
else
printf("输入坐标被占用\n");
}
else
printf("输入坐标无效\n");
}
}
void Computer(char board[ROW][ROW])
{
int x, y;
printf("电脑下棋\n");
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(char board[ROW][COL])
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
char Determine(char board[ROW][COL])
{
int i = 0;
int count2 = 0;
int count3 = 0;
for (i = 0; i < ROW; i++)
{
int j = 0;
int count = COL;
int count1 = COL;
for (j = 0; j < COL; j++)
{
if (board[i][j] == '*'&&board[i][0]=='*')//依据计数来统计行相同数
count++;
else if (board[i][j] == '#'&& board[i][0] == '#')
count--;
if (board[j][i] == '*'&& board[0][i] == '*')//依据计数来统计列相同数
count1++;
else if (board[j][i] == '#'&& board[0][i] == '#')
count1--;
if (board[i][j] == '*' && i == j)//统计对角线相同数
count2++;
else if (board[i][j] == '#' && i == j)
count2--;
if (board[i][j] == '*' && i + j == COL - 1 )//统计反对角线相同数
count3++;
else if (board[i][j] == '#' && i + j == COL - 1 )
count3--;
}
if (count == 2 * COL)//判断行满足胜利条件
return '*';
else if (count == 0)
return '#';
if (count1 == COL * 2)//判断列满足胜利条件
return '*';
else if (count1 == 0)
return '#';
}
if (count2 == COL || count3 == COL)
return '*';
if (count2 == -COL || count3 == -COL)
return '#';
if (IsFull(board) == 1)
return 'Q';
return 'C';
}
game.h中:
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.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(char board[ROW][COL]);//玩家下棋
void Computer(char board[ROW][COL]);//电脑下棋
//*--玩家胜 #--电脑胜 Q--退出 C--继续
char Determine(char board[ROW][COL]);//判断游戏进行的情况