目录
一.初步设想
1.游戏不退出,继续玩下一把(循环)
2.应用多文件形式写代码
分为三个文件:test.c -- 测试游戏的
game.c -- 游戏函数的实现
game.h -- 游戏函数的声明
先实现第一个
在test.c里面加入这段代码,玩家可以多次玩游戏
#include <stdio.h>
#include "game.h"
void menu()
{
printf("*****************************\n");
printf("******** 1. play *********\n");
printf("******** 0. exit *********\n");
printf("*****************************\n");
}
void game()
{
}
int main()
{
int input = 0;//放到相对全局的位置
do
{
menu();
printf("请选择:>");
scanf("%d", &input);//1 0 4
switch (input)
{
case 1:
game();
printf("玩三子棋\n");
break;
case 2:
printf("推出游戏\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
我们先看看三子棋的棋盘大概长什么样
从棋盘我们可以发现 ,这是一个3×3的棋盘,每一步棋(每一个位置)都要存起来,所以需要一个二维数组char board[3][3],而且要保证没下棋前数组存放空格,最终要达到这种效果
二. 版本1(尝试阶段)
在game.c里面放入这个代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(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] = ' ';
}
}
}
//版本1
void DisplayBoard(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]);
}
printf("\n");
}
}
game.h里面放入这段代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#define ROW 3
#define COL 3
void InitBoard(char borad[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
其中InitBoard是初始化棋盘,DisplayBoard是打印棋盘,我们来看看打印效果如何
怎么什么都没有?!
原来在game.c文件里面的这两段代码把整个棋盘打印成空的了
把它改成x这个简单的3×3数组棋盘就显示出来了
但是这还达不到我们的要求,让我们进入下一个版本
三.版本2
仔细观察棋盘,我们其实可以这么打印
在打印数据那里,其实我们需要把数据放在中心,所以我们可以这样操作“空格+字符+空格+|”
分割线就这样打印“---|---|---”
到第三行我们不用打印分割线我们就在分割线打印那里进行两次循环就行。
修改的DisplayBoard如下:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//1.打印数据
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//2.打印分割线
if (i < row -1)
printf("---|---|---\n");
}
}
达到我们的棋盘效果啦~
但是这只是针对3×3的棋盘,如果我们把行和列都改成10,那打印出来的棋盘长这样
原因是我们在DisplayBoard函数里面的打印数据把这个棋盘限死了
所以我们再改一下 ,进入第三个版本
四. 版本3
我们可以这样想
前i行打印 “数据+|数据+|数据+|”,到最后一行打印“|”
分割线也一样
修改后的DisplayBoard如下:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//1.打印数据
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2.打印分割线
if (i < row - 1)
{
/*printf("---|---|---\n");*/
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
就可以达到这个效果啦~
好,我们把行和列改成3,开始下棋
五. 玩家下棋
我们创建一个PlayerMove函数专门用于玩家下棋
(当然在test.c和game.h里面要传入对应函数)
//game.c
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
while (1)
{
printf("请输入下棋的坐标,中间使用空格>:");
scanf("%d %d", &x, &y);
//坐标合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')//可以落子
{
board[x - 1][y - 1] = '*';
break;
}
else//不能落子
{
printf("坐标备战有,不能落子,请重新输入坐标\n");
}
}
else//非法
{
printf("坐标非法,请重新输入\n");
}
}
}
至于这里的x和y为什么要减1,因为玩家不都是程序员,他们不知道一个数组第一个数下标是0,他们只知道1是第一个数,3是最后一个数,为了对应位置,我们在处理上给他们减个1.
//test.c
//下棋
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//电脑下棋
}
现在能达到这个效果,就差一个电脑下棋啦
六.电脑下棋
我们给让电脑随机在棋盘上面下,下的棋子为#
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;//0到row-1
int y = 0;//0到col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = "#";
break;
}
}
}
同时game.h 和 test.c里面也要加上ComputerMove函数
七. 判断谁能赢
现在有四种情况:玩家赢,电脑赢,平局,还没下完继续
所以我们定义一个Iswin函数来判断胜负情况
//判断输赢,用下面字母符号代替
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'
先来判断赢的情况
//赢
//行
int i = 0;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
//列
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
{
return board[0][2];
}
因为玩家赢就返回 ’*‘ 而电脑赢就返回’#‘,这刚好是他们下的棋子,所以直接返回棋盘坐标就行
平局情况需要设置一个IsFull函数来判断棋盘是不是满的
int IsFull(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
接着在Iswin函数里面调用这个函数
//平局
if (IsFull(board, row, col) == 1)
{
return 'Q';
}
以上情况都没有,就继续游戏
//继续
return 'C';
这样我们的游戏就写完了
游戏效果大致是这样
八.三个文件的源代码
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(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] = ' ';
}
}
}
//版本1
//void DisplayBoard(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]);
// }
// printf("\n");
// }
//}
//版本2
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
// int i = 0;
// for (i = 0; i < row; i++)
// {
// //1.打印数据
// printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
// //2.打印分割线
// if (i < row -1)
// printf("---|---|---\n");
// }
//}
//版本3
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//1.打印数据
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2.打印分割线
if (i < row - 1)
{
/*printf("---|---|---\n");*/
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
while (1)
{
printf("请输入下棋的坐标,中间使用空格>:");
scanf("%d %d", &x, &y);
//坐标合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')//可以落子
{
board[x - 1][y - 1] = '*';
break;
}
else//不能落子
{
printf("坐标备战有,不能落子,请重新输入坐标\n");
}
}
else//非法
{
printf("坐标非法,请重新输入\n");
}
}
}
//
//电脑随机下棋
//
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;//0到row-1
int y = 0;//0到col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = "#";
break;
}
}
}
int IsFull(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char Iswin(char board[ROW][COL], int row, int col)
{
//赢
//行
int i = 0;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
//列
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
{
return board[0][2];
}
//平局
if (IsFull(board, row, col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//初始棋盘
void InitBoard(char borad[ROW][COL], int row, int col);
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'
char Iswin(char board[ROW][COL], int row, int col);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
void menu()
{
printf("*****************************\n");
printf("******** 1. play *********\n");
printf("******** 0. exit *********\n");
printf("*****************************\n");
}
void game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//下棋
char ret = 0;
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
int main()
{
int input = 0;//放到相对全局的位置
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);//1 0 4
switch (input)
{
case 1:
game();
printf("玩三子棋\n");
break;
case 2:
printf("推出游戏\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}