通过C代码实现的连连看小游戏,以下是源码和注释:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h> //Windows平台相关函数
#define MAXROW 9
#define MAXCOL 16 //游戏图板的最大行数(Row)和最大列数(Column)
typedef unsigned char bool;
#define true 1
#define false 0
int brd[MAXROW + 2][MAXCOL + 2]; //描述图板(board)的二维整型数组
int row, col, pic; //游戏中使用的图板的行数和列数,游戏中的图片种类数
int X0 = 0, Y0 = 1; //绘制图板时的左上角起始坐标(X0, Y0)
typedef struct Dot { //平面点坐标结构体类型struct Dot
int x, y;
} Dot; //用typedef命令定义类型别名Dot
void gotoxy(short x, short y) { //定位光标位置到(x,y)
static COORD crd; //定义结构体变量crd(使用频繁,所以定义为静态变量)
crd.X = x;
crd.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), crd);
}
void showcursor(bool visible) { //显示或隐藏光标
CONSOLE_CURSOR_INFO cursor = { 20, visible };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor);
}
void clrscr() { //清空屏幕
HANDLE hdout = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出设备的句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义表示屏幕缓冲区属性的变量
GetConsoleScreenBufferInfo(hdout, &csbi); //获取标准输出设备的屏幕缓冲区属性
DWORD size = csbi.dwSize.X * csbi.dwSize.Y, num = 0; //定义双字节变量
COORD pos = { 0, 0 }; //表示坐标的变量(初始化为左上角(0, 0)点)
//把窗口缓冲区全部填充为空格并填充为默认颜色(清屏)
FillConsoleOutputCharacter(hdout, ' ', size, pos, &num);
FillConsoleOutputAttribute(hdout, csbi.wAttributes, size, pos, &num);
SetConsoleCursorPosition(hdout, pos); //光标定位到窗口左上角
}
void initBoard(int level) { //根据游戏难度(level)初始化图板
int ix, iy, jx, jy, k;
//整个图板(MAXROW行 * MAXCOL列)初始化为空
for (iy = 0; iy < MAXROW; iy++)
for (ix = 0; ix < MAXCOL; ix++)
brd[iy][ix] = 0;
//根据游戏难度(level:0-容易; 1-中等; 2-困难)设定图板的行列数和所使用的牌面种类
row = (level == 0 ? 7 : (level == 1 ? 8 : 9)); //行数
col = (level == 0 ? 12 : (level == 1 ? 14 : 16)); //列数(必须为偶数)
pic = row * col / 4; //牌面种类数:每种牌面出现4次,三种难度下分别为21、28、36
//在游戏图板(row行 * col列)范围内,左右对称地顺序填入牌面编号1--pic
for (iy = 1, k = 0; iy <= row; iy++)
for (ix = 1; ix <= col / 2; ix++)
brd[iy][ix] = brd[iy][col / 2 + ix] = (k++) % pic + 1;
//把已经顺序对称填入的牌面编号随机打乱
for (iy = 1; iy <= row; iy++)
for (ix = 1; ix <= col; ix++) {
jx = rand() % col + 1;
jy = rand() % row + 1;
k = brd[iy][ix];
brd[iy][ix] = brd[jy][jx];
brd[jy][jx] = k;
}
return;
}
enum COLORS {
BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY,
LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE
}; //定义表示颜色的枚举类型,枚举元素值为0--15
void drawxy(int x, int y, int bright) { //绘制图板中坐标为(x, y)的格点,bright为是否高亮
static HANDLE hdout = 0;
static char mark[37][3] = { " ", "●", "■", "□", "◆", "◇", "◎", "★",
"☆", "☉", "▲", "△", "▼", "▽", "@", "#", "*", "=",
"A", "B", "C", "D", "天", "地", "山", "水", "日", "月", "星",
"T", "U", "W", "X", "鸟", "花", "虫", "鱼"
};
hdout = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄
gotoxy(X0 + x * 2, Y0 + y);
if (bright)
SetConsoleTextAttribute(hdout, GREEN * 16 + YELLOW); //绿底黄字
else
SetConsoleTextAttribute(hdout, BLUE * 16 + WHITE); //蓝底白字
printf("%s", mark[brd[y][x]]); //输出牌面字符
return;
}
void drawBoard() { //绘制整个图板
// gotoxy(0, 0);
// cout << "连 连 看";
int ix, iy;
for (ix, iy = 0; iy <= row + 1; iy++)
for (ix = 0; ix <= col + 1; ix++)
drawxy(ix, iy, 0);
return;
}
void drawBtns(int level, int cur) { //在界面顶行绘制仿真按钮
int k;
static HANDLE hdout = 0;
char btns[7][7] = { "[新建]", "[容易]", "[中等]", "[困难]", "[提示]", "[混洗]", "[退出]" };
hdout = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄
for (k = 0; k < 7; k++) {
SetConsoleTextAttribute(hdout, BLACK * 16 + WHITE); //黑底白字
if (level + 1 == k) //游戏难度level 值为 0, 1, 2,对应 k 值为 1, 2, 3
SetConsoleTextAttribute(hdout, GREEN * 16 + WHITE); //绿底白字
if (cur == k) //鼠标当前悬浮所在的按钮
SetConsoleTextAttribute(hdout, WHITE * 16 + BLUE); //白底蓝字
gotoxy(8 * k, 0);
printf("%s",btns[k]);
}
SetConsoleTextAttribute(hdout, BLACK * 16 + WHITE); //默认黑底白字
return;
}
int turntype(Dot c1, Dot t, Dot c2) { //判断c1-t-c2的转折类型
if ((c1.y == t.y && c1.x > t.x && t.y > c2.y)