控制台版记忆翻牌:4×4 卡片,输入两个编号翻开,相同就配对,不同翻回去。练二维数组、随机洗牌和简单的"回合状态"。
1. 洗牌与数组
16 张卡片 = 0~7 各两张,用 Fisher-Yates 洗牌。记录"是否已配对"和"是否翻开":
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 16
int cards[N]; // 图案 0~7
int matched[N]; // 1=已配对
int open_a, open_b; // 当前翻开的两张(未翻开为 -1)
void shuffle(void) {
for (int i = N - 1; i > 0; i--) {
int j = rand() % (i + 1);
int t = cards[i]; cards[i] = cards[j]; cards[j] = t;
}
}
void init(void) {
for (int i = 0; i < N; i++) cards[i] = i / 2;
shuffle();
for (int i = 0; i < N; i++) matched[i] = 0;
open_a = open_b = -1;
}
2. 回合逻辑
玩家输入两个编号,检查合法性(未配对、未翻开),然后比较图案:
int play_round(int a, int b) {
if (a == b) return 0;
if (matched[a] || matched[b]) return 0;
open_a = a; open_b = b;
if (cards[a] == cards[b]) {
matched[a] = matched[b] = 1;
return 1;
}
return -1;
}
3. 完整代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 16
#define COLS 4
int cards[N];
int matched[N];
int open_a, open_b;
int moves = 0;
void shuffle(void) {
for (int i = N - 1; i > 0; i--) {
int j = rand() % (i + 1);
int t = cards[i]; cards[i] = cards[j]; cards[j] = t;
}
}
void init(void) {
for (int i = 0; i < N; i++) cards[i] = i / 2;
shuffle();
for (int i = 0; i < N; i++) matched[i] = 0;
open_a = open_b = -1;
moves = 0;
}
void draw(void) {
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 4; c++) {
int i = r * COLS + c;
if (matched[i]) printf(" * ");
else if (i == open_a || i == open_b) printf(" %d ", cards[i]);
else printf(" _ ");
}
printf("\n");
}
printf("步数: %d\n", moves);
}
int main(void) {
srand((unsigned)time(NULL));
init();
while (1) {
draw();
int a, b;
printf("翻开两张(0-15,空格隔开,q退出): ");
fflush(stdout);
char cmd[8];
if (scanf("%7s", cmd) == 1 && cmd[0] == 'q') break;
sscanf(cmd, "%d", &a);
if (scanf("%d", &b) != 1) continue;
if (a < 0 || a >= N || b < 0 || b >= N) continue;
if (a == b || matched[a] || matched[b]) { printf("无效选择\n"); continue; }
moves++;
open_a = a; open_b = b;
draw();
if (cards[a] == cards[b]) {
matched[a] = matched[b] = 1;
printf("配对成功!\n");
} else {
printf("不匹配,记住它们~\n");
}
open_a = open_b = -1;
int done = 1;
for (int i = 0; i < N; i++) if (!matched[i]) done = 0;
if (done) { printf("通关!用了 %d 步\n", moves); break; }
}
return 0;
}
4. 运行与常见问题
保存为 memory.c,gcc memory.c -o memory 后运行。常见问题:①洗牌不随机——记得 srand(time(NULL)) 播种;②输入非法导致死循环——用 scanf 返回值判断;③想看图案再翻回去——翻回逻辑由"下一轮 open_a=open_b=-1"实现。
💡 改进方向:①6×6 更大棋盘;②计时;③图案改成 ASCII 字符更直观;④配对音效(beep);⑤步数排行榜。