这个游戏我认为是很考验思维含量的,毕竟登上了最强大脑的舞台。
然而写这个程序也累(主要有一个大bug没找出来,详见后面的分析)。
程序
//This is a simple 15-puzzle game.
#include <iostream>
#include <vector>
#include <Windows.h>
#include <string>
#include <random>
#include <ctime>
#include <conio.h>
using namespace std;
int sx = 3, sy = 3; // int connot be replaced by unsigned
vector<vector<char>> p = {
{
'1','2','3','4'},
{
'5','6','7','8'},
{
'9','A','B','C'},
{
'D','E','F',' '}};
vector<vector<char>> p0 = p; // the finished state
void change(int n)
{
switch (n)
{
case 1: // up
if (sx + 1 <= 3)
{
p[sx][sy] = p[sx + 1][sy];
p[sx + 1][sy] = ' ';
++sx;
}
break;
case 2: // down
if (sx - 1 >= 0)
{
p[sx][sy] = p[sx - 1][sy];
p[sx - 1][sy] = ' ';
--sx;
}
break;
case 3: // left
if (sy + 1 <= 3)
{
p[sx][sy] = p[sx][sy + 1];
p[sx][sy + 1] = ' ';
++sy;
}
break;
case 4: // right
if (sy - 1 >= 0)
{
p[sx][sy] = p[sx][sy - 1];
p[sx][sy - 1] = ' ';
--sy;
}
break;
default:
break;
}
}
void input(char c1, char c2)
{
c1 = _getch();
c2 = _getch();
switch (c2)
{
case 72: // up
change(1);
break;
case 80: // down
change(2);
break;
case 75: // left
change(3);
break;
case 77: // right
change(4);
break;
default:
break;
}
}
void random_start() // create a random plate
{
default_random_engine random;
vector<int> ivec;
for (int i = 0; i != 400; i++)
ivec.push_back(random() % 4 + 1);
srand((unsigned)time(NULL));
int ran = rand() % 200; // generate a random number ranging from 0 to 199
for (int i = ran; i != ran + 200; i++) // make 200 moves
change(ivec[i]);
if (sx == 0) change(1);
if (sx == 1) change(1);
if (sx == 2) change(1);
if (sy == 0) change(3);
if (sy == 1) change(3);
if (sy == 2) change(3); // move the empty place to p[3][3]
}
void print(vector<vector<char>> q)
{
for (int i = 0; i != 4; i++)
{
for (int j = 0; j != 4; j++)
cout << "|" << q[i][j];
cout << "|" << endl;
}
}
int main()
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(hOut, &cci);
// The five lines above are used to hide the Console Cursor.
cout << "This is a simple 15-puzzle game.\nProgrammer:Teddy van Jerry" << endl;
random_start();
cout << "\nYou can move the number ranging from 1 to F using ↑,↓,←,→.\n" << endl;
print(p);
cout << "\nNow you have 10 seconds to get ready. After that, we will begin.\n" << endl;
for (int i = 10; i != 0; i--)
{
cout << i;
Sleep(1000); // wait for a second;
cout << " ";
}
cout << "Go!\n" << endl;
long time_start = clock(); // the starting point
unsigned cnt = 0;
while (p != p0) // when it's unfinshed
{
char a1 = '\0', a2 = '\0';
input(a1, a2);
print(p);
cout << "\n" << endl;
++cnt;
}
long total_time = clock() - time_start;
int min = total_time / 60000;
int second = (total_time % 60000) / 1000;
string zero = (second < 10) ? "0" : "";
cout << "You made it!" << endl;
cout << "You made " << cnt << " moves. ";
cout << "The total time is " << min << "'" << zero << second << "\"." << endl;
cout << "\nALL RIGHTS RESERVED (c) 2020 Teddy van Jerry" << endl;
char anything;
cin >> anything;
return 0;
}
//Copyright :2020 Teddy van Jerry
输出示例
分析
- 首先说最令人头疼的bug!一直是以下错误:
然后发现问题就在move()
函数中,好久之后发现move()
是overloaded,改成change()
还是错的,又搞了好久好久(一共已经两个多小时了),考虑了各种各样的情况,重看了不知道多少遍,最终忽然发现一切都是unsigned
造成的。虽然空位的坐标不可能为负,但是在change()
函数中判断是否为合法输入时有-1
的操作,(事实上移到右边就对了)因为unsigned
在0
时-1
就会翻上去一轮,就是很大很大的值,判断一定成立,因而就会有vector subscript out of range
。
- 注意151行输出
"
要用转义字符\
。 - 其他的类似于贪吃蛇游戏中问题,可以举一反三。
ALL RIGHTS RESERVED © 2020 Teddy van Jerry
欢迎转载,转载请注明出处。
See also
Teddy van Jerry 的导航页
【C++ 程序】 井字棋游戏(人 VS 人)
【C++ 程序】 井字棋游戏(人 VS Lv1电脑)
【C++ 程序】 井字棋游戏(人 VS Lv2电脑)
【C++ 程序】 井字棋游戏(人 VS Lv3电脑)
【C++ 程序】 井字棋游戏(人 VS Lv3电脑)(战绩统计版)
【C++ 程序】 五子棋游戏(人 VS 人)
【C++ 程序】 移动迷宫游戏
【C++ 程序】 随机数
【C++ 程序】 贪吃蛇游戏
【C++ 程序】 2048游戏
【C++ 程序】 井字棋游戏(人 VS 人)(EasyX 图形界面)
【C++ 程序】 井字棋游戏(人 VS Lv3电脑)(战绩统计版)(EasyX 图形界面)
问一下有没有发现bug的图有些异样?这其实是 Snake Game 里的,但被我用 3D Paint 给改过了。