首页 > 其他分享 >c语言实现三子棋

c语言实现三子棋

时间:2023-01-11 15:33:43浏览次数:41  
标签:语言 实现 三子 COL int board ROW col row

前言:

在此之前我们学习了循环,函数,数组等相关知识,我们来写一个小游戏练练手

概述:

代码大致分为三部分程序主函数,函数,声明函数(这一点我们在通讯录项目是就介绍过了,将代码分为三部分可以是代码各司其职,不冗余,可读性高),游戏框架大概分为以下几部分,主函数main,菜单函数,初始化棋盘,打印棋盘,玩家走函数,电脑走函数,判断输赢函数,所以我们也会按照这几个部分来讲解,先给大家演示一下,我们是通过输入坐标的形式来落子

c语言实现三子棋_#include

程序主函数(course-8.c)

main程序入口

我们先搭建好程序的主体部分,然后在慢慢添加相应功能,这里进入主函数然后调用test函数

int main()
{
test();
return 0;
}

test函数

在test函数中我们可以加入菜单和根据用户输入判断出对应的不同提示语句,

srand((unsigned int)time(NULL));这句代码我们在猜数字游戏是就介绍过,他是用来生成随机数的(等函数部分涉及到我们在讲解),先说结构,利用一个do...while循环嵌套switch....case语句,根据用户输入判断出相应的功能(这里说明一点将0作为退出结束,是因为0在c语言中可以作为假,在进行while(0)即可跳出do...while循环)

void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}

menu函数

void menu()
{
printf("********************************\n");
printf("****** 1 .play 0.exit ******\n");
printf("********************************\n");
}

game函数

在game中涉及到初始化棋盘,打印棋盘,玩家走函数,电脑走函数,判断输赢函数的调用,首先进入函数设置棋盘信息,然后初始化棋盘(目的是将棋盘置空),然后是打印棋盘,我们来探讨一下重点,就是判断输赢一共有四种状态   

*代表玩家赢

#代表电脑赢

q代表平局

c代表继续

通过调用函数iswin得到的返回值来判断是谁赢还是继续或者平局,判断机制是玩家或者电脑每下一步棋就进行一次判断,while循环是为了让玩家和电脑循环下棋,如果得到的返回值不得c了,即游戏不在继续,利用break跳出循环,根据返回值判断出对弈结果

void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };//数组存放走出的棋盘信息
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);//打印棋盘
//判断电脑是否赢
ret=iswin(board, ROW, COL);
if (ret != 'c')
{
break;
}
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}

程序的头文件即函数声明(game.h)

函数声明

这里特别声明一点define宏定义,之前我们没有把棋盘的row和col写死,而是利用一个变量,这里的变量就利用了宏定义,(我们单独将函数的声明写在一个文件里是因为可以增强函数的可读性)这样只需要在主函数文件(course-8.c)的顶部引用#include "game.h"即可

#define ROW 3
#define COL 3

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

//函数的声明
void initboard(char board[ROW][COL], int row, int col);
void displayboard(char board[ROW][COL], int rw, 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);

函数部分(game.c)

我们按照顺序依次介绍

棋盘初始化initboard

利用两个for循环把每一个位置置为空

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] = ' ';//给棋盘初始化成空格
}
}
}

打印棋盘displayboard

首先展示一下我们棋盘的样子,他是由sanbufenzucheng,数据,| ,___  ,

c语言实现三子棋_随机数_02

我们是按行打印,首先我们利用for循环的嵌套先打印第一行数据,因为 “ | ”一行只需要两个所以if(j < col - 1),打印一行数据后换行,接着打印第二行也就是分割线" ___ ",(这里提示row是控制行,而col则是控制列)

void displayboard(char board[ROW][COL], int row, int col)//打印棋盘优化函数
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;

////////////1.打印一行数据
for (j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if(j < col - 1)
printf("|");
}
printf("\n");

/////////////2.打印分割行
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}

玩家落子playermove

玩家走起的逻辑也很简单,就一个循环,之所以使用循环是因为玩家可能下的坐标不合法,所以首先我们使用一个while循环,让玩家落子,直接判断其坐标是否合法if (x >= 1 && x <= row && y >= 1 && y <= col),因为棋子要落在棋盘内且为空,如果条件满足则合法可以落子,否则循环回去重新下,如下,由于我们的数组是从0开始计数的但是玩家不知道,所以在玩家下完棋后我们需要将坐标减1才行

c语言实现三子棋_#include_03

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");
}
}
}

c语言实现三子棋_初始化_04

电脑落子computermove

电脑落子和玩家落子逻辑其实差不多,要坐标合法,重点就是生成随机数的问题,我们利用rand函数生成随机数(rand需要srand函数的调用,俄日srand又需要时间戳的来生成随机数列,即srand((unsigned int)time(NULL));),通过处理rand() % row;则可以是随机数达到我们想要的范围,rand()%n,范围肯定是0~n-1即0-2,这里可能就有小伙伴问了,不是需要1-3的数嘛,大家仔细想一想,我们的数组是从0开始的

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;
}
}
}

c语言实现三子棋_i++_05

判断棋盘满isfull

如果棋盘满了还没分出胜负,那就是平局呗,返回值0代表没满,1代表满了,我们遍历棋盘但凡是碰到一个空就是没满返回0,否则返回1

//判断棋盘满没满
//返回1满了
//返回0没满
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;//满了
}

判断输赢iswin

判断输赢是整个游戏的核心,也是代码最复杂的,大家要多动脑思考其中的逻辑,首先我们进入函数,先判断行存不存在赢棋,我们利用for循环一行一行的判断,根据画图总结一行只需要判断两次即可确定,定义一个判断返回标志为int count = 0;//用来记录两次判断的结果(因为一行要判断两次),因为一行判断两次所以col-1,例如第一行 第一次00=01&&00!=‘ ’第二次01=02&&01!= ‘ ’,一行判断两次,如果count值为2则证明此行数据相同,则返回本行的第一个数据在主函数中的game函数中根据相关逻辑给出相应提示并结束游戏,判断列,和判断行相同原理,只是行列颠倒

c语言实现三子棋_#include_06

接下来就是判断斜行,左斜行,count一样用来记录两次判断的结果,即00=11&&00!='' 和 11=22&&11!=‘’,此时的for循环就有需要两个变量了,做到同增同减

c语言实现三子棋_初始化_07

右斜行判断 02=11&&02!='' 和 11=20&&11!=‘’

c语言实现三子棋_#include_08

如果,行列斜行都判断过了均没有返回,就剩下两种可能,平局或者游戏继续

棋盘满了则平局,否则游戏继续

char iswin(char board[ROW][COL], int row, int col)//判断输赢    
{
int i = 0;

//判断行
for (i = 0; i < row; i++)
{
int count = 0;//用来记录两次判断的结果(因为一行要判断两次)
int j = 0;
for (j = 0; j < col-1; j++)//一行判断两次所以col-1,例如第一行 第一次00=01&&00!=‘’第二次01=02&&01!=‘’
{
if (board[i][j] == board[i][j+ 1] && board[i][j] != ' ')
{
count++;//符合条件count++
}
}
if (count == col - 1)//一行判断两次,如果count值为2则证明此行数据相同
{
return board[i][0];//返回本行的第一个数据
}
}
//判断列,和判断行相同原理,只是行列颠倒
for (i = 0; i < col; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < row-1; j++)
{
if (board[j][i] == board[j+1][i] && board[j][i] != ' ')
{
count++;
}
}
if (count == row - 1)
{
return board[0][i];
}
}

//判断两斜行
//左斜行
int j = 0;
int count = 0;//用来记录两次判断的结果
for (i = 0,j=0; i < row-1; i++,j++)//00=11&&00!='' 和 11=22&&11!=‘’
{

if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
count++;
}
if (count == row-1)
{
return board[i][j];
}
}

//右斜行
int counts = 0;
for (i = 0, j = row - 1; i < row - 1; i++, j--)//02=11&&02!='' 和 11=20&&11!=‘’
{

if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
counts++;
}

if (counts == row - 1)
{
return board[i][j];
}
}

//平局
if (isfull(board, ROW, COL) == 1)
{
return 'q';//平局
}


return 'c'; //继续

}

全部代码

主函数文件course-8.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include "game.h"

//三子棋游戏
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };//数组存放走出的棋盘信息
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);//打印棋盘
//判断电脑是否赢
ret=iswin(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 .play 0.exit ******\n");
printf("********************************\n");
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}

函数声明game.h

#define ROW 3
#define COL 3

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

//函数的声明
void initboard(char board[ROW][COL], int row, int col);
void displayboard(char board[ROW][COL], int rw, 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);

函数部分game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

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 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"); //打印分割行
// }
// }
//}


void displayboard(char board[ROW][COL], int row, int col)//打印棋盘优化函数
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;

////////////1.打印一行数据
for (j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if(j < col - 1)
printf("|");
}
printf("\n");

/////////////2.打印分割行
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;
}
}
}
//判断棋盘满没满
//返回1满了
//返回0没满
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;//满了
}
//一共有四种状态
//*代表玩家赢
//#代表电脑赢
//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][1] != ' ')
// {
// return board[i][1];
// }
// }
// //判断竖三列
// for (i = 0; i < col; i++)
// {
// if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
// {
// return board[1][i];
// }
// }
// //判断两斜行
// if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
// return board[1][1];
// if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
// return board[1][1];
// if (isfull(board, ROW, COL) == 1)
// {
// return 'q';//平局
// }
// return 'c'; //继续
//}


char iswin(char board[ROW][COL], int row, int col)//判断输赢 自己写的优化代码
{
int i = 0;

//判断行
for (i = 0; i < row; i++)
{
int count = 0;//用来记录两次判断的结果(因为一行要判断两次)
int j = 0;
for (j = 0; j < col-1; j++)//一行判断两次所以col-1,例如第一行 第一次00=01&&00!=‘’第二次01=02&&01!=‘’
{
if (board[i][j] == board[i][j+ 1] && board[i][j] != ' ')
{
count++;//符合条件count++
}
}
if (count == col - 1)//一行判断两次,如果count值为2则证明此行数据相同
{
return board[i][0];//返回本行的第一个数据
}
}
//判断列,和判断行相同原理,只是行列颠倒
for (i = 0; i < col; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < row-1; j++)
{
if (board[j][i] == board[j+1][i] && board[j][i] != ' ')
{
count++;
}
}
if (count == row - 1)
{
return board[0][i];
}
}

//判断两斜行
//左斜行
int j = 0;
int count = 0;//用来记录两次判断的结果
for (i = 0,j=0; i < row-1; i++,j++)//00=11&&00!='' 和 11=22&&11!=‘’
{

if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
count++;
}
if (count == row-1)
{
return board[i][j];
}
}

//右斜行
int counts = 0;
for (i = 0, j = row - 1; i < row - 1; i++, j--)//02=11&&02!='' 和 11=20&&11!=‘’
{

if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
counts++;
}

if (counts == row - 1)
{
return board[i][j];
}
}

//平局
if (isfull(board, ROW, COL) == 1)
{
return 'q';//平局
}


return 'c'; //继续

}

留言:

欢迎评论区交流哦



标签:语言,实现,三子,COL,int,board,ROW,col,row
From: https://blog.51cto.com/u_15784725/6001779

相关文章

  • 数组描述线性表(C++实现)
    线性表也称有序表,其每一个实例都是元素的一个有序集合抽象类linearList一个抽象类包含没有实现代码的成员函数,这样的成员函数称为纯虚函数,用数字0作为初始值来说明templ......
  • Redux与前端表格施展“组合拳”,实现大屏展示应用的交互增强
    Redux是JavaScript状态容器,提供可预测化的状态管理。它可以用在react、angular、vue等项目中,但与react配合使用更加方便一些。Redux原理图如下,可以看到store仓库......
  • 利用无线物联网控制器实现土壤肥力的在线测量
    利用无线物联网控制器实现土壤肥力的在线测量与土壤相同,肥料在农业可持续发展中也占据重要地位,可以作为保障农业可持续发展的一个物质基础。据相关实验研究表明,肥料......
  • Redux与前端表格施展“组合拳”,实现大屏展示应用的交互增强
    Redux是JavaScript状态容器,提供可预测化的状态管理。它可以用在react、angular、vue等项目中,但与react配合使用更加方便一些。Redux原理图如下,可以看到store仓......
  • go 语言jsontoYAML
    /*CopyrightTheHelmAuthors.LicensedundertheApacheLicense,Version2.0(the"License");youmaynotusethisfileexceptincompliancewiththeLicense.You......
  • 哪些软件和程序用了C语言?
    在日常生活中,很多系统软件和桌面应用程序都采用C语言进行开发,下面给出了一些示例。1.操作系统UNIX是第一个使用**语言设计的操作系统,它使用的编程语言就是C语言。后来,Mic......
  • 前后端分离架构:Web 实现前后端分离,前后端解耦
    一、前言”前后端分离“已经成为互联网项目开发的业界标杆,通过Tomcat+Ngnix(也可以中间有个Node.js),有效地进行解耦。并且前后端分离会为以后的大型分布式架构、弹性计算架......
  • 一个C语言的剪刀石头布小游戏
    /******************************************************石头剪刀布的程序geek_monkey于2015年3月3日修改了bug(输入字符非石头剪刀布都算是玩家赢)编译环境为VC+......
  • Jenkins实现代码的部署&回滚
    一、Jenkins介绍   Jenkins是一个独立的开源软件项目,是基于Java开发的一款CI(持续集成)&CD(持续交付)工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台。可......
  • 直播美颜SDK的功能实现流程——美白、磨皮
    时下,很多开发者和技术发烧友想要自主开发直播美颜SDK,但受限于技术原因导致进度受阻,下文小编总结了直播美颜SDK美白与磨皮功能的实现流程,阅读时间大约五分钟。众所周知,一套完......