You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C语言编写的黑白棋(Reversi)Bot算法接入Web应用?

实现Web GUI调用C语言黑白棋Bot的方案

方案一:将C Bot封装为HTTP API服务

这是最通用的落地方案,Web前端通过HTTP请求调用Bot接口获取落子结果,无需修改原有C算法逻辑。

步骤1:为C Bot添加网络服务层

选用轻量级C语言HTTP库(如libmicrohttpd、mongoose)快速搭建HTTP服务,核心是定义API接口并处理请求:

  • 定义POST接口/api/reversi/move,请求体以JSON格式传递当前棋盘状态(例:{"board": [[0,0,1,...], ...], "currentPlayer": 1},0为空、1为黑、2为白)
  • 在C服务中解析请求数据,调用已有的Bot算法计算最优落子,再返回JSON格式的落子坐标(例:{"row": 3, "col": 4})

简化代码框架示例:

#include <stdio.h>
#include <string.h>
#include "microhttpd.h"
#include "reversi_bot.h" // 你的Bot算法头文件

static int handle_post_request(void *cls, struct MHD_Connection *connection,
                               const char *url, const char *method,
                               const char *version, const char *upload_data,
                               size_t *upload_data_size, void **con_cls) {
    if (strcmp(url, "/api/reversi/move") != 0 || strcmp(method, "POST") != 0) {
        return MHD_NO;
    }

    // 这里需要实际解析上传的JSON数据,提取棋盘和玩家信息
    int board[8][8] = {0}; // 示例棋盘数据
    int current_player = 1;
    // 调用你的Bot算法计算落子
    int row, col;
    bot_calculate_move(board, current_player, &row, &col);

    // 构造JSON响应
    char response[100];
    snprintf(response, sizeof(response), "{\"row\": %d, \"col\": %d}", row, col);
    struct MHD_Response *mhd_response = MHD_create_response_from_buffer(strlen(response),
                                                                       (void *)response,
                                                                       MHD_RESPMEM_PERSISTENT);
    // 添加CORS头解决跨域问题
    MHD_add_response_header(mhd_response, "Access-Control-Allow-Origin", "*");
    int ret = MHD_queue_response(connection, MHD_HTTP_OK, mhd_response);
    MHD_destroy_response(mhd_response);
    return ret;
}

int main() {
    struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD,
                                                 8080, NULL, NULL,
                                                 &handle_post_request, NULL,
                                                 MHD_OPTION_END);
    if (!daemon) return 1;
    getchar();
    MHD_stop_daemon(daemon);
    return 0;
}

步骤2:Web前端调用API

在Web GUI中,当需要Bot落子时,用JavaScript发送POST请求:

async function requestBotMove(board, currentPlayer) {
    try {
        const response = await fetch('http://localhost:8080/api/reversi/move', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ board, currentPlayer })
        });
        const move = await response.json();
        // 根据返回的row和col更新棋盘UI
        updateBoard(move.row, move.col, currentPlayer);
    } catch (err) {
        console.error('请求Bot失败:', err);
    }
}

步骤3:部署注意事项

  • 若前端与C服务不在同一域名/端口,需在C服务中添加CORS响应头(如上述代码中的Access-Control-Allow-Origin)
  • 生产环境可将C服务部署在服务器,前端静态页面部署到Nginx等静态资源服务器,或用Nginx反向代理统一域名

方案二:将C Bot编译为WebAssembly(Wasm)

直接把C代码编译为Wasm,让Web前端在浏览器中直接调用,无需额外后端服务,延迟更低。

步骤1:用Emscripten编译C代码

安装Emscripten工具链后,编写暴露给JS的C接口:

#include "reversi_bot.h"

// 暴露给JS的函数:接收一维棋盘数组、玩家,返回编码后的落子(row*8+col)
int get_bot_move(int* board, int player) {
    int board_2d[8][8];
    // 将一维数组转为Bot需要的二维格式
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            board_2d[i][j] = board[i*8 + j];
        }
    }
    int row, col;
    bot_calculate_move(board_2d, player, &row, &col);
    return row * 8 + col;
}

执行编译命令生成Wasm及JS桥接文件:

emcc reversi_bot.c -o reversi_bot.js -s EXPORTED_FUNCTIONS='["_get_bot_move", "_malloc", "_free"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'

步骤2:前端调用Wasm函数

在HTML中引入生成的reversi_bot.js,调用Bot函数:

// Wasm初始化完成后执行
Module.onRuntimeInitialized = function() {
    // 构造一维棋盘数组
    const board = new Int32Array(64).fill(0);
    board[27] = 1; board[28] = 2;
    board[35] = 2; board[36] = 1;
    const currentPlayer = 1;

    // 分配内存存储棋盘数据
    const ptr = Module._malloc(board.length * 4);
    Module.HEAP32.set(board, ptr / 4);
    // 调用C函数
    const result = Module._get_bot_move(ptr, currentPlayer);
    // 解析落子坐标
    const row = Math.floor(result / 8);
    const col = result % 8;
    // 释放内存
    Module._free(ptr);

    console.log(`Bot落子:行${row},列${col}`);
    updateBoard(row, col, currentPlayer);
};

方案三:用Node.js作为中间层

若熟悉Node.js,可将C Bot编译为Node.js原生模块,再用Node.js搭建API服务,兼顾开发效率与性能。

步骤1:编译C代码为Node.js模块

编写binding.gyp配置文件:

{
  "targets": [
    {
      "target_name": "reversi_bot",
      "sources": ["reversi_bot.c", "addon.c"]
    }
  ]
}

编写addon.c暴露接口给Node.js:

#include <node.h>
#include "reversi_bot.h"

namespace reversi {
    using v8::FunctionCallbackInfo;
    using v8::Isolate;
    using v8::Local;
    using v8::Object;
    using v8::Number;
    using v8::Value;

    void GetBotMove(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        // 解析传入的棋盘数组和玩家
        Local<Object> boardObj = args[0].As<Object>();
        int player = args[1].As<Number>()->Value();
        
        int board[8][8];
        // 从JS对象提取棋盘数据
        for (int i = 0; i < 8; i++) {
            Local<Object> rowObj = boardObj->Get(isolate, i).As<Object>();
            for (int j = 0; j < 8; j++) {
                board[i][j] = rowObj->Get(isolate, j).As<Number>()->Value();
            }
        }

        int row, col;
        bot_calculate_move(board, player, &row, &col);

        // 返回落子结果
        Local<Object> result = Object::New(isolate);
        result->Set(isolate, "row", Number::New(isolate, row));
        result->Set(isolate, "col", Number::New(isolate, col));
        args.GetReturnValue().Set(result);
    }

    void Initialize(Local<Object> exports) {
        NODE_SET_METHOD(exports, "getBotMove", GetBotMove);
    }

    NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
}

编译模块:

node-gyp configure build

步骤2:搭建Node.js API服务

用Express快速实现接口:

const express = require('express');
const reversiBot = require('./build/Release/reversi_bot');
const app = express();
app.use(express.json());

app.post('/api/reversi/move', (req, res) => {
    const { board, currentPlayer } = req.body;
    const move = reversiBot.getBotMove(board, currentPlayer);
    res.json(move);
});

app.listen(3000, () => {
    console.log('服务运行在端口3000');
});

前端同样通过fetch请求该接口即可。


内容的提问来源于stack exchange,提问作者agrimshar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:27:14