4. 洗衣机程序状态机

任务说明

设计一个洗衣机控制程序的状态机,覆盖从启动到结束的完整洗涤流程。程序需要管理以下核心状态:注水、洗涤、漂洗、脱水,并支持用户随时暂停(暂停后可在当前阶段继续)和取消(终止程序并排水)。本案例使用C语言实现一个轻量级状态机,不依赖特定硬件平台,通过标准输入模拟用户操作,便于独立编译和验证。

状态定义与迁移逻辑

状态触发事件动作下一状态
IDLE(待机)START启动注水FILL
FILL(注水)WATER_FULL开始洗涤WASH
WASH(洗涤)WASH_DONE开始漂洗RINSE
RINSE(漂洗)RINSE_DONE开始脱水SPIN
SPIN(脱水)SPIN_DONE流程结束COMPLETE
PAUSE(暂停)RESUME恢复原状态原状态
任意运行态CANCEL排水、停机IDLE

完整实现代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum {
    IDLE, FILL, WASH, RINSE, SPIN, PAUSE, COMPLETE
} State;

typedef enum {
    EV_START, EV_WATER_FULL, EV_WASH_DONE, EV_RINSE_DONE,
    EV_SPIN_DONE, EV_PAUSE, EV_RESUME, EV_CANCEL
} Event;

const char* state_name(State s) {
    switch(s) {
        case IDLE: return "IDLE(待机)";
        case FILL: return "FILL(注水)";
        case WASH: return "WASH(洗涤)";
        case RINSE: return "RINSE(漂洗)";
        case SPIN: return "SPIN(脱水)";
        case PAUSE: return "PAUSE(暂停)";
        case COMPLETE: return "COMPLETE(完成)";
    }
    return "UNKNOWN";
}

// 状态机核心:返回迁移后的新状态
State transition(State current, Event ev, State* saved_state) {
    // 暂停状态特殊处理:只有RESUME和CANCEL有效
    if (current == PAUSE) {
        if (ev == EV_RESUME) return *saved_state;
        if (ev == EV_CANCEL) return IDLE;
        return current; // 其他事件在暂停时忽略
    }

    // 非暂停状态:若收到PAUSE,保存当前状态并进入暂停
    if (ev == EV_PAUSE) {
        if (current == FILL || current == WASH || current == RINSE || current == SPIN) {
            *saved_state = current;
            return PAUSE;
        }
        return current; // IDLE和COMPLETE不可暂停
    }

    // 取消事件:任何运行状态均可取消
    if (ev == EV_CANCEL) {
        if (current == FILL || current == WASH || current == RINSE || current == SPIN) {
            return IDLE;
        }
        return current;
    }

    // 正常流程迁移
    switch (current) {
        case IDLE:
            if (ev == EV_START) return FILL;
            break;
        case FILL:
            if (ev == EV_WATER_FULL) return WASH;
            break;
        case WASH:
            if (ev == EV_WASH_DONE) return RINSE;
            break;
        case RINSE:
            if (ev == EV_RINSE_DONE) return SPIN;
            break;
        case SPIN:
            if (ev == EV_SPIN_DONE) return COMPLETE;
            break;
        default:
            break;
    }
    return current; // 无效事件保持原状态
}

// 模拟操作:从标准输入读取事件字符串并转换
Event parse_event(const char* cmd) {
    if (strcmp(cmd, "start") == 0) return EV_START;
    if (strcmp(cmd, "full") == 0) return EV_WATER_FULL;
    if (strcmp(cmd, "wash_done") == 0) return EV_WASH_DONE;
    if (strcmp(cmd, "rinse_done") == 0) return EV_RINSE_DONE;
    if (strcmp(cmd, "spin_done") == 0) return EV_SPIN_DONE;
    if (strcmp(cmd, "pause") == 0) return EV_PAUSE;
    if (strcmp(cmd, "resume") == 0) return EV_RESUME;
    if (strcmp(cmd, "cancel") == 0) return EV_CANCEL;
    return -1; // 无效命令
}

int main() {
    State current = IDLE;
    State saved = IDLE; // 用于暂停时保存原状态
    char cmd[32];

    printf("洗衣机状态机已启动。可用命令:\n");
    printf("  start | full | wash_done | rinse_done | spin_done\n");
    printf("  pause | resume | cancel | quit\n");
    printf("当前状态: %s\n", state_name(current));

    while (1) {
        printf("> ");
        if (scanf("%31s", cmd) != 1) break;

        if (strcmp(cmd, "quit") == 0) break;

        Event ev = parse_event(cmd);
        if (ev == -1) {
            printf("无效命令,请重试。\n");
            continue;
        }

        State next = transition(current, ev, &saved);
        if (next != current) {
            printf("[状态迁移] %s --> %s\n", state_name(current), state_name(next));
            current = next;
        } else {
            printf("[事件被忽略] 当前状态 %s 不响应此事件。\n", state_name(current));
        }

        if (current == COMPLETE) {
            printf("洗涤流程完成!输入 start 可开始新一轮。\n");
            current = IDLE; // 自动回到待机,便于连续演示
        }
    }
    printf("程序退出。\n");
    return 0;
}

编译与运行

# 编译
gcc -o washer_fsm washer_fsm.c

# 运行
./washer_fsm

验证方法与通过标准

按以下顺序输入命令,观察状态迁移是否符合预期:

  1. 正常流程:依次输入 start → full → wash_done → rinse_done → spin_done,状态应依次从IDLE→FILL→WASH→RINSE→SPIN→COMPLETE,随后自动回到IDLE。
  2. 暂停/恢复:输入 start → full(进入WASH)→ pause(进入PAUSE)→ resume(应回到WASH而非其他状态)→ wash_done 继续后续流程。
  3. 取消:输入 start → pause → cancel,应从PAUSE回到IDLE;或在WASH状态直接输入 cancel,应回到IDLE。
  4. 无效事件:在IDLE状态输入 wash_done,应提示“事件被忽略”且状态不变。

以上操作均得到与预期一致的状态输出,且程序无崩溃,即可判定通过。

关键设计说明

状态机采用二维迁移表逻辑(事件驱动+状态判断),通过 saved_state 变量记录暂停前的运行状态,确保恢复时能精确回到中断点。取消操作在任意运行态(FILL/WASH/RINSE/SPIN)或PAUSE下均直接回到IDLE,模拟排水停机。COMPLETE状态仅作为流程终点的瞬时展示,随后自动复位以便连续运行。代码不依赖任何外部库,仅使用标准输入输出,便于在任何C编译环境中直接验证。