控制台版记忆翻牌: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);⑤步数排行榜。