目录
- 一、井字棋介绍
- 二、涉及的知识点
- 三、设计思路及代码实现
- 1.主函数
- 2.头文件
- 3.函数实现
- 四、个人总结
- 五、改进建议
一、井字棋介绍
井字棋其实不用过多介绍,就是三点成线就算赢,所以又称三子棋,相信诸位在学生时代早早就在无聊的课堂上精通了这个游戏,那么今天重点是学习利用数组,循环,随机值函数等写出一个简易版的井字棋出来
二、涉及的知识点
- 二维数组
- 随机值生成
- goto语句
- 循环语句
- 选择语句
- 时间戳
三、设计思路及代码实现
为方便管理我们创建三个文件
main.c//主函数
game.c//功能实现
game.h//存放头文件使主函数可以调用game.c中的文件
思路:在下棋之前要有一个菜单menu,可用switch实现,然后打印一个棋盘,棋盘里面包含了一个3*3的字符数组即棋子,当你选择继续游戏时就调用game里面的函数进行实现,否则退出游戏,然后就是改变数组里面的棋子进行循环走棋,所以要有移动棋子的函数,最后还要有判断胜负的函数,到此基本就实现了一个井字棋的基本功能
接下来就直接看代码:
1.主函数
#include"game.h"
int main()
{//选择是否游戏
int a;
menu();
printf("请选择是否继续:");
//goto函数方便循环,大项目不建议使用易出错
again:
scanf("%d", &a);
switch (a)
{
case 1:game(); goto again; break;
case 0:printf("再次点击退出游戏!"); break;
default:printf("输入错误!请重新输入:"); goto again;
}
}
2.头文件
#pragma once
//定义棋盘大小
#define ROW 3
#define COL 3
#include<stdio.h>
#include<time.h>//用于时间戳生成真正的随机值
#include<stdlib.h>//用于生成伪随机值
//声明被调用函数
void menu();
void game();
3.函数实现
代码里有详细注释如有错误或疑问欢迎评论区讨论
#include"game.h"//调用宏定义和头文件
//菜单打印
void menu() {
printf("*******************************\n");
printf("********** 1.继续 ***********\n");
printf("********** 0.退出 ***********\n");
printf("*******************************\n");
}
//初始化棋子为空格
void initBoard(char board[ROW][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 i, j;
for (i = 0; i < ROW; i++)
{
//打印棋子和“|”
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 ply_move(char board[ROW][COL])
{
int a= 0,x=0,y=0;
while (1) {
printf("请输入你的坐标:");
scanf("%d", &a);
x = a / 10;
y = a % 10;
if (board[x - 1][y - 1] == ' ' && 1<= x &&x<= ROW && 1<= y&&y <= COL)
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("输入有误!");
}
}
}
//电脑走棋
void cpt_move(char board[ROW][COL])
{
srand((unsigned)time(NULL));//用时间戳生成真正的随机值
int x=0,y=0;
while (1)
{
x = rand() % 3;
y = rand() % 3;
if (board[x][y] == ' ')
{ board[x][y] = '#'; break; }
}
printf("电脑走棋 %d-%d 如下:\n",x+1,y+1);
}
//判断胜负或平局,只要某个符号连成线就返回那个符号
int judge(char board[ROW][COL])
{
int i , j ,count;
//判断行
for (i = 0; i < ROW; i++)
{
count = 0;
for (j=0; j < COL - 1; j++){if (board[i][j]==board[i][j+1])count++;}
if (count == COL - 1)return board[i][j];
}
//判断列
for (j = 0; j < COL; j++)
{
count = 0;
for (i = 0; i < ROW - 1; i++)
if (board[i][j] == board[i + 1][j])count ++;
if (count == ROW - 1)return board[i][j];
}
//判断正对角线
count = 0;
for (i = 0, j = 0; i < ROW - 1; i++, j++)
if (board[i][j] == board[i + 1][j + 1])count += 1;
if (count == ROW - 1)return board[i][j];
//判断副对角线
count = 0;
for (i = ROW-1, j = 0; i >=0; i--, j++)
if (board[i][j] == board[i -1][j + 1])count += 1;
if (count == ROW - 1)return board[i][j];
//判断是否满子
count = 0;
for (i = 0; i < ROW; i++)
for (j = 0; j < COL; j++)
if (board[i][j] == ' ')count += 1;
if (count == 0)return 1;
return ' ';
}
void game()
{//创建数组存放棋子
char board[ROW][COL];
initBoard(board);//初始化后打印棋子
displayBoard(board);
//循环走棋,得出结果后跳出死循环
while (1)
{//玩家走棋后打印
ply_move(board);
displayBoard(board);
//判断胜负玩家棋子为'*'棋子满了就是平局
if (judge(board) == '*'){printf("恭喜你赢了!\n"); break;}
else if (judge(board) == 1) { printf("平局!\n"); break; }
//电脑走棋后打印
cpt_move(board);
displayBoard(board);
//判断函数返回电脑棋子'#'则输了
if (judge(board) == '#'){printf("很遗憾,你输了!"); break;}
}
//每次下完提供选择是否继续
menu();
}
四、个人总结
- 首先就是思路要清晰,因为时间原因我没有将这个游戏的教学视频看完就着手写了,所以最开始写得很混乱,好在最后经过思路整理写出了这个不太一样的代码,只需要修改宏定义的两个数字就可以玩四子、五子等等
- 在写的过程中也可以对比其他人的代码,说不定其他人会有更好的思路
- 这个代码给我最大的收获应该就是数组传参的理解和代码模块化的思想
- 在使用循环判断时还不够熟练,下次思路一定要清晰,多多练习
五、改进建议
1.这里是玩家先手,可以用随机值决定先手
2.三子时,可以根据网络技巧使电脑立于不败之地
3. 后期学习图形库等知识再做一个美观的小游戏,我很期待!
那么好,此文到此便结束了,谢谢你的耐心阅读,希望你我都能不断有所收获!