C语言开发简易版扫雷小游戏

2025-05-29 0 62

前言:

  想起来做这个是因为那时候某天知道了原来黑框框里面的光标是可以控制的,而且又经常听人说起这个,就锻炼一下好了。

  之前就完成了那1.0的版本,现在想放上来分享却发现有蛮多问题的,而且最重要的是没什么注释【果然那时候太年轻】!现在看了也是被那时候的自己逗笑了,就修改了一些小bug,增加了算是详尽而清楚的注释,嗯,MSDN上面对各种函数的解释很详细的【又锻炼一下英语】,顺便让开头和结尾的展示“动”了起来,就当作1.5的版本好了。

  这个只是给出了一个实现的思路,其中肯定也有很多不合理的地方和可优化之处,希望能供大家参考和交流。

过程:

  期间也是遇到了蛮多困惑的。

  1.最先的是怎么知道按了方向键,左查右找,说法有好几个版本呢,就想看能不能自己测试一下自己的好了,再查再找,好了,感谢写了测试方向键的人;

  2.再比如说怎么消除窗口中一行的缓冲,因为不消除就一直在哪,视觉效果不好,翻查了一下资料,就写了delLine()这个来做这个事情了;

  3.设定颜色时,在cmd里面help color知道了颜色的参数,但是通过数字0-9来设定的太暗了,发现有更亮的,比如0A,在setColor()里面用它却说类型不对,于是上MSDN,发现还可以用宏,就想通过如'BACKGROUND_INTENSITY | BACKGROUND_RED '之类来完成,就想怎么去代替那个宏,觉得每次写一长串好麻烦。然后换了各种类型的参数类型和不定长参数什么的,发现还是不行,后来一想,万一它支持数字10呢,A不就是10么?!一测,成了;

  4.还有一些判断状态的顺序,嗯啊,这些要先想好再下手,不然左改右改很麻烦呢;

  5.别的困惑不怎么记得了。。。

代码:

  下面分别给出LittleMines【好弱的名字】,测试颜色,测试方向键的代码。【反映说有行号不好复制,那取消好了】

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583
/*********************************

* c语言命令行+方向键简易版扫雷

* Author:AnnsShadoW

* Version:1.5

* Time:2015-11-29

********************************/

/********************************

* 运行环境:Windows10-64bit

* 编译环境:Codeblocks-13.12

********************************/

//用到的都导进去吧

#include <stdio.h>

#include <stdlib.h>

#include <conio.h>

#include <time.h>

#include <windows.h>

//定义各种判断状态的ASCII码

//MINE是定义翻开格子中的‘*'号

#define MINE 42

#define ESC 27

#define ENTER 13

#define SPACE 32

#define UP 72

#define DOWN 80

#define LEFT 75

#define RIGHT 77

//定义类型状态,方便后续判断

#define bool int

#define true 1

#define false 0

#define ROW 10

#define COLUMN 10

#define ALL_MINES 15

//当前位置的结构体

typedef struct currentPosition_struct

{

int x;

int y;

} currentPosition;

//每一个小格的结构体

typedef struct blockCondition_struct

{

//是否被覆盖了

bool beCovered;

//以它为中心周围的雷数

int minesNum;

} blockCondition;

//光标的位置数组

currentPosition cursorPos[ROW][COLUMN];

//雷区地图的数组

blockCondition minesMap[ROW][COLUMN];

//剩下的格子数

int leftBlocksNum = ROW * COLUMN;

//光标在光标位置、雷区地图中的下标

int index_x = 0, index_y = 0;

//设置窗口前后背景色

void setColor(unsigned short color);

//开头的欢迎“动画”

void welcomeToMyGame();

//游戏地图初始化

void gameInitailize();

//以某格子为中心计算惊天雷数量

void countMines();

//获取键盘的输入

void keyBoardInput();

//指定光标的位置

void setCurPos(int y, int x);

//移动光标的位置

void moveCursor(int y, int x);

//检测每一步的结果

bool checkResult(int y, int x);

//输出游戏界面

void printMap();

//游戏退出后的“动画”

void gameOver(char *str);

//删除窗口中一行的缓冲

void delLine(int y);

int main()

{

setColor(10);

system("cls");

welcomeToMyGame();

gameInitailize();

countMines();

printMap();

for(;;)

{

setCurPos(cursorPos[index_y][index_x].y, cursorPos[index_y][index_x].x);

keyBoardInput();

}

return EXIT_SUCCESS;

}

void setColor(unsigned short color)

{

HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);

//对设置之后的输出有效

SetConsoleTextAttribute(hCon, color);

};

void welcomeToMyGame()

{

int i = 0;

char introductions0[] = "LittleMines";

char introductions1[] = "--";

char introductions2[] = "Version 1.5";

char introductions3[] = "Author:AnnsShadow,thank you ╮( ̄▽ ̄)╭";

//控制台窗口默认大小是80*25,所以能达到最大的位置是[79,24]

for(i = 0; i <= 5; ++i)

{

//每次输出之前都清屏,就会有看起来是动的效果

system("cls");

//纵坐标不断加,形成向下效果

setCurPos(i, (80 - strlen(introductions0)) / 2);

printf("%s", introductions0);

//缓冲一下,太快了看不到呢

Sleep(50);

}

//为了对称,从边边78开始到中间39好了

for(i = 78; i >= 39; --i)

{

//上面用了5行了,大于它吧

setCurPos(7, i);

printf("%s", introductions1);

setCurPos(7, 78 - i);

printf("%s", introductions1);

Sleep(40);

}

//从左边一步步进入屏幕中间

for(i = 0; i <= (80 - strlen(introductions2)) / 2; ++i)

{

//要删除这一行缓冲的原因:

//上一次循环的输出会影响到下一次,如输出VVVVVVVVVVersion1.0

//换成中文就不会,中文要两个字节才能显示完整呀

delLine(9);

//这里就会有闪闪发亮的效果哦

Sleep(10);

setCurPos(9, i);

printf("%s", introductions2);

Sleep(50);

}

//从底部进入

for(i = 24; i >= 12; --i)

{

setCurPos(i, (80 - strlen(introductions3)) / 2);

printf("%s", introductions3);

Sleep(20);

//删除上一次的缓冲,不加1的话最后一行就会残留,其它都不见了

delLine(i + 1);

Sleep(50);

}

Sleep(500);

char help0[] = "动啊:←↑↓→╮(╯▽╰)╭";

char help1[] = "点击啊:Space / Enter (ΘェΘ)";

char help2[] = "不玩啦:Esc (>﹏<)";

char help3[] = "<<愿你玩的开心 _(:з」∠)_>>";

setCurPos(14, (80 - strlen(help0)) / 2);

setColor(14);

printf("%s", help0);

setCurPos(15, (80 - strlen(help1)) / 2);

printf("%s", help1);

setCurPos(16, (80 - strlen(help2)) / 2);

printf("%s", help2);

setCurPos(17, (80 - strlen(help3)) / 2);

setColor(15);

printf("%s", help3);

getch();

}

void gameInitailize()

{

int i = 0, j = 0;

int allMines = ALL_MINES;

//设置随机值

srand((unsigned int)time(NULL));

//雷区地图初始化

for(i = 0; i < ROW; ++i)

{

for(j = 0; j < COLUMN; ++j)

{

minesMap[i][j].beCovered = true;

minesMap[i][j].minesNum = 0;

}

}

//放置惊天雷!

while(allMines)

{

i = rand() % ROW;

j = rand() % COLUMN;

if(minesMap[i][j].minesNum == 0)

{

//这个‘-1'就作为判断惊天雷的依据了

minesMap[i][j].minesNum = -1;

--allMines;

}

}

//光标位置初始化

for(i = 0; i < ROW; ++i)

{

for(j = 0; j < COLUMN; ++j)

{

cursorPos[i][j].x = j * 6 + 3;

cursorPos[i][j].y = i * 2 + 1;

}

}

}

void countMines()

{

int i = 0, j = 0, m = 0, n = 0;

//以格子为中心周围的雷数

int minesNum = 0;

for(i = 0; i < ROW; ++i)

{

for(j = 0; j < COLUMN; ++j)

{

//遇到惊天雷就放弃统计吧

if(minesMap[i][j].minesNum == -1)

continue;

minesNum = 0;

//九宫格嘛,那3次好了

for(m = -1; m <= 1; ++m)

{

//行溢出了没,不能算没有的哦

if(i + m < 0 || i + m >= ROW)

{

continue;

}

for(n = -1; n <= 1; ++n)

{

//这次就是看列溢出了没

if(j + n < 0 || j + n >= COLUMN)

{

continue;

}

//周边有惊天雷赶紧加起来

if(minesMap[i + m][j + n].minesNum == -1)

{

++minesNum;

}

}

}

minesMap[i][j].minesNum = minesNum;

}

}

}

void keyBoardInput()

{

bool lose;

int key1 = getch();

/*****************************

测试之后才知道方向键两个字节

第一个字节ASCII 0x00e0 224

第二个字节分别是:

上:0x0048 72

下:0x0050 80

左:0x012b 75

右:0x012d 77

*****************************/

if(key1 == 224)

{

int key2 = getch();

switch(key2)

{

case UP:

moveCursor(index_y - 1, index_x);

break;

case DOWN:

moveCursor(index_y + 1, index_x);

break;

case LEFT:

moveCursor(index_y, index_x - 1);

break;

case RIGHT:

moveCursor(index_y, index_x + 1);

break;

default:

break;

}

}

else

{

switch(key1)

{

case ENTER:

case SPACE:

lose = checkResult(index_y, index_x);

system("cls");

printMap();

if(lose)

{

setColor(13);

printf("| 诶哟,还差一点点哦! ╥﹏╥ |\\n");

printf("| 按\\"r\\"重玩,Esc不玩啦。 |\\n");

printf("[%c]-------------------------------------------------------[%c]\\n", MINE, MINE);

setColor(10);

Sleep(1000);

char key3 = getch();

if(key3 == 'r' || key3 == 'R')

{

//重来,跟main中过程是一样的

setColor(10);

gameInitailize();

countMines();

printMap();

}

}

//剩余的格子比雷还要多,可以继续玩

else if(leftBlocksNum > ALL_MINES)

{

setColor(13);

printf("| 哎哟,挺不错哦~ ( ̄0  ̄) |\\n");

printf("[%c]-------------------------------------------------------[%c]\\n", MINE, MINE);

setColor(10);

}

//来到这你已经赢了

else

{

setColor(13);

printf("| 哟,恭喜你赢了(/≧▽≦/) |\\n");

printf("| 按\\"r\\"重玩,Esc就不玩啦。 |\\n");

printf("[%c]-------------------------------------------------------[%c]\\n", MINE, MINE);

setColor(10);

Sleep(1000);

char key3 = getch();

if(key3 == 'r' || key3 == 'R')

{

setColor(10);

gameInitailize();

countMines();

printMap();

}

}

break;

case ESC:

system("cls");

gameOver("\\t\\t\\t啦啦啦~很逗很扯吧~最后感谢你的玩耍呀(≧Д≦)\\n\\n\\n\\n\\n\\n\\n\\n");

default:

break;

}

}

}

void setCurPos(int y, int x)

{

//在窗口缓冲中定义每个位置的状态

COORD currentPosition;

currentPosition.Y = y;

currentPosition.X = x;

//所以现在的位置是在{y,x}

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), currentPosition);

}

void moveCursor(int y, int x)

{

//限定能走的地方

if((x >= 0 && x < COLUMN) && (y >= 0 && y < ROW))

{

setCurPos(cursorPos[y][x].y, cursorPos[y][x].x);

index_x = x;

index_y = y;

}

}

bool checkResult(int y, int x)

{

int i = 0, j = 0;

//检测有没有溢出地图了

if(x < 0 || x >= COLUMN || y < 0 || y >= ROW)

{

return false;

}

//就是你了!被选中的格子!

minesMap[y][x].beCovered = false;

//被惊天雷炸了

if(minesMap[y][x].minesNum == -1)

{

minesMap[y][x].minesNum = 9;

return true;

}

//如果没有雷,就当作空格吧

if(minesMap[y][x].minesNum > 0 && minesMap[y][x].minesNum < 9)

{

return false;

}

//九宫格,3x3咯

for(i = -1; i <= 1; ++i)

{

//检查一下在这一行溢出了没吧

if(y + i < 0 || y + i >= ROW)

{

continue;

}

for(j = -1; j <= 1; ++j)

{

//这次就到列了吧

if(x + j < 0 || x + j >= COLUMN)

{

continue;

}

//如果下一个是没开过的,就检查它吧

if(minesMap[y + i][x + j].beCovered)

{

minesMap[y + i][x + j].beCovered = false;

checkResult(y + i, x + j);

}

}

}

return false;

}

void printMap()

{

system("cls");

char help0[] = "←↑↓→";

char help1[] = "动啊";

char help2[] = "Space / Enter";

char help3[] = "点击啊";

char help4[] = "Esc 不玩啦";

//因为要输出提示,所以地图不能太大了,10x10就差不多了

setColor(14);

setCurPos(4, 62);

printf("%s", help0);

setCurPos(6, 62);

printf("%s", help1);

setCurPos(9, 62);

printf("%s", help2);

setCurPos(11, 62);

printf("%s", help3);

setCurPos(14, 62);

printf("%s", help4);

setCurPos(0, 0);

setColor(10);

int i = 0, j = 0, k = 0;

leftBlocksNum = 0;

setColor(11);

printf("[开]--");

setColor(10);

for(k = 1; k < COLUMN - 1; ++k)

{

printf("+-----");

}

setColor(11);

printf("+--[心]\\n");

setColor(10);

for(i = 0; i < ROW; ++i)

{

for(j = 0; j < COLUMN; ++j)

{

if(minesMap[i][j].beCovered)

{

++leftBlocksNum;

//这个输出的就是格子被覆盖的时候输出的图形,可以换成1-6试试

//1-4是正方形的4个角,5-6是双竖线和双横线

printf("| %c ", 3);

}

else if(minesMap[i][j].minesNum == -1 || minesMap[i][j].minesNum == 9)

{

printf("| %c ", MINE);

}

else if(minesMap[i][j].minesNum == 0)

{

printf("| %c ", ' ');

}

else

{

printf("| %d ", minesMap[i][j].minesNum);

}

}

printf("|\\n");

if(i < ROW - 1)

{

for(k = 0; k < COLUMN; ++k)

{

printf("+-----");

}

printf("+\\n");

}

}

setColor(11);

printf("[就]--");

setColor(10);

for(k = 1; k < COLUMN - 1; ++k)

{

printf("+-----");

}

setColor(11);

printf("+--[好]\\n");

setColor(10);

}

void gameOver(char *str)

{

setColor(12);

system("cls");

setCurPos(10, 0);

int i = 0;

do

{

//逐字输出

printf("%c", str[i]);

Sleep(60);

}

while(str[i++]);

setColor(15);

system("pause");

//随意终止程序并返回给OS,0是正常的

exit(0);

}

void delLine(int y)

{

HANDLE hOutput;

//窗口缓存信息

CONSOLE_SCREEN_BUFFER_INFO sbi;

DWORD len, nw;

//用MSDN上的TCHAR类型跪了,换成char就好

char fillchar = ' ';

//定位光标

COORD startPosition = {0, y};

//获取输出句柄

hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

//获取窗口缓冲中的信息

GetConsoleScreenBufferInfo(hOutput, &sbi);

//窗口缓冲的位置,这里取得X值

len = sbi.dwSize.X;

//从特定的位置用特定的字符去填充窗口的缓冲特定次数

//成功返回非0值,一般都成功,就不判断了

FillConsoleOutputCharacter(hOutput, fillchar, len, startPosition, &nw);

}

测试颜色:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
#include <windows.h>

#include <stdlib.h>

#include <stdio.h>

void setColor(unsigned short color)

{

HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);

//对设置之后的输出有效

SetConsoleTextAttribute(hCon, color);

};

int main()

{

//测试颜色啊~~

for(int i = 0; i <= 255; i++)

{

setColor(i);

printf("%d\\n", i);

system("pause");

}

return 0;

}

测试方向键:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26
#include <stdio.h>

#include <stdlib.h>

#include <windows.h>

#include <conio.h>

int main()

{

unsigned short int k;

while(1)

{

_sleep(100);

if(_kbhit())

{

k = _getch();

if(0 == k)

k = _getch() << 8;

_cprintf("key:0x%04x pressed\\r\\n", k);

}

}

system("pause");

return 0;

}

运行截图:图片不会动啦,在自己机子跑起来就看得到动的效果了~~~

C语言开发简易版扫雷小游戏

C语言开发简易版扫雷小游戏

C语言开发简易版扫雷小游戏

后话:

  虽然不是什么很厉害的事情,稍微懂点的都可以自己做出来,不过在实践的过程中还是收获蛮多的,在这分享也算个小小的记录吧,继续加油~

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 C语言开发简易版扫雷小游戏 https://www.kuaiidc.com/106803.html

相关文章

发表评论
暂无评论