STM32井字棋无视觉方案:传感器检测与AI算法实战
最近在准备电赛的同学应该都注意到了,2024年电赛E题"井字棋装置"确实是个热门题目。很多队伍都在纠结视觉方案的成本和复杂度问题,特别是对于大一新生来说,视觉识别系统的搭建确实存在不小的技术门槛。本文将分享一套完整的无视觉方案实现思路,从基础原理到代码实现,帮助大家用更简单的方式完成1-6问的全部要求。
1. 井字棋电赛题目解析与无视觉方案优势
1.1 2024年电赛E题核心要求分析
2024年全国大学生电子设计竞赛E题"井字棋装置"主要考察参赛选手在自动控制、人机交互和智能决策方面的综合能力。题目要求设计一个能够自动运行井字棋游戏的装置,实现人机对弈功能。
从题目要求来看,核心功能点包括:
- 棋盘状态检测:实时获取棋盘上棋子的分布情况
- 落子机制:实现机械臂或其它执行机构在指定位置落子
- 决策算法:设计合理的AI算法进行智能对弈
- 胜负判断:实时判断游戏状态并显示结果
- 人机交互:提供友好的操作界面和提示信息
1.2 无视觉方案的技术优势
传统方案多采用摄像头进行棋盘状态识别,但这种方法存在以下痛点:
- 环境光线影响大,识别稳定性难以保证
- 图像处理算法复杂,对处理器要求高
- 摄像头标定和安装精度要求严格
- 整体成本较高,调试周期长
无视觉方案通过传感器直接检测棋盘状态,具有明显优势:
- 响应速度快,实时性更好
- 稳定性高,不受光照条件影响
- 硬件成本低,适合学生预算
- 调试简单,上手难度低
1.3 方案整体架构设计
我们的无视觉方案采用分层架构设计:
传感器层 → 信号处理层 → 决策控制层 → 执行机构层 ↓ ↓ ↓ ↓ 棋盘检测 状态解析 AI算法 落子控制这种架构确保了系统的模块化和可扩展性,每个层次都可以独立开发和测试。
2. 硬件系统搭建与元器件选型
2.1 核心控制器选择
对于大一新生来说,STM32系列单片机是最佳选择。推荐使用STM32F103C8T6最小系统板,理由如下:
- 资源丰富:72MHz主频,64KB Flash,20KB RAM
- 开发简单:有完善的HAL库和丰富的教程资源
- 成本低廉:核心板价格在10-15元之间
- 外设齐全:足够支持本项目所有功能需求
// 系统时钟配置示例 void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 配置HSE振荡器 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&RCC_OscInitStruct); // 配置系统时钟 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); }2.2 棋盘状态检测方案
采用9个红外对管传感器阵列检测棋盘状态,每个格子对应一对红外发射和接收管:
// 红外传感器引脚定义 #define SENSOR_ROW1_PINS {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2} #define SENSOR_ROW2_PINS {GPIO_PIN_3, GPIO_PIN_4, GPIO_PIN_5} #define SENSOR_ROW3_PINS {GPIO_PIN_6, GPIO_PIN_7, GPIO_PIN_8} // 传感器状态读取函数 uint8_t read_board_status(void) { uint8_t board[3][3] = {0}; // 扫描第一行传感器 for(int col = 0; col < 3; col++) { HAL_GPIO_WritePin(SENSOR_POWER_GPIO_Port, SENSOR_POWER_Pin, GPIO_PIN_SET); HAL_Delay(1); // 短暂延时确保传感器稳定 board[0][col] = HAL_GPIO_ReadPin(SENSOR_GPIO_Port, SENSOR_ROW1_PINS[col]); HAL_GPIO_WritePin(SENSOR_POWER_GPIO_Port, SENSOR_POWER_Pin, GPIO_PIN_RESET); } // 同理扫描第二、三行 // ... return encode_board_status(board); }2.3 落子执行机构设计
采用二自由度机械臂结构,使用SG90舵机实现精准控制:
// 舵机控制参数定义 typedef struct { uint16_t current_angle; uint16_t target_angle; TIM_HandleTypeDef* htim; uint32_t channel; } Servo_TypeDef; // 舵机初始化函数 void servo_init(Servo_TypeDef* servo, TIM_HandleTypeDef* htim, uint32_t channel) { servo->htim = htim; servo->channel = channel; servo->current_angle = 90; // 初始位置 servo->target_angle = 90; // 启动PWM输出 HAL_TIM_PWM_Start(htim, channel); servo_set_angle(servo, 90); } // 设置舵机角度 void servo_set_angle(Servo_TypeDef* servo, uint16_t angle) { if(angle > 180) angle = 180; uint16_t pulse_width = 500 + (angle * 2000 / 180); // 0.5ms-2.5ms __HAL_TIM_SET_COMPARE(servo->htim, servo->channel, pulse_width); servo->current_angle = angle; }3. 棋盘状态检测与数据处理
3.1 传感器数据处理算法
红外传感器数据需要经过滤波处理以提高稳定性:
// 传感器数据滤波结构体 typedef struct { uint8_t raw_data[10]; // 原始数据缓冲区 uint8_t filtered_data; // 滤波后数据 uint8_t buffer_index; // 缓冲区索引 uint8_t stable_count; // 稳定计数 } SensorFilter_TypeDef; // 中值滤波算法 uint8_t median_filter(SensorFilter_TypeDef* filter, uint8_t new_data) { // 更新数据缓冲区 filter->raw_data[filter->buffer_index] = new_data; filter->buffer_index = (filter->buffer_index + 1) % 10; // 复制数据并排序 uint8_t temp[10]; memcpy(temp, filter->raw_data, sizeof(temp)); // 冒泡排序 for(int i = 0; i < 9; i++) { for(int j = 0; j < 9 - i; j++) { if(temp[j] > temp[j+1]) { uint8_t swap = temp[j]; temp[j] = temp[j+1]; temp[j+1] = swap; } } } // 取中值 return (temp[4] + temp[5]) / 2; } // 传感器状态更新函数 uint8_t update_sensor_status(SensorFilter_TypeDef* filter, uint8_t new_reading) { uint8_t filtered = median_filter(filter, new_reading); if(filtered == filter->filtered_data) { filter->stable_count++; } else { filter->stable_count = 0; filter->filtered_data = filtered; } // 连续5次读数稳定才确认状态变化 if(filter->stable_count >= 5) { return filter->filtered_data; } return 0xFF; // 表示状态未稳定 }3.2 棋盘状态编码与解码
为了高效处理棋盘状态,我们采用位编码方式:
// 棋盘状态编码 uint16_t encode_board_state(uint8_t board[3][3]) { uint16_t encoded = 0; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { uint8_t pos = i * 3 + j; if(board[i][j] == 1) { // 玩家棋子 encoded |= (1 << pos); } else if(board[i][j] == 2) { // AI棋子 encoded |= (1 << (pos + 9)); } } } return encoded; } // 棋盘状态解码 void decode_board_state(uint16_t encoded, uint8_t board[3][3]) { for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { uint8_t pos = i * 3 + j; if(encoded & (1 << pos)) { board[i][j] = 1; // 玩家棋子 } else if(encoded & (1 << (pos + 9))) { board[i][j] = 2; // AI棋子 } else { board[i][j] = 0; // 空位置 } } } } // 棋盘状态打印函数(调试用) void print_board(uint8_t board[3][3]) { printf("\n当前棋盘状态:\n"); printf("-------------\n"); for(int i = 0; i < 3; i++) { printf("|"); for(int j = 0; j < 3; j++) { if(board[i][j] == 0) printf(" |"); else if(board[i][j] == 1) printf(" X |"); else printf(" O |"); } printf("\n-------------\n"); } }4. 井字棋AI算法实现
4.1 极小化极大算法基础
井字棋是个完全信息零和游戏,适合使用极小化极大算法:
// 游戏状态评估函数 int evaluate_board(uint8_t board[3][3]) { // 检查行 for(int i = 0; i < 3; i++) { if(board[i][0] == board[i][1] && board[i][1] == board[i][2]) { if(board[i][0] == 2) return +10; // AI获胜 else if(board[i][0] == 1) return -10; // 玩家获胜 } } // 检查列 for(int j = 0; j < 3; j++) { if(board[0][j] == board[1][j] && board[1][j] == board[2][j]) { if(board[0][j] == 2) return +10; else if(board[0][j] == 1) return -10; } } // 检查对角线 if(board[0][0] == board[1][1] && board[1][1] == board[2][2]) { if(board[0][0] == 2) return +10; else if(board[0][0] == 1) return -10; } if(board[0][2] == board[1][1] && board[1][1] == board[2][0]) { if(board[0][2] == 2) return +10; else if(board[0][2] == 1) return -10; } return 0; // 平局或未结束 } // 检查是否还有空位置 int is_moves_left(uint8_t board[3][3]) { for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) return 1; } } return 0; }4.2 极小化极大算法实现
// 极小化极大算法核心函数 int minimax(uint8_t board[3][3], int depth, int is_maximizing) { int score = evaluate_board(board); // 如果AI获胜,返回正分 if(score == 10) return score - depth; // 如果玩家获胜,返回负分 if(score == -10) return score + depth; // 如果没有可走的位置,平局 if(!is_moves_left(board)) return 0; // AI回合(最大化分数) if(is_maximizing) { int best = -1000; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) { board[i][j] = 2; // AI落子 best = max(best, minimax(board, depth + 1, 0)); board[i][j] = 0; // 撤销落子 } } } return best; } // 玩家回合(最小化分数) else { int best = 1000; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) { board[i][j] = 1; // 玩家落子 best = min(best, minimax(board, depth + 1, 1)); board[i][j] = 0; // 撤销落子 } } } return best; } } // 寻找最佳落子位置 void find_best_move(uint8_t board[3][3], int* best_row, int* best_col) { int best_val = -1000; *best_row = -1; *best_col = -1; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) { board[i][j] = 2; // 尝试AI落子 int move_val = minimax(board, 0, 0); board[i][j] = 0; // 撤销落子 if(move_val > best_val) { *best_row = i; *best_col = j; best_val = move_val; } } } } }4.3 算法优化与剪枝
为了提升算法效率,我们加入Alpha-Beta剪枝:
// 带Alpha-Beta剪枝的极小化极大算法 int minimax_ab(uint8_t board[3][3], int depth, int is_maximizing, int alpha, int beta) { int score = evaluate_board(board); if(score == 10) return score - depth; if(score == -10) return score + depth; if(!is_moves_left(board)) return 0; if(is_maximizing) { int best = -1000; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) { board[i][j] = 2; int val = minimax_ab(board, depth + 1, 0, alpha, beta); board[i][j] = 0; best = max(best, val); alpha = max(alpha, best); if(beta <= alpha) break; // Beta剪枝 } } } return best; } else { int best = 1000; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 0) { board[i][j] = 1; int val = minimax_ab(board, depth + 1, 1, alpha, beta); board[i][j] = 0; best = min(best, val); beta = min(beta, best); if(beta <= alpha) break; // Alpha剪枝 } } } return best; } }5. 机械臂运动控制与路径规划
5.1 坐标系统建立
建立棋盘坐标系与机械臂运动坐标的映射关系:
// 棋盘坐标定义 typedef struct { float x; // 机械臂X坐标 float y; // 机械臂Y坐标 } BoardPosition; // 棋盘位置映射表 const BoardPosition board_positions[3][3] = { {{-40.0, 40.0}, {0.0, 40.0}, {40.0, 40.0}}, // 第一行 {{-40.0, 0.0}, {0.0, 0.0}, {40.0, 0.0}}, // 第二行 {{-40.0, -40.0},{0.0, -40.0},{40.0, -40.0}} // 第三行 }; // 棋子仓库位置 const BoardPosition piece_storage = {50.0, 50.0}; // 当前机械臂位置 BoardPosition current_arm_position = {0.0, 0.0};5.2 运动轨迹规划
实现平滑的运动轨迹控制:
// 轨迹规划函数 void plan_trajectory(BoardPosition start, BoardPosition end, BoardPosition* trajectory, int* step_count) { float dx = end.x - start.x; float dy = end.y - start.y; float distance = sqrt(dx*dx + dy*dy); *step_count = (int)(distance / 2.0) + 1; // 每2mm一个步进 for(int i = 0; i < *step_count; i++) { float ratio = (float)i / (*step_count - 1); trajectory[i].x = start.x + dx * ratio; trajectory[i].y = start.y + dy * ratio; } } // 执行运动轨迹 void execute_trajectory(BoardPosition* trajectory, int step_count) { for(int i = 0; i < step_count; i++) { // 控制X轴舵机 float x_angle = position_to_angle_x(trajectory[i].x); servo_set_angle(&servo_x, x_angle); // 控制Y轴舵机 float y_angle = position_to_angle_y(trajectory[i].y); servo_set_angle(&servo_y, y_angle); HAL_Delay(20); // 运动间隔 } // 更新当前位置 current_arm_position = trajectory[step_count - 1]; } // 坐标到角度的转换函数 float position_to_angle_x(float x) { // 机械臂运动学正解计算 // 这里需要根据实际机械结构进行调整 return 90.0 + x * 180.0 / 100.0; // 示例转换公式 } float position_to_angle_y(float y) { return 90.0 + y * 180.0 / 100.0; }5.3 完整的落子流程控制
// 完整的落子操作 void make_move(int row, int col) { BoardPosition target = board_positions[row][col]; BoardPosition trajectory[50]; int step_count; printf("AI落子位置: (%d, %d)\n", row, col); // 1. 移动到棋子仓库 plan_trajectory(current_arm_position, piece_storage, trajectory, &step_count); execute_trajectory(trajectory, step_count); // 2. 抓取棋子 grab_piece(); HAL_Delay(500); // 3. 移动到目标位置上方 BoardPosition above_target = {target.x, target.y + 10.0}; plan_trajectory(current_arm_position, above_target, trajectory, &step_count); execute_trajectory(trajectory, step_count); // 4. 下降到落子位置 plan_trajectory(current_arm_position, target, trajectory, &step_count); execute_trajectory(trajectory, step_count); // 5. 释放棋子 release_piece(); HAL_Delay(300); // 6. 抬起到安全高度 plan_trajectory(current_arm_position, above_target, trajectory, &step_count); execute_trajectory(trajectory, step_count); printf("落子完成\n"); } // 抓取和释放棋子函数 void grab_piece(void) { servo_set_angle(&servo_gripper, 0); // 闭合夹爪 } void release_piece(void) { servo_set_angle(&servo_gripper, 90); // 打开夹爪 }6. 系统集成与主控程序
6.1 主程序状态机设计
采用状态机模式管理游戏流程:
// 游戏状态定义 typedef enum { GAME_INIT, // 初始化 GAME_WAIT_PLAYER, // 等待玩家落子 GAME_CHECK_PLAYER, // 检测玩家落子 GAME_AI_THINK, // AI思考 GAME_AI_MOVE, // AI落子 GAME_CHECK_RESULT, // 检查游戏结果 GAME_OVER // 游戏结束 } GameState; // 游戏控制结构体 typedef struct { GameState current_state; uint8_t board[3][3]; uint8_t current_player; // 1:玩家, 2:AI uint8_t game_result; // 0:进行中, 1:玩家胜, 2:AI胜, 3:平局 } GameController; // 主控程序循环 void game_main_loop(void) { GameController game; game_init(&game); while(1) { switch(game.current_state) { case GAME_INIT: game_state_init(&game); break; case GAME_WAIT_PLAYER: game_state_wait_player(&game); break; case GAME_CHECK_PLAYER: game_state_check_player(&game); break; case GAME_AI_THINK: game_state_ai_think(&game); break; case GAME_AI_MOVE: game_state_ai_move(&game); break; case GAME_CHECK_RESULT: game_state_check_result(&game); break; case GAME_OVER: game_state_over(&game); break; } HAL_Delay(10); // 防止CPU过载 } }6.2 各状态具体实现
// 初始化状态 void game_state_init(GameController* game) { printf("井字棋游戏初始化...\n"); // 清空棋盘 memset(game->board, 0, sizeof(game->board)); game->current_player = 1; // 玩家先手 game->game_result = 0; // 机械臂回原点 arm_go_home(); // 显示欢迎信息 display_show_message("欢迎玩井字棋!"); game->current_state = GAME_WAIT_PLAYER; } // 等待玩家落子状态 void game_state_wait_player(GameController* game) { display_show_message("请落子..."); // 检测玩家操作 if(detect_player_move()) { game->current_state = GAME_CHECK_PLAYER; } } // 检测玩家落子状态 void game_state_check_player(GameController* game) { uint8_t new_board[3][3]; if(read_board_status(new_board)) { // 找出玩家落子的位置 int move_row, move_col; if(find_player_move(game->board, new_board, &move_row, &move_col)) { // 验证落子合法性 if(is_valid_move(game->board, move_row, move_col)) { game->board[move_row][move_col] = 1; printf("玩家落子: (%d, %d)\n", move_row, move_col); print_board(game->board); game->current_state = GAME_CHECK_RESULT; } else { display_show_message("无效落子,请重试"); game->current_state = GAME_WAIT_PLAYER; } } } } // AI思考状态 void game_state_ai_think(GameController* game) { display_show_message("AI思考中..."); int best_row, best_col; find_best_move(game->board, &best_row, &best_col); game->board[best_row][best_col] = 2; game->ai_next_row = best_row; game->ai_next_col = best_col; game->current_state = GAME_AI_MOVE; } // AI落子状态 void game_state_ai_move(GameController* game) { make_move(game->ai_next_row, game->ai_next_col); print_board(game->board); game->current_state = GAME_CHECK_RESULT; } // 检查游戏结果状态 void game_state_check_result(GameController* game) { int result = check_game_result(game->board); if(result != 0) { game->game_result = result; game->current_state = GAME_OVER; } else { // 切换玩家 game->current_player = (game->current_player == 1) ? 2 : 1; if(game->current_player == 1) { game->current_state = GAME_WAIT_PLAYER; } else { game->current_state = GAME_AI_THINK; } } } // 游戏结束状态 void game_state_over(GameController* game) { switch(game->game_result) { case 1: display_show_message("玩家获胜!"); printf("游戏结束:玩家获胜\n"); break; case 2: display_show_message("AI获胜!"); printf("游戏结束:AI获胜\n"); break; case 3: display_show_message("平局!"); printf("游戏结束:平局\n"); break; } // 等待重启信号 if(detect_restart_signal()) { game->current_state = GAME_INIT; } }7. 人机交互与显示界面
7.1 OLED显示模块集成
使用SSD1306 OLED显示屏显示游戏状态:
// OLED显示初始化 void oled_init(void) { // SSD1306初始化序列 uint8_t init_cmds[] = { 0xAE, // 关闭显示 0xD5, 0x80, // 设置显示时钟分频 0xA8, 0x3F, // 设置多路复用率 0xD3, 0x00, // 设置显示偏移 0x40, // 设置显示起始行 0x8D, 0x14, // 电荷泵设置 0x20, 0x00, // 内存地址模式 0xA1, // 段重映射 0xC8, // COM扫描方向 0xDA, 0x12, // COM引脚硬件配置 0x81, 0xCF, // 对比度设置 0xD9, 0xF1, // 预充电周期 0xDB, 0x40, // VCOMH电平 0xA4, // 整体显示开启 0xA6, // 正常显示 0xAF // 开启显示 }; for(int i = 0; i < sizeof(init_cmds); i++) { oled_write_cmd(init_cmds[i]); } } // 显示棋盘函数 void oled_draw_board(uint8_t board[3][3]) { oled_clear(); // 绘制棋盘网格 for(int i = 1; i <= 2; i++) { oled_draw_line(i*32, 0, i*32, 96, WHITE); oled_draw_line(0, i*32, 96, i*32, WHITE); } // 绘制棋子 for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 1) { // 绘制X(玩家) oled_draw_line(j*32+8, i*32+8, j*32+24, i*32+24, WHITE); oled_draw_line(j*32+24, i*32+8, j*32+8, i*32+24, WHITE); } else if(board[i][j] == 2) { // 绘制O(AI) oled_draw_circle(j*32+16, i*32+16, 8, WHITE); } } } oled_update(); }7.2 用户输入处理
使用按钮和LED指示灯提供交互:
// 按钮检测函数 uint8_t read_buttons(void) { uint8_t buttons = 0; if(HAL_GPIO_ReadPin(BTN_START_GPIO_Port, BTN_START_Pin) == GPIO_PIN_RESET) { buttons |= BTN_START; } if(HAL_GPIO_ReadPin(BTN_RESTART_GPIO_Port, BTN_RESTART_Pin) == GPIO_PIN_RESET) { buttons |= BTN_RESTART; } return buttons; } // LED控制函数 void set_led_status(uint8_t status) { HAL_GPIO_WritePin(LED_PLAYER_GPIO_Port, LED_PLAYER_Pin, (status & LED_PLAYER) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_AI_GPIO_Port, LED_AI_Pin, (status & LED_AI) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(LED_WIN_GPIO_Port, LED_WIN_Pin, (status & LED_WIN) ? GPIO_PIN_SET : GPIO_PIN_RESET); }8. 系统调试与性能优化
8.1 调试信息输出
通过串口输出详细的调试信息:
// 调试信息输出函数 void debug_print(const char* format, ...) { char buffer[128]; va_list args; va_start(args, format); vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 1000); } // 传感器数据调试 void debug_sensor_data(void) { uint8_t board[3][3]; if(read_board_status(board)) { debug_print("传感器原始数据:\n"); for(int i = 0; i < 3; i++) { debug_print("行%d: %d %d %d\n", i, board[i][0], board[i][1], board[i][2]); } } } // 机械臂位置调试 void debug_arm_position(void) { debug_print("机械臂位置: X=%.1f, Y=%.1f\n", current_arm_position.x, current_arm_position.y); }8.2 性能优化技巧
针对STM32的资源限制进行优化:
// 使用查表法优化三角函数计算 const float sin_table[91] = { 0.0000, 0.0175, 0.0349, 0.0523, 0.0698, // 0-4度 // ... 完整的正弦表 1.0000 // 90度 }; float fast_sin(float angle) { while(angle < 0) angle += 360; while(angle >= 360) angle -= 360; int index = (int)angle; if(index <= 90) return sin_table[index]; else if(index <= 180) return sin_table[180-index]; else if(index <= 270) return -sin_table[index-180]; else return -sin_table[360-index]; } // 优化棋盘评估函数 int fast_evaluate(uint8_t board[3][3]) { // 使用位运算快速检查胜负 uint16_t player_bits = 0; uint16_t ai_bits = 0; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(board[i][j] == 1) player_bits |= (1 << (i*3+j)); else if(board[i][j] == 2) ai_bits |= (1 << (i*3+j)); } } // 胜利模式掩码 const uint16_t win_patterns[8] = { 0x007, 0x038, 0x1C0, // 行 0x049, 0x092, 0x124, // 列 0x111, 0x054 // 对角线 }; for(int i = 0; i < 8; i++) { if((player_bits & win_patterns[i]) == win_patterns[i]) return -10; if((ai_bits