前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >三子棋——年轻人的第一款小游戏

三子棋——年轻人的第一款小游戏

作者头像
北 海
发布2023-07-01 10:38:18
1430
发布2023-07-01 10:38:18
举报
文章被收录于专栏:用户10155340的专栏


前言

  经过一段时间的学习,分支与循环、数组与函数的相关知识已经足够支撑我们完成一个小游戏了,这个小游戏不需要太多的功能,也不需要太复杂的逻辑,只需要懂点循环与分支,懂点数组的使用以及函数如何传参和返值即可。作为草稿纸上常出现的小游戏,三子棋的逻辑可谓是非常简单了,只需要玩家走一步、电脑走一步,并在八种可能获胜结果中比对就行了,下面让我们一起来看看三子棋的实现。

  注意:本文为模拟游戏实现,代码量两百左右,共有两个源文件+一个头文件。

正文

本程序一共就下面三个文件

主函数部分(test.c)

 我们直接从主函数开始!

 下面看看game(游戏)函数的设计

代码语言:javascript
复制
//三子棋
#include"game.h"
void menu()
{
	printf("**************************\n");
	printf("********  1.Play  ********\n");
	printf("********  0.Exit  ********\n");
	printf("**************************\n");

}
void game()
{
	char board[ROW][COL] = { 0 };//定义
	init_board(board, ROW, COL);//初始化
	display_board(board, ROW, COL);//打印
	//下棋
	char tmp = 0;
	while (1)
	{
		player_move(board, ROW, COL);//玩家走
		display_board(board, ROW, COL);//打印
		tmp=who_win(board, ROW, COL);//判断
		if (tmp != 'C')
			break;

		computer_move(board, ROW, COL);//电脑走
		display_board(board, ROW, COL);//打印
		tmp=who_win(board, ROW, COL);//判断
		if (tmp != 'C')
			break;
	}
	if (tmp == '*')
		printf("玩家获胜\n");
	else if (tmp == '#')
		printf("电脑获胜\n");
	else
		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;
}

 主函数文件(test.c就介绍完了),下面介绍game.h这个头文件

头文件部分(game.h)

这个头文件是自己建立的,目的就是在主函数源文件(test.c)和功能实现函数(game.c)中搭起一座沟通的桥梁。

代码语言:javascript
复制
#pragma once
#include<stdio.h>
#include<stdlib.h>

#define ROW 3
#define COL 3

void init_board(char board[][COL],int row,int col);//初始化

void display_board(char board[][COL], int row, int col);//打印

void player_move(char board[][COL], int row, int col);//玩家走

void computer_move(char board[][COL], int row, int col);//电脑走

char who_win(char board[][COL], int row, int col);//判断

自定义头文件部分代码量最少,功能也比较简单,如果说test.c是大脑、控制中心,那么game.h就相当于神经系统的一部分,是函数间沟通的桥梁,能对函数起主导作用。

功能实现函数部分(game.c)

此部分是程序运行必不可少的部分,没有它们,程序能跑,但什么都干不了,类似于植人。 本部分函数细节较多,因此我会分开逐个讲解。 

 1.初始化函数

 初始函数主要就是把整个数组遍历一遍,然后将字符 空格 (' ')赋给每个数组即可。

代码语言:javascript
复制
void init_board(char board[][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] = ' ';//初始化数组为空格' '
		}
	}
}

2.打印棋盘函数

打印棋盘函数需要思考下:什么情况打印 | 和 什么情况打印 --- ,不想清楚这些问题就无法打印出优美的棋盘。

代码语言:javascript
复制
void display_board(char board[][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]);//放置数组至棋盘
			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");
		}
	}
}

3.玩家移动函数

玩家移动就是让玩家输入坐标,输入坐标有三种情况:非法、占用、成功,依次判断即可,其次要注意不是人人都知道坐标从0开始,因此在使用x、y时要减1,确保坐标不会越界。

代码语言:javascript
复制
void player_move(char board[][COL], int row, int col)//玩家走
{
	int x = 0;
	int y = 0;
	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");
	}
}

4.电脑移动函数

电脑移动不要太多判断,只需要给电脑一个随机值,一个判断条件。 直到电脑落子成功再跳出即可

代码语言:javascript
复制
void computer_move(char board[][COL], int row, int col)//电脑走
{
	printf("轮到电脑落子:>");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	printf("电脑已落子\n");
}

5.判断输赢函数

这个函数出现于玩家或电脑移动之后,目的就是判断是否已达成胜利条件(共八种),如果达成了,就能跳出game函数中的死循环,结束游戏。

 注意:本程序中函数就判断输赢函数和判断和局函数有返回值,一个是char,一个是int

代码语言:javascript
复制
int place(char board[][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 who_win(char board[][COL], int row, int col)//判断
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && 
			board[i][1] == board[i][2] && board[i][2] != ' ')
			return board[i][0];
	}//判断行

	for (j = 0; j < row; j++)
	{
		if (board[0][j] == board[1][j] &&
			board[1][j] == board[2][j] && board[2][j] != ' ')
			return board[0][j];
	}//判断列

	if (board[0][0] == board[1][1] && 
		board[1][1] == board[2][2] && board[2][2] != ' ')
		return board[0][0];//判断正斜

	if (board[0][2] == board[1][1] && 
		board[1][1] == board[2][0] && board[2][0] != ' ')
		return board[0][2];//判断反斜

	if (place(board, ROW, COL) == 1)
		return 'Q';//判断和局

	return 'C';//默认选项
}

6.重回game函数

经过game.c中各函数的一顿操作,最终由判断输赢函数携带返回值回到game函数进行判断

效果展示

让我们直接来看看效果如何:

可以看到三种情况都能实现,现在只需要将代码进行优化,主要是优化输赢判断部分,使其兼容性更强,以后在玩五子棋时能沿用这套方案。 

 下面我将展示功能实现函数(game.c)的全部代码:

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1	
#include"game.h"

void init_board(char board[][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] = ' ';//初始化数组为空格' '
		}
	}
}

void display_board(char board[][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]);//放置数组至棋盘
			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 player_move(char board[][COL], int row, int col)//玩家走
{
	int x = 0;
	int y = 0;
	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 computer_move(char board[][COL], int row, int col)//电脑走
{
	printf("轮到电脑落子:>");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
	printf("电脑已落子\n");
}

int place(char board[][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 who_win(char board[][COL], int row, int col)//判断
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && 
			board[i][1] == board[i][2] && board[i][2] != ' ')
			return board[i][0];
	}//判断行

	for (j = 0; j < row; j++)
	{
		if (board[0][j] == board[1][j] &&
			board[1][j] == board[2][j] && board[2][j] != ' ')
			return board[0][j];
	}//判断列

	if (board[0][0] == board[1][1] && 
		board[1][1] == board[2][2] && board[2][2] != ' ')
		return board[0][0];//判断正斜

	if (board[0][2] == board[1][1] && 
		board[1][1] == board[2][0] && board[2][0] != ' ')
		return board[0][2];//判断反斜

	if (place(board, ROW, COL) == 1)
		return 'Q';//判断和局

	return 'C';//默认选项
}

总结 

  我们本次三子棋之旅到这就要结束了,说实在的,三子棋这段代码蕴含逻辑比较简单,唯一需要注意的就是棋盘打印和电脑随机值,只有理解透彻了,代码敲起来才能得心应手!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正文
    • 主函数部分(test.c)
      • 头文件部分(game.h)
        • 功能实现函数部分(game.c)
          •  1.初始化函数
          • 2.打印棋盘函数
          • 3.玩家移动函数
          • 4.电脑移动函数
          • 5.判断输赢函数
          • 6.重回game函数
        • 效果展示
        • 总结 
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档