学c也学了有一些时间了,今天用c语言做了一个小游戏——井字棋。相信大家也玩过。我们这个游戏的思路呢,是玩家和电脑对弈。谁先把三颗棋子连成一条线,谁就赢了。如下图所示:
要想实现我们这个井字棋需要用到数组的知识,所以,老规矩我们先简单的把数组讲一下:
数组:数组是一组相同类型元素的集合。
数组的创建方式: type_t? ?arr_name? [const_n];
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // type_t? 是指数组的元素类型
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //const_n? ?是一个常量表达式,用来指定数组的大小
数组的创建实例:
int arr1[10];
char arr2[10];
char arr3[10];
数组初始化:
#include<stdio.h>
#include<stdlib.h>
int main(){
//初始化方法一:
int arr1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//初始化方法二:
int arr2[] = {1, 2, 3};
//初始化方法三:
char arr3[10];
int i = 0;
for(i = 0; i < 10; i++){ // 利用for循环将arr3数组中的所有值初始化为'a';
arr3[i] = 'a';
}
return 0;
}
数组的使用:如果想要使用数组中的元素可以通过访问数组的下标来获取数组中的某一个元素
#include<stdio.h>
int main(){
int arr[10] = {0}; // 数组的不完全初始化
// 计算数组的元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
// 对数组内容赋值,数组是使用下标来访问的,下标从0开始。
int i = 0; // 做下标
for(i = 0; i < sz; i++){
arr[i] = i;
}
// 输出数组的内容
for(i = 0; i< sz; i++){
printf("%d", arr[i]);
}
return 0;
}
二维数组的创建:
int arr[3][4];
char arr[3][5];
double arr[2][4];
二维数组的初始化:
int arr[3][4] = {1, 2, 3, 4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3}, {4,5}};
二维数组的使用:
#include<stdio.h>
int main{
int arr[3][4] = {0};
int i = 0;
for(i = 0; i < 3; i++){
int j = 0;
for(j = 0; j < 4; j++){
arr[i][j] = i*4+j;
}
}
for(i = 0; i < 3; i++){
int j = 0;
for(j = 0; j < 4; j++){
printf("%d", arr[i][j]);
}
}
return 0;
}
PS:数组创建,[ ]中要给一个常量才可以,不能使用变量
游戏开始
游戏开始我们得让玩家自己选择是玩游戏还是退出,所以我们得打印一个游戏头,让玩家知道有哪些选项以及怎么进入那些选项代码如下:
// 打印游戏头
void game_head() {
printf("####################\n");
printf("# 1.PLAY #\n");
printf("# 0.EXIT #\n");
printf("####################\n");
}
这段代码执行出来得效果是这样的:
?游戏头搞定了,这下玩家就知道了有哪些选项,这个时候我们就得让玩家来选择,就得让玩家输入1或者0来玩游戏或退出游戏,因为是多条件所以我们使用switch语句。此外,可能玩家在玩了一局之后还想玩第二局,所以我们得把这些代码写到一个循环中。代码如下:
#include<stdio.h>
int main(){
int input = 0; //让玩选择1 play 或者 0 exit
do{
game_head();
printf("请输入1开始游戏>>");
scanf("%d", &input);
switch(input){
case 1:
printf("开始玩游戏\n");
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("没有这个选项,请重新输入\n");
break;
}
}while(input != 0);
}
?运行结果如下:?
?到这一步,这个游戏大的框架就成型了。接下来我们就来实现游戏的功能,首先我们要把井字棋的棋盘先打印出来。这就需要我们用到二维数组,我们先创建一个字符二维数组,并把它初始化为全是空格的数组。为什么要用字符数组呢?那是因为我们这个数组里面存放的是玩家下的棋子和电脑下的棋子。大概的意思如下图:
#define ROW 3 //宏定义的常量,此时ROW == 3
#define COL 3 //宏定义的常量,此时COL == 3
char arr[ROW][COL]; // 这里我是将数组定义为一个全局变量,就在程序的任何地方可以直接使用
// 初始化数组
void init(){
int i = 0;
int j = 0;
for(i = 0; i < ROW; i++){
for(j = 0; j < COL; j++){
arr[i][j] = ' ';
}
}
}
初始化数组之后,就把棋盘打印出来。我们知道棋盘除了要体现玩家和电脑下棋的数据以外还有一些分割线。所以我们打印棋盘的思路就是,下棋的数据和分割线一起打印。在打印每一行前两个数据的时候在数据的后面加一个' | ',把每个数据分割开。再在前两行打印完后增加一行’ -----------‘这样的短线,把每一行数据分割开。具体代码实现如下:
void map() {
system("CLS"); //这一行是清屏的代码
int row = 0;
int col = 0;
for (row = 0; row < ROW; row++) {
for (col = 0; col < COL; col++) {
if (col < COL - 1) {
printf(" %c |", arr[row][col]);
}
else {
printf(" %c \n", arr[row][col]);
}
}
if (row < ROW - 1) {
for (col = 0; col < COL; col++) {
printf("----");
}
}
printf("\n");
}
}
当我们把打印地图的函数写到我们的游戏主函数中去时,它的效果是这样的:
#include<stdio.h>
#include"game.h"
int main() {
int input = 0; //让玩选择1 play 或者 0 exit
do {
game_head();
printf("请输入1开始游戏>>");
scanf("%d", &input);
switch (input) {
case 1:
map(); // 调用打印棋盘的函数
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("没有这个选项,请重新输入\n");
break;
}
} while (input != 0);
}
解决了棋盘的事要怎么下棋呢?我们设计的函数是让用户输入要下的那个位置的坐标,然后就把数组中对应坐标的数据改成‘ X ’。要考虑几个特殊情况,就是用户输入的位置已经被下了,另一个情况就是用户输入的坐标根本不存在。函数的实现如下:
void play_game() {
int x = 0;
int y = 0;
while (1) {
printf("请输入坐标>");
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= ROW) && (y >= 1 && y <= COL)) {
if (arr[x - 1][y - 1] == ' ') {
arr[x - 1][y - 1] = 'X';
break;
}
else {
printf("这个地方已经下过了,请重新输入\n");
}
}
else {
printf("输入不合法,请重新输入\n");
}
}
}
玩家落子之后,就该电脑下棋了,电脑我是用rand()函数来实现,rand函数的作用是生成随机数,在使用前要使用srand()函数来设置一下,要不然rand()函数是由规律的生成一些数,就不是随机的。电脑下棋的代码如下:
srand((unsigned int)time(NULL)); // 这段代码写在主函数中,这里是为了方便说明
void cmp_game() {
int cmp_x = 0;
int cmp_y = 0;
while (1) {
if (is_end() != -1) {
break;
}
cmp_x = rand() * 10 % 3;
cmp_y = rand() * 10 % 3;
if (arr[cmp_x][cmp_y] == ' ') {
arr[cmp_x][cmp_y] = 'O';
break;
}
}
}
下棋的操作实现之后,就得看看谁输谁赢了,我们知道井字棋的输赢就是看哪一方先有三颗子连成一条线。这个数据我们可以在数组中得到,所以输赢的判断就是连数组中相邻的三个位置所存放的数据是否相等,然后返回那个数据,代码如下:
char is_win() {
if ((arr[0][0] == arr[1][0] && arr[1][0] == arr[2][0] && arr[0][0] != ' ')||
(arr[0][0] == arr[0][1] && arr[0][1] == arr[0][2] && arr[0][0] != ' ')) {
return arr[0][0];
}
if ((arr[0][1] == arr[1][1] && arr[1][1] == arr[2][1] && arr[0][1] != ' ') ||
(arr[1][0] == arr[1][1] && arr[1][1] == arr[1][2] && arr[1][0] != ' ') ||
(arr[2][0] == arr[1][1] && arr[1][1] == arr[0][2] && arr[0][2] != ' ')||
(arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[0][0] != ' ')) {
return arr[1][1];
}
if ((arr[0][2] == arr[1][2] && arr[1][2] == arr[2][2] && arr[0][2] != ' ') ||
(arr[2][0] == arr[2][1] && arr[2][1] == arr[2][2] && arr[2][0] != ' ')) {
return arr[2][2];
}
return ' ';
}
最终将我们的主函数完善,因为下棋是一步一步下,所以我们就用一个循环将我们的下棋操作包起来:
#include "game.h"
int main() {
int input = 0;
int cmp_x = 0;
int cmp_y = 0;
srand((unsigned int)time(NULL));
do {
game_head();
printf("输入1开始游戏>>");
scanf("%d", &input);
InitMap(arr, ROW, COL);
switch (input) {
case PLAY:
map();
while (is_end() == -1) {
play_game();
map();
cmp_game();
map();
}
if (is_win() == 'X') {
printf("玩家获胜\n");
}
else if (is_win() == 'O') {
printf("电脑获胜\n");
}
else {
printf("平局\n");
}
break;
case EXIT:
printf("游戏结束!\n");
break;
default:
printf("输入不合法,请重新输入\n");
}
} while (input != 0);
return 0;
}
如果需要完整的代码可以访问我的gitee:
https://gitee.com/damiing/game
|