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

C++控制台国际象棋程序Unicode棋子显示为问号的问题排查

问题

我正在开发一款C++控制台国际象棋游戏,计划使用Unicode棋子符号显示棋盘,但黑后(♕)、白后(♛)等Unicode棋子符号均显示为问号(?)。

以下是我的代码:

#include "ChessGame.h"
#include <iostream>
#include <locale>
#include <codecvt>
#include <iomanip>
#include <Windows.h>

using namespace std;

const wchar_t* pieces[7] = { L"♕", L"♙", L"♖", L"♘", L"♗", L"♕", L"♔" };
const wchar_t* blackPieces[7] = { L"♛", L"♟", L"♜", L"♞", L"♝", L"♛", L"♚" };

ChessGame::ChessGame() : whiteTurn(true) {
    board = { {
        {-5, -3, -4, -7, -6, -4, -3, -5},
        {-1, -1, -1, -1, -1, -1, -1, -1},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 1,  1,  1,  1,  1,  1,  1,  1},
        { 5,  3,  4,  7,  6,  4,  3,  5}
    } };
}

void ChessGame::run() {
    SetConsoleOutputCP(CP_UTF8);
    wcout.imbue(locale("en_US.UTF-8"));

    while (true) {
        printBoard();
        wcout << (whiteTurn ? L"White's move." : L"Black's move.") << endl;
        wcout << L"Enter your move (e.g., e2 e4): ";
        string start, end;
        cin >> start >> end;

        int startX = start[0] - 'a';
        int startY = 8 - (start[1] - '0');
        int endX = end[0] - 'a';
        int endY = 8 - (end[1] - '0');

        if (isMoveValid(board[startY][startX], startX, startY, endX, endY)) {
            processMove(startX, startY, endX, endY);
            whiteTurn = !whiteTurn;
        } else {
            wcout << L"Invalid move. Try again." << endl;
        }
    }
}

void ChessGame::printBoard() {
    wcout << L"    A B C D E F G H" << endl;
    wcout << L"  +-----------------+" << endl;

    for (int y = 0; y < 8; ++y) {
        wcout << 8 - y << L" | ";
        for (int x = 0; x < 8; ++x) {
            int piece = board[y][x];

            if (piece > 6 || piece < -6) {
                wcout << L"?" << L" ";
                continue;
            }

            if (piece > 0)
                wcout << pieces[piece] << L" ";
            else if (piece < 0)
                wcout << blackPieces[-piece] << L" ";
            else
                wcout << L". ";
        }
        wcout << L"| " << 8 - y << endl;
    }

    wcout << L"  +-----------------+" << endl;
    wcout << L"    A B C D E F G H" << endl;
}

bool ChessGame::isMoveValid(int piece, int startX, int startY, int endX, int endY) {
    if (startX < 0 || startX >= 8 || startY < 0 || startY >= 8 || endX < 0 || endX >= 8 || endY < 0 || endY >= 8) {
        cerr << "Index out of range!" << endl;
        return false;
    }

    if (board[startY][startX] == 0) return false;
    if (whiteTurn && piece < 0) return false;
    if (!whiteTurn && piece > 0) return false;

    return true;
}

void ChessGame::processMove(int startX, int startY, int endX, int endY) {
    board[endY][endX] = board[startY][startX];
    board[startY][startX] = 0;
}

运行结果:

A B C D E F G H
  +-----------------+
8 | ♛ ♞ ♝ ? ♚ ♝ ♞ ♛ | 8
7 | ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟ | 7
6 | . . . . . . . . | 6
5 | . . . . . . . . | 5
4 | . . . . . . . . | 4
3 | . . . . . . . . | 3
2 | ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ | 2
1 | ♕ ♘ ♗ ? ♔ ♗ ♘ ♕ | 1
  +-----------------+
    A B C D E F G H

尽管已通过SetConsoleOutputCP(CP_UTF8)设置控制台输出为UTF-8,并为wcout注入locale("en_US.UTF-8"),且使用的终端(如Windows Terminal或Visual Studio输出控制台)支持UTF-8,但棋盘仍显示问号而非正确的Unicode棋子符号。其他文本显示正常,仅Unicode棋子符号存在问题。

请问遗漏了什么?如何确保控制台正确渲染Unicode字符?该如何解决此问题使棋子符号正常显示?

解决方案

1. 修复数组索引越界问题

你的核心问题是棋子编号与数组索引不匹配导致越界访问:

  • 棋盘初始化中,白方国王编号是7,黑方国王编号是-7,但你的pieces和blackPieces数组长度仅为7(索引0-6),访问pieces[7]会触发越界,直接输出问号。
  • 同时数组索引对应逻辑混乱:比如pieces[0]被赋值为白后,但代码中棋子编号从1开始使用。

修正步骤:

  1. 调整棋子编号与数组索引的对应关系,扩展数组长度到8(索引0留空,匹配1-7的棋子编号):
// 索引0留空,1=兵,3=车,4=马,5=象,6=后,7=王
const wchar_t* pieces[8] = { L"", L"♙", L"", L"♖", L"♘", L"♗", L"♕", L"♔" };
const wchar_t* blackPieces[8] = { L"", L"♟", L"", L"♜", L"♞", L"♝", L"♛", L"♚" };
  1. 修正棋盘初始化的编号顺序,确保国王(7/-7)、后(6/-6)的位置正确:
ChessGame::ChessGame() : whiteTurn(true) {
    board = { {
        {-5, -3, -4, -6, -7, -4, -3, -5}, // 黑方:象、车、马、后、王、马、车、象
        {-1, -1, -1, -1, -1, -1, -1, -1},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 0,  0,  0,  0,  0,  0,  0,  0},
        { 1,  1,  1,  1,  1,  1,  1,  1},
        { 5,  3,  4,  6,  7,  4,  3,  5} // 白方:象、车、马、后、王、马、车、象
    } };
}

2. 完善控制台Unicode输出配置

在Windows平台,仅设置代码页不够,需要额外配置终端模式:

void ChessGame::run() {
    // 同时设置输入、输出代码页为UTF-8
    SetConsoleOutputCP(CP_UTF8);
    SetConsoleCP(CP_UTF8);
    
    // 启用虚拟终端处理,提升Unicode渲染兼容性
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode = 0;
    GetConsoleMode(hOut, &mode);
    SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
    
    wcout.imbue(locale("en_US.UTF-8"));

    // ... 原有代码
}

另外,统一使用宽字符输出,把cerr改为wcerr避免编码混合:

wcerr << L"Index out of range!" << endl;

3. 确保源码与编译环境编码一致

  • 将源码文件保存为不带BOM的UTF-8编码;
  • 在Visual Studio中,项目属性 -> 常规 -> 字符集选择使用多字节字符集,或添加编译选项/utf-8强制使用UTF-8编译。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:15:54