C语言实现三子棋

2024-01-23 14:48:23 浏览数 (1)

1.题目描述

  1. 三子棋,民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙等。
  2. 将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。

2.功能实现

想要用c语言完成,就得一步一步将所需实现的功能拆开,逐步实现(切记不可一步到位)。

1.开始界面

可以用一系列输出函数将开始界面进行输出,1为开始游戏,0为退出游戏,同时在主函数里进行调用,为了防止输入一次就结束运行,可用do while循环,先循环一次,再根据输入的是1还是0判断是否继续进行循环。

开始菜单函数。

代码语言:javascript复制
void menu() {
	printf("***************************n");
	printf("**********1.play**********n");
	printf("**********0.exit***********n");
	printf("***************************n");
}

主函数

代码语言:javascript复制
int main() {
	int input;
	srand((unsigned int)time(NULL));\用于随机数的生成器,后面会有解释
	do {                            \先进行一次循环,再根据input值进行判断是否继续
		menu();
		printf("请选择:n");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏n");
			break;


		default:
			printf("选择错误,请重新选择n");
			break;
		}



	} while (input);
		return 0;
}

有了开始菜单和输入功能,接下来就可以进行游戏功能实现了。

2.游戏功能

开始游戏功能实现前,我们需要明确它需要实现的功能有哪些。既然下棋,就得有棋盘吧,还得有旗子吧,最后还得有对手吧,这些我们来一一明确。

1.棋盘

可以知道的是,棋盘是一个3*3的矩阵方格,由纵线和横线划分成每一个方格。这里可以用一个二维数组来存放,在这里我们采用空格存放来达到初始化棋盘的目的,并在每一个数组的位置打印相应的线段来达到划分棋盘的效果,而棋盘的头部和尾部不需要进行划分线,所以在遍历时进行判断是否到达底部,否则打印。

代码语言:javascript复制
void Initboard(char board[ROW][COL], int row,int col) {
	int i = 0;
	for (i = 0; i < row; i  ) {
		for (int j = 0; j < col; j  ) {
			board[i][j] = ' ' ;

		}
	}
}
void Displayboard(char board[ROW][COL], int row, int col) {
	int i = 0;
	for (i = 0; i < row; i  ) {
		//先打印数据
		printf(" %c | %c | %c n", board[i][0], board[i][1], board[i][2]);
		//打印分割行
		if(i<row-1) printf("---|---|---n");//只打印前两行 
		}
		printf("n");
	}

细心的老铁们可能已经看到,打印棋盘的代码只能满足3*3的棋盘,万一以后需要扩大玩法的话,效率并不是很高,所以我们直接进行对于所传入数组(行与列)进行遍历与判断,先打印数据,在打印分割行,这样就可以更加灵活与方便的进行棋盘的调整。

代码语言:javascript复制
void Displayboard(char board[ROW][COL], int row, int col) {
	int i = 0;
	for (i = 0; i < row; i  ) {
		//先打印数据
		for (int j = 0; j < col; j  ) {
			printf(" %c ", board[i][j]);
			if (j < col - 1) printf("|");
		}
		printf("n");
		//打印分割行
		if (i < row - 1) {
			for (int j = 0; j < col; j  ) {
				printf("---");
				if (j < col - 1) printf("|");
			}

		}
		printf("n");
	}
}
2.下棋

(玩家用*表示,电脑用#表示)这里很清楚的是,我们得通过输入棋盘相应的坐标来达到下棋的目标。其次还要对该坐标进行判断,如果上面已经有棋子了,那就得重新下。这里要注意,编译器与我们所输入的坐标不同的区别在于电脑下标从0开始,而我们输入的是1开始(不能保证玩的都是程序员)所以修改的坐标也有讲究。

这是玩家。

代码语言:javascript复制
void PlayerMove(char board[ROW][COL], int row, int col) {
	int x, y;
	printf("玩家下棋n");
	while (1) {
		printf("请输入要下棋的坐标:>");
		scanf_s("%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");
		}
	}

	
		 
}

电脑下棋

对于编译器来说,达到下棋的目的便是能够让他随机生成一个坐标,并往里面放入#。这里需要考虑的是1.如何生成随机数;2.控制生成坐标的范围;3.考虑该坐标上是否有棋子

1.针对随机数的情况,我们可以利用srand函数配合time函数(time函数的作用是生成一个时间戳,用于给srand提供可变参数,srand是随机数生成器)来生成随机数,利用rand函数生成相应坐标,为了控制范围,给生成数对行和列求余,同时进行判断相应坐标上是否有棋子

(ps:time函数和srand需要time.h和stalib.h头文件)

代码语言:javascript复制
void ComputerMove(char board[ROW][COL], int row, int col) {
	printf("电脑下棋n");
	int x = 0;
	int y = 0;
	while (1) {
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ') {
			board[x][y] = '#';
			break;
		}
	}

}
3.判断结果

对于结果来说,无非三种,输、赢、平局。

这里采用了对返回值进行判断来输出相应的结果(输出*,玩家赢,#则电脑赢,否则平局)。

赢的条件,任意棋子满足横竖或对角线即可,我们可以对数组所存放的值与位置进行判断,如果满足,返回对应棋子,如果都没有满足,则进行平局判断,通过对里面的空格数进行判断,如果都没有,则说明棋盘已满,且同时没有满足输赢条件,输出平局。

代码语言:javascript复制
static int is_full(char board[ROW][COL], int row, int col) {//判断平局函数
	for (int i = 0; i < row; i  ) {
		for (int 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 < 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 (is_full(board, row, col)) {
		return 'Q';
	}
	return 'C';
}

相关代码

1.测试代码

代码语言:javascript复制
#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 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=Iswin(board,ROW,COL);
		if (ret != 'C') {
			break;
		}

		ComputerMove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		//判断输赢
		if (ret != 'C') {
			break;
		}
	}
	if (ret == '*') {
		printf("玩家赢n");
	}
	else if (ret == '#') {
		printf("电脑赢n");
	}
	else {
		printf("平局n");
	}


}




int main() {
	int input;
	srand((unsigned int)time(NULL));
	do {
		menu();
		printf("请选择:n");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏n");
			break;


		default:
			printf("选择错误,请重新选择n");
			break;
		}



	} while (input);
		return 0;
}

2.头文件代码

代码语言:javascript复制
#pragma once
#define ROW 3
#define COL 3
#include<time.h>
#include<stdlib.h>
#include<stdio.h>
//初始化棋盘
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 Iswin(char board[ROW][COL], int row, int col);

编码相关小技巧

1.如果所需要的头文件过多,可以单独用一个头文件涵盖,在调用时就可以全部调用到,效率特高。

2.对于自定义函数功能的实现,也可以在自己的头文件里进行声明,也可大大提高效率。

3.如果编写的代码功能过多,可以一步一步来实现,切不可一步到位,从简到难更能加深思维的强化与理解。

(ps:新人博主,第一次写博客,还有些不熟悉,请多多指教(害羞))

0 人点赞