C语言编写三子棋游戏:从概念到思路到实现
目录
一.文章概述
二.游戏规则概述
三.理解思路
1. 定义游戏数据结构
2. 游戏搭建思路及其步骤
·菜单选择列表:
·初始化棋盘:所有位置均为空格
·创建棋盘样式
·设置玩家下棋
·设置电脑下棋
·检查游戏状态:
四.代码示例
一.game.c部分
二.game.h部分
三.test.c部分
结论
一.文章概述
本文将深入探讨用C语言实现一个经典的双人策略游戏——三子棋(Tic Tac Toe)。我们不仅会详细解释游戏规则、数据结构选择,还会阐述如何设计和编码游戏的逻辑流程。通过本篇文章,读者能够理解如何从概念分析到具体代码实现,一步步构建出完整的三子棋游戏。
二.游戏规则概述
三子棋是一种经典的两人策略游戏,通常在一个3x3(本次代码可以随意更改棋盘大小)的网格上进行。玩家轮流放置他们的标记(这里代码玩家下棋用“*”,电脑下棋用“#”来示例),目的是在横行、竖列或斜对角线上获得三个连续的标记及为获胜。
1.一个玩家形成一条直线上的三个标记。
2.所有的格子都被占用(平局)。
三.理解思路
1. 定义游戏数据结构
创建一个二维数组来表示棋盘。使用字符型数组
//存放数据需要一个3*3的二维数组char board[ROW][COL] = {0};
来存储每个位置的棋子,其中 ‘’, ‘*’, 和 ‘#’分别代表空位、玩家和电脑。
2. 游戏搭建思路及其步骤
·菜单选择列表:
//声明菜单是menu定义格式
void menu()
{printf("*******************************\n");printf("******** 1. play ******\n");printf("******** 0. exit ******\n");printf("*******************************\n");
}
·初始化棋盘:所有位置均为空格
//初始化棋盘InitBoard(board, ROW, COL);
//方法一
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] = ' ';}}
}
//方法二
void InitBoard(char board[ROW][COL], int row, int col)
{memset(&board[0][0], ' ', row*col*sizeof(board[0][0]));
}
·创建棋盘样式
void DisplayBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 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");}
}
·设置玩家下棋
使用循环结构(如 while
循环)来处理玩家和电脑输入,询问玩家和电脑选择的位置并验证。通常需要一个函数来接受用户输入的行和列,并转换为有效的数组索引。
//判断玩家下棋输入坐标是否符合要求
//若符合要求,则判断该位置是否是没有超出棋盘范围的
//若没有超出且该位置是空的,玩家就下棋
//为了能达成赢,输,平局三种其一的局面
//需要while不停的循环
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;int y = 0;printf("电脑下棋>:\n");while (1){//假如row=9//rand()%row=0-8//那么+1就是1-9x = rand() % row;y = rand() % col;if (board[x][y] == ' '){board[x][y] = '#';break;}}
}
·检查游戏状态:
需要有函数来检查游戏是否结束(是否有胜者或平局)和验证下棋操作的有效性(确保不是重复落子、非空位等)。
//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'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 (IsFull(board, row, col)){return 'Q';}//游戏继续return '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] == ' '){//没有空格子了就直接返回0终止程序return 0;}}}//继续下棋return 1;
}
四.代码示例
一.game.c部分
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"void InitBoard(char board[ROW][COL], int row, int col)
{int i,j;//方法一//for (i = 0; i < row; i++)//{// for (j = 0; j < col; j++)// {// //刚开始棋盘上是什么都没有的// board[i][j]=' ';// }//}//方法二 包含头文件#include "string.h"//函数规定将&/*部分指向的地方前多大空间转化为空格(' ')memset(&board[0][0], ' ', row * col * sizeof(board[0][0]));}//void DispalyBoard(char board[ROW][COL], int row, int col)
//{
// int i, j;
//
// for (i = 0; i < row; i++)
// {
// //写死了只能打印3列
// printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);
// if (i < row - 1)
// {
// printf("---|---|---\n");
// }
// }
//
//}void DispalyBoard(char board[ROW][COL], int row, int col)
{int i, j;//灵活变换的棋盘for (i = 0; i < row; i++){//把一个字符和一个竖杠看作一组//---|---|---//那么最后一组没有‘|’//先打印数据和|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 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;int y = 0;printf("电脑下棋:>\n");//随机函数while (1){x = rand() % row;y = rand() % col;if (board[x][y] = ' '){board[x][y] = '#';break;}}
}//判断棋盘是否满了
int Is_Full(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;
}//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//继续 - 'C'
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];}}///判断主副对角线//为什么要是board[1][1] != ' ',board[0][0] != ' '不可以吗,前面不都是判断了board[1][1] ==board[0][0]//因为他是中间相互公共部分,是00或者22的话//意思就是如果要改的话,主副对角线就要检查对角位置就可以了,用中心检查是为了提高代码效率而已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';
}
二.game.h部分
#pragma once//头文件的包含
#include <string.h>
#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 IsWin(char board[ROW][COL],int row, int col);
三.test.c部分
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"void menu()
{printf("***** 请 选 择 *****\n");printf("***** 1.play 0.exit *****\n");printf("**************************\n");
}void game()
{//如果是这样的话,确实打印出了棋盘//但是直接打印的话那么如何落子输入?/*printf(" | | \n");printf("--|--|--\n");printf("__|__|__\n");printf(" | | \n");*///运用数组解决问题//存放一个3*3的数组char board[ROW][COL] = { 0 };char ret = 0;//初始化棋盘InitBoard(board, ROW, COL);//打印棋盘DispalyBoard(board, ROW, COL);while (1){//下棋//玩家下PlayerMove(board, ROW, COL);//打印DispalyBoard(board, ROW, COL);//判断输赢ret=IsWin(board, ROW, COL);if (ret != 'C'){//在这里不判断谁赢//当不平局直接跳出,再进行判断//节省了代码break;}//电脑下ComputerMove(board, ROW, COL);//打印DispalyBoard(board, ROW, COL);//判断输赢ret = IsWin(board, ROW, COL);if (ret != 'C'){break;}}if ('*' == ret){printf("玩家赢\n");}else if ('#' == ret ){printf("电脑赢\n");}else if ('C' == ret){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;
}
结论
这个简单的C语言程序实现了三子棋的基本功能:定义游戏数据结构、游戏搭建思路及其步骤、检查胜利条件和切换玩家等。使用标准输入输出函数进行人机交互,并通过数组来管理棋盘状态。
我期待这篇博客示例能为你提供宝贵的思路和指导,在使用C语言构建三子棋游戏的过程中遇到问题时找到有效的解决方案。在这段旅程中,请记住,正确地挑选并应用合适的函数是关键所在——这一点在实际编程过程中尤为重要。通过合理选择这些功能,你可以确保程序不仅高效而且易于维护。希望这个资源能成为你编程之旅中的得力助手,并激发你进一步探索和优化代码的热情。