目录
前言
经过前面的学习,我们终于到了一个能写简单代码的阶段。这里我将带领大家使用 C 语言来编写一个三子棋的小游戏,用来将前面的知识整合并且融会贯通。相信各位写完这个代码会对 C 语言有更浓厚的学校兴趣。车速太快,请系好安全带,上车,开整。
本文所使用到的代码与一些步骤的讲解板书:三子棋代码合集与板书
程序编写大纲
俗话说的好:只要思想不滑坡,办法总比困难多。
写代码的时候,我们应该先要构思出代码执行需要什么,根据需求我们再去作出判断。这里我将给大家带来一些我写这个三子棋小游戏程序的一些思路。
首先我们想这个游戏实现所需要的所需要什么?
- 开始游戏和退出游戏的这个页面。当确认开始游戏的时候,我们就会进入到下一步,当退出游戏的时候,我们就会退出这个程序。
- 当我们选择进入游戏的时候,我们就会去看这个棋盘,从而决定我下什么位置,打印棋盘(第一次棋盘上面应该啥也没有)。
- 假如说我们先我们作为先手去下棋。就是输入一个数值去。决定我下棋的位置并且在屏幕上打印我这个下棋的位置。
- 写一个代码程序。让机器人或者说人机去下棋。并且把它下的位置打印到屏幕上,以方便我们去做一些操作。
- 你来我往的下棋过程中,我们要去判断数去判断一些情况。就比如什么样的情况,电脑音什么样的情况,我们什么样的情况是平局。然后再给一个选项,是不是要重新再来一局?
这大概就是我们需要的一些去用代码解决的一些问题。然后解决了这些问题,我们这个代码才能说基本上去实现这个小游戏所需要的功能。
三字棋小游戏代码分解
一、开始游戏和退出游戏的页面
解释:
我们经过前面的知识可以知道 do…while 循环,就是循环必须进行一次。然后当我们进入这个游戏的时候,这个程序肯定是必然要进去一次的,所以这里我们选择 do…while 循环,然后当进入这个循环的时候,我们就打一个 menu 函数。这个 menu 函数让我们看到了一个菜单,然后让我们进行判断,根据我们输入的数字,从而进行决定程序的走向。
温馨提示:
注意:这里我为什么说 0 是退出游戏 ,1 是进入游戏?
因为我们后面的 do…while 循环的判断的条件是零为假,非零为真。所以为因为后面的我就是输入 0 的话,判断条件为假,直接终止循环。
void menu()
{
printf("*****************************\n");
printf("******** 1.开始游戏 *********\n");
printf("******** 0.退出游戏 *********\n");
printf("*****************************\n");
}
int main()
{
int input = 0;
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;
}
二、棋盘的打印与初始化
当我们第一次看到这个棋盘的时候,棋盘上面什么是没有棋子的,我们就可以用 空格 来代替上面什么都没有的情形,下面图片应该是我们常见的三子棋的字棋的情形。
经过我们仔细观察,认为可以用二维数字来控制这个行和列。利用二维数组的行和列进行下棋等操作。我们利用二维数组把棋盘下棋的地方输入为空格。
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
下面是我们展示这个棋盘的代码,因为上面的图片展示我们可以看出。每个下棋的地方都有东西相阻挡。为了做出这个阻挡的效果,我们就会有了以下代码。
void DisplayBoard(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
//当我们没有给row - 1、col - 1时候,它的最下面和最右边会多余出现 | 和 --- 出现
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
效果图:
三、玩家下棋
经过上面的初始化棋盘和打印棋盘,现在我们就可以开始。我们的下棋步骤了。
- 我们这边假设我们自己下棋是 * ,电脑下载是为 #。
- 这边我们再自己想一下,我是玩家,我就直接自己输入坐标的话,应该就是说输入的坐标应该是从 1 开始而不是从 0 开始的 。一般来说普通人不会知道二维数组这个东西。
- 我们根据所展示出来的棋盘从键盘上输入我要下棋的坐标,然后并且把我们输入之后的那个效果展示出来,这应该是玩家下棋的代码的基本思路。
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)
{//这边的x-1和y-1就是为了矫正二维数组的下标的问题,使*对应到正确的位置。
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请输入一个新的坐标。");
}
}
else
{
printf("坐标非法,请输入一个新的坐标。");
}
}
}
四、电脑下棋
现在是电脑下棋的代码。
首先的电脑也会输入两个数,当成坐标。因为是电脑下棋,所以这两个数应该是电脑随机生成的。
然后电脑生成的数成为的坐标也要在上面打印出来。所以这一步的关键是怎么让电脑伸出随机出来。
rand函数,这函数的作用就是生成库函数。使用这个函数要去搭配srand函数,这个函数里面需要一个可变的种子(参数),在日常生活中常见的也是时间是有变化的,这个时候我们可以使用time函数。(函数具体的参数和效果见本文版书部分)。
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;
//因为余数小于被除数的 假设row、col是3 取值范围0-2
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
五、判断胜负
通过上面的输出的效果来看,我们与电脑双方就下了一次,这样肯定是不合理的,这边我们可以把我们下棋、打印棋盘,电脑下棋、打印棋盘,这两个代码写成死循环,直到双方平局、玩家赢、电脑赢,利用这三种情况去跳出程序。
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 IsWinner(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 < col; 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[1][1] != ' ')
{//对角相等
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{//对角相等
return board[1][1];
}
//判断平局
if (IsFull(board, row, col))
{
return 'Q';
}
return 'C';
}
其它
1.三子棋小游戏代码实现分为三个模块
- 第一个模块是主要存放函数的定义和定义一些宏,还有一些头文件。
- 第二个模块是功能实现模块 里面存放的比如初始化数组。玩家下棋,电脑下棋,判断输赢等逻辑。
- 第三个模块利用函数的外部连接属性调用函数是代码逻辑更为明了。
2.本文的一些代码实验效果和一些代码分析都在板书部分有所讲解和展示。
3.本片的代码合集可以点击上面的链接进行查看。
第一个模块代码集合
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.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 PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWinner(char board[ROW][COL], int row, int col);
第二个模块代码集合
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋谱
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
//展示棋谱
void DisplayBoard(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
//当我们没有给row - 1、col - 1时候,它的最下面和最右边会多余出现 | 和 --- 出现
printf("\n");
if (i < row - 1)
{
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("坐标被占用,请输入一个新的坐标。");
}
}
else
{
printf("坐标非法,请输入一个新的坐标。");
}
}
}
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;
//因为余数小于被除数的 假设row、col是3 取值范围0-2
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//玩家赢 - '*'
//电脑赢 - '#'
//平局 --- 'Q'
//游戏继续-'C'
//
//判断输赢
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 IsWinner(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 < col; 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[1][1] != ' ')
{//对角相等
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{//对角相等
return board[1][1];
}
//判断平局
if (IsFull(board, row, col))
{
return 'Q';
}
return 'C';
}
第三个模块代码集合
void game()
{
char ret = 0;
char board[ROW][COL];
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋与打印
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWinner(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋与打印
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWinner(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
}
void menu()
{
printf("*****************************\n");
printf("******** 1.开始游戏 *********\n");
printf("******** 0.退出游戏 *********\n");
printf("*****************************\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
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;
}
后语
希望各位在翻阅过本篇文章各位能够对三子棋小游戏有所认识,并在看完之后能够把它写出来。
希望能对各位有所帮助,如果各位有任何疑问,欢迎各位留言,我们可以进行友好的探讨与交流。
欢乐的时间总是过得特别快。又到时间讲bye,我们下一篇再见!!!