Skip to main content

moregeek program

c语言实现三子棋-多极客编程

前言:

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

概述:

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

c语言实现三子棋_i++

程序主函数(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语言实现三子棋_i++_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语言实现三子棋_初始化_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语言实现三子棋_初始化_06

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

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

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

c语言实现三子棋_初始化_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'; //继续

}

留言:

欢迎评论区交流哦



©著作权归作者所有:来自51CTO博客作者进击的菜鸟子的原创作品,请联系作者获取转载授权,否则将追究法律责任

(一)java基础语法-多极客编程

一.基础写法/*使用命令行的方式执行的时候,cmd的默认编码是GBK所以在输入中文的时候需要设置文件的编码格式为ANSI这样不会出现乱码格式*/public class HelloWorld/*java文件的名称必须跟public class的名称保持一致*/{ public static void main(String[] args) /* 1.该代码是所有java程序的入口,如果向执行

运用c语言完成简单的猜数字游戏(随机数为1到100)-多极客编程

要完成一个猜数字游戏首先我们要让电脑生成一个随机数,这时候我们就可以使用rand函数这个函数的作用就是返回一个随机数但如果不先配置随机数生成器那么就会出现一个问题就是就是每一次重新启动这个代码那么生成的随机数还是你上次游玩时的随机数,这就不够随机这时我们便要使用srand函数来配置随机数生成器但使用srand函数要运用一个不断在变化的值这时候我们便可以使用时间戳来配置,而c语言中time函数便可以

c语言模拟用户输入三次密码并判断是否正确-多极客编程

#include<stdio.h>int main(){ char password[20] = { 0 };//先初始化这个数组避免出现其它数据 int flag = 0;//设立flag变量是若三次密码都输入错误了能向用户输出三次均错误的信息 for (int i = 1; i <= 3; i++) { printf("请输入密码:<"); scan

扫雷游戏程序-多极客编程

程序大纲#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include"game.h" void menu() { printf("*******************************\n"); printf("************1.play*************\n"); printf("******

c语言指针统览-多极客编程

前言本文对C语言指针和指针使用时的问题做一个概览性的总结,并对一些值得探讨的问题进行讨论。阅读本文,读者能达到统览C语言指针的目的。以下的讨论只针对32/64位机器。指针纲领:什么是指针要知道什么是指针,就要先了解内存的编址方法。内存的编址存储器由一块块的空间(存储单元)组成,为了方便寻找到每一块空间,我们需要对每一个空间进行标识——内存编址。字节(Byte)是讨论内存空间时的基本单位,每个存储单

sgx性能实验-多极客编程

SGX实验报告​一.实验目标​了解采用SGX可信任环境后对应用和目标主机产生的性能影响有多少。​二.实验准备​Microsoft Window10 21H2版本主机一台,​处理器:Intel Core(TM)i5-9500F ​​CPU@3.00GHZ​​​64位操作系统,内存16GB​代码编译环境:vs2015专业版或者Clion2021​SGX插件相关版本​Intel ME版本:ME_SW_1

shell 命令奇淫技巧,就是有点短-多极客编程

1、在任意目录之间快速移动 你发现自己要在两个或更多目录之间频繁移动,一会切换到这里,一会切换到那里,来回跳转。这些目录之间隔得还挺远,反复输入冗长的路径让人疲惫不堪。 使用内建命令 pushd 和 popd 来管理目录栈,轻松地在目录之间切换。下面是一个简单的示例: $ cd /tmp/tank $ pwd /tmp/tank $ pushd /var/log/cups /var/log/cu

使用file类创建简单的文件目录检索小工具-多极客编程

File类的常用方法 序号 方法描述 1 public String getName() 返回由此抽象路径名表示的文件或目录的名称。 2 public String getParent()****、 返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。 3 public File getParentFile() 返回此抽象路径名的父路径名

场景编程集锦 - bmi指数与健身达人-多极客编程

1. 场景描述   BMI指数(身体质量指数,英文Body Mass Index)是用体重公斤数除以身高米数的平方得出的数字,是目前国际上通用的衡量人体胖瘦程度以及是否健康的一个标准。“身体质量指数”这个概念,是由19世纪中期的比利时数学家凯特勒最先提出来的,BMI指数的计算公式: $BMI = weight / height^2$ 其中weight体重的度量单位是公斤,height身高的度量单

扫雷游戏程序-多极客编程

程序大纲#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include"game.h" void menu() { printf("*******************************\n"); printf("************1.play*************\n"); printf("******

mybatisplus实战专题 多表连接 代码生成 分组查询 一网打尽-多极客编程

一、MybatisPlusMax简介 MybatisPlusMax是MybatisPlus的增强包,秉承只拓展不修改的理念,对MybatisPlus做增强。 正如MybatisPlus是对MyBatis的增强,MybatisPlusMax是对MybatisPlus的增强,拓展理念一脉相承。 MybatisPlus依然进入软件成熟期,对其进行微小的修改会慎之又慎,向其提交修改PR周期较长,基于此考虑

c语言指针统览-多极客编程

前言本文对C语言指针和指针使用时的问题做一个概览性的总结,并对一些值得探讨的问题进行讨论。阅读本文,读者能达到统览C语言指针的目的。以下的讨论只针对32/64位机器。指针纲领:什么是指针要知道什么是指针,就要先了解内存的编址方法。内存的编址存储器由一块块的空间(存储单元)组成,为了方便寻找到每一块空间,我们需要对每一个空间进行标识——内存编址。字节(Byte)是讨论内存空间时的基本单位,每个存储单