今天来放松一下, 一起来写一个简易的小游戏——三子棋:
既然是小游戏,我们就可以设置一个简易的菜单,比如1为开始游戏,0为退出游戏:
void menu()
{
printf("-------------------------------\n");
printf("---------- 1、play ----------\n");
printf("---------- 0、exit ----------\n");
printf("-------------------------------\n");
}
有了菜单我们就要去实现我们的一个逻辑了,当然这里建议同学们不要把所有内容全部写到 main函数里面哦,我们今天采用多文件写法:
首先我们这个菜单在玩家运行时就要打印,需要玩家选择,所以我们这里可以采用 do while 循环,然后根据玩家输入的值进行 switch 分支判断,并把游戏实现部分封装到一个函数 game 里头:
int main()
{
int input = 0;
do
{
menu();
printf("Please select :>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("Input error,please select again!\n");
break;
}
} while (input);
return 0;
}
由上可见我们简单的 main 函数里头的内容写这么多就够啦,我们可以看到,进行一次游戏还可以重复玩哦!当玩家输入错误也会提醒他重新输入!主要游戏实现函数我们放到 game.c 里,函数的声明我们放到 game.h 里头。
准备工作做完啦,现在就要实现具体函数了!
既然我们是下棋,我们肯定要有一个棋盘,这里棋盘是设置成 3*3 还是 5*5 呢?如果后期我们要增大棋盘怎么办?所以我们干脆直接在头文件里 #define 定义一个常量,这样很方便我们后期要修改棋盘大小就不用一个个修改了!
#define ROW 3 // 行
#define COL 3 // 列
接着我们需要创建我们的棋盘并且初始化!InitBoard 函数会把我们棋盘内容全部初始化成空格。这里我们采用的是两个 for 循环遍历二维数组的方式进行初始化:
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < COL; ++j)
{
board[i][j] = ' ';
}
}
}
来到这我们棋盘得有一个简单的外观吧!这个小伙伴们可以随便设计了,那么我今天就简单的设计一个棋盘,比如:

那么我们如何用C语言打印出来呢?其实很简单:
void PrintBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
while (i < row)
{
for (int j = 0; j < col; ++j)
{
if (j < col - 1)
printf(" %c |", board[i][j]);
else
printf(" %c ", board[i][j]);
}
printf("\n");
for (int j = 0; j < col; ++j)
{
if (i < row - 1)
{
if (j < col - 1)
printf("---|");
else
printf("---");
}
}
if(i < row - 1)
printf("\n");
++i;
}
}
效果图:(小伙伴可以按照自己喜欢的风格调整哦)

有了棋盘,我们就可以开始下棋了,那么我们肯定得给这个三子棋制定一个规则,比如玩家下的棋用 ' * ' 表示,电脑下的棋用 ' # ' 表示,既然我们约定好了,那么就可以开始实现代码了!
来到这我们要考虑几个问题:
其实这三个问题非常好解决,首先我们使玩家输入下标 x,y 都减一就可以了,如果位置重复,我们让玩家或电脑重新输入新的位置就好,如果下标越界,肯定是提示玩家,并且重新输入!
代码实现:
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("Please enter coordinates (x,y) :>");
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("Coordinates occupied!\n");
}
else
{
printf("Coordinate error!\n");
}
}
}
上面则是我们玩家下棋,那么电脑下棋呢?
首先我们要保证电脑下棋的随机性,同时也要限制电脑的有效下标范围,这里我们可以使用 srand 和 rand 函数来生成随机数,大致思路跟玩家下棋逻辑一样:(srand 设置起始位置在后面会有)
void ComuterMove(char board[ROW][COL], int row, int col)
{
printf("ComuterMove:\n");
while (1)
{
// x, y = [0, 2]
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
我们已经解决了下棋的问题,剩下来就是判断输赢了,可想而知,这个游戏只有玩家赢,电脑赢,或者平局,那么这个我们该如何设计呢?
如果玩家赢了,那我们就返回 ' * ',如果电脑赢了,我们就返回 ' # ',当棋盘满的情况下就证明是平局了,我们就返回 ' d ',除了以上三种情况,我们游戏都需要继续,那么我们就返回 ' c ';
/*
return '*' PlayerWin
return '#' comuterWin
return 'c' GameContinue
return 'd' GameDogfall
*/
char IsWin(char board[ROW][COL], int row, int col);
玩过三子棋的都知道规则,如果横着三个连成线,或者竖着三个连成线,以及斜着可以连成线都算成功,所以这个我们就分别得判断这四种情况了:行(row), 列(col),斜(tilted),平局(Dogfall)
这个函数的实现相较于上边会有点难度,因为我们不能直接把判断条件写固定住,比如说: boare[0][0] == boare[0][1] && boare[0][1] == boare[0][2],如果真这样写的话,如果我们要使用 5*5 的棋盘或者 8*8 的棋盘呢?所以这里我们可以采用遍历二维数组的思路:
代码实现:
char IsWin(char board[ROW][COL], int row, int col)
{
//row
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
if (j < col - 2 && board[i][j] != ' ' && board[i][j] == board[i][j + 1]
&& board[i][j + 1] == board[i][j + 2])
return board[i][j];
}
}
//col
for (int i = 0; i < col; ++i)
{
for (int j = 0; j < row; ++j)
{
if (j < row - 2 && board[j][i] != ' ' && board[j][i] == board[j + 1][i]
&& board[j + 1][i] == board[j + 2][i])
return board[j][i];
}
}
//tilted
for (int i = 0; i < row ; ++i)
{
for (int j = 0; j < col; ++j)
{
if (j < col - 2 && board[i][j] != ' ' && board[i][j] == board[i + 1][j + 1]
&& board[i + 1][j + 1] == board[i + 2][j + 2])
return board[i][j];
}
}
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
if (j > 1 && board[i][j] != ' ' && board[i][j] == board[i + 1][j - 1]
&& board[i + 1][j - 1] == board[i + 2][j - 2])
return board[i][j];
}
}
//Dogfall
while (1)
{
int count = 0;
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
if (board[i][j] == ' ')
{
count = 1;
}
}
}
if (count == 0)
return 'd';
else
return 'c';
}
}
其实以上代码有一个点需要说一下:首先判断行(row)的时候我们要防止下标越界访问,所以需要 j < col - 2,如果不这样写,我们想象一下,如果我们只有 3*3 的棋盘,我们有必要从第二列开始往后判断那些坐标位置吗?没这个必要,因为从第二列开始最多只有两个有效坐标!
相信后面的代码你们靠着上面的解释也能看懂吧!有不明白或者有更好的建议都可以告诉我哦!
接下来就是在 game 函数里头来调用我们刚刚写的那些函数了:
void game()
{
char ret = 0;
//The starting value
srand((unsigned)time(NULL));
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
printf("Start the game.\n");
PrintBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'c')
break;
PrintBoard(board, ROW, COL);
ComuterMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'c')
break;
PrintBoard(board, ROW, COL);
}
if (ret == '*')
printf("PlayerWin!\n");
else if (ret == '#')
printf("comuterWin!\n");
else
printf("GameDogfall!\n");
PrintBoard(board, ROW, COL);
}
以及我们 game.h 的头文件包含以及函数声明部分:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define ROW 5
#define COL 5
void InitBoard(char board[ROW][COL], int row, int col);
void PrintBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComuterMove(char board[ROW][COL], int row, int col);
/*
return '*' PlayerWin
return '#' comuterWin
return 'c' GameContinue
return 'd' GameDogfall
*/
char IsWin(char board[ROW][COL], int row, int col);
好了,代码都实现完了,那我们就玩两把试试吧:

这个三子棋电脑下棋可能有点憨憨的,它只会随机下棋,感兴趣的小伙伴可以下来把他优化成智能下棋的哈,这次我没有用图片放代码哈,也可以直接 copy 我的代码下去玩俩吧哈!
其实这个游戏不是主要的,主要的是希望小伙伴们通过这个小案例来锻炼自己的编程逻辑,像递归一样,写多了,自然都会了,有句话说得好,眼看十遍不如手敲一遍,赶紧拿出电脑来敲敲代码吧!

为了更美好的明天而战,加油吧,少年们!
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
修改(澄清问题)我已经花了几天时间试图弄清楚如何从Facebook游戏中抓取特定信息;但是,我遇到了一堵又一堵砖墙。据我所知,主要问题如下。我可以使用Chrome的检查元素工具手动查找我需要的html-它似乎位于iframe中。但是,当我尝试抓取该iframe时,它是空的(属性除外):如果我使用浏览器的“查看页面源代码”工具,这与我看到的输出相同。我不明白为什么我看不到iframe中的数据。答案不是它是由AJAX之后添加的。(我知道这既是因为“查看页面源代码”可以读取Ajax添加的数据,也是因为我有b/c我一直等到我可以看到数据页面之后才抓取它,但它仍然不存在)。发生这种情况是因为
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby有很大不同。由于我与ruby之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?
如果特定语言环境中缺少翻译,如何配置i18n以使用en语言环境翻译?当前已插入翻译缺失消息。我正在使用RoR3.1。 最佳答案 找到相似的question这里是答案:#application.rb#railswillfallbacktoconfig.i18n.default_localetranslationconfig.i18n.fallbacks=true#railswillfallbacktoen,nomatterwhatissetasconfig.i18n.default_localeconfig.i18n.fallback
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion是否有适用于这些的3d游戏引擎?
在我的双语Rails4应用程序中,我有一个像这样的LocalesController:classLocalesController用户可以通过此表单更改其语言环境:deflocale_switcherform_tagurl_for(:controller=>'locales',:action=>'change_locale'),:method=>'get',:id=>'locale_switcher'doselect_tag'set_locale',options_for_select(LANGUAGES,I18n.locale.to_s)end这有效。但是,目前用户无法通过URL更改
我使用Ruby编程已经有一段时间了,现在只使用Ruby的标准MRI实现,但我一直对我经常听到的其他实现感到好奇。前几天我在读有关Rubinius的文章,这是一个用Ruby编写的Ruby解释器。我试着在不同的地方查找它,但我很难弄清楚这样的东西到底是如何工作的。我在编译器或语言编写方面从来没有太多经验,但我真的很想弄明白。一门语言究竟如何才能被自己解释?编译中是否有一个我不明白这有意义的基本步骤?有人可以像我是个白痴一样向我解释这个吗(因为无论如何这都不会太离谱) 最佳答案 它比你想象的要简单。Rubinius并非100%用Ruby编