在Windows CMD中打印出Chess Unicode字符

时间:2015-01-25 07:22:14

标签: c++ windows unicode cmd

我为我的任务建立了一个简单的国际象棋程序。我在我的Linux机器里试过它,它运行得很好。我也在我的Windows机器中尝试过它。我在Windows机器上遇到的问题是Unicode字符没有像Linux那样正确显示。这是我的代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>

#ifdef _WIN32
#include <windows.h>
#endif

using namespace std;

/*
 player 1 = 0 (black)
 player 2 = 1 (white)
*/
char unicodePieces[2][6][4] = 
{
    { "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" },
    { "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F" }
};

typedef struct pieceinfo
{
    // coordinate x & y on graph
    int x, y;

    // 1 = alive, 0 = dead
    int status;

    // belong to which player number (0 or 1)
    int belong;

    // location at unicodePieces
    // also represent which piece this struct is
    int pos;

} PieceInfo;

typedef struct chessplayer
{
    PieceInfo king, queen, rooks[2], knights[2], bishops[2];

    // pawns start from left to right from 1 until 8
    PieceInfo pawns[8];

} ChessPlayer;

// functions definition
void init_chess(ChessPlayer *, unsigned char, int, int);
PieceInfo *get_player_at_coordinate(ChessPlayer *, int, int);
int check_dest_can_move(ChessPlayer *, int, int, int, int);
int if_move_have_barrier(ChessPlayer *, int, int, int, int, double *, int, int);
void display_board(ChessPlayer *);
int check_if_king_has_dead(ChessPlayer *);

int main()
{   
    /*
        0 - player 1
        1 - player 2
    */
    ChessPlayer player[2];

    init_chess(&player[0], 0, 1, 2);
    init_chess(&player[1], 1, 8, 7);

    int src_x, src_y, dest_x, dest_y, turn = 0, get_winner;
    PieceInfo *get, *get_temp;

    while(1)
    {

#ifdef _WIN32
        system("cls");

        // make cmd to support unicode characters
        SetConsoleOutputCP(1251); 
#else
        system("clear");
#endif

        // get 1 space
        cout << endl;

        // display the board below here
        display_board(player);

        if((get_winner = check_if_king_has_dead(player)) != -2)
        {
            cout << endl << "Player " << unicodePieces[get_winner - 1][player[get_winner - 1].pawns[0].pos] << " [" << get_winner << "] win!" << endl << endl;
            break;
        }

        cout << endl << "Player " << unicodePieces[turn][player[turn].pawns[0].pos] << " 's  turn..\n";

        while(1)
        {
            cout << "Please enter source coordinate of your piece : ";
            scanf("%d %d", &src_x, &src_y);

            get = get_player_at_coordinate(player, src_x, src_y);

            if(src_x > 8 || src_y > 8 || get == NULL)
            {
                cout << endl << "Error! Invalid source coordinate [" << src_x << "] [" << src_y << "]" << endl << endl;
                continue;
            }
            else if(get->belong != turn)
            {
                cout << endl << "Sorry! That piece isn't belong to you!" << endl <<endl;
                continue;
            }

            break;
        }

        cout << "You have selected -> " << unicodePieces[get->belong][get->pos] << "  at [" << get->x << "] [" << get->y << "] \n";

        while(1)
        {
            cout << "Please enter destination coordinate : ";
            scanf("%d %d", &dest_x, &dest_y);

            if(dest_x > 8 || dest_y > 8)
            {
                cout << endl << "Error! Invalid destination coordinate [" << dest_x << "] [" << dest_y << "]" << endl << endl;
                continue;
            }

            // check for common errors made by player
            if(!check_dest_can_move(player, src_x, src_y, dest_x, dest_y)) continue;

            break;
        }

        if((get_temp = get_player_at_coordinate(player, dest_x, dest_y)) != NULL) get_temp->status = 0;

        get->x = dest_x, get->y = dest_y;

        // xor variable turn with 1 to switch between first & second player
        turn ^= 1;
    }
}

void init_chess(ChessPlayer *chess_struct, unsigned char player_num, int first, int second)
{
    chess_struct->king = { .x = 5, .y = first, .status = 1, .belong = player_num, .pos = 0};
    chess_struct->queen = { .x = 4, .y = first, .status = 1, .belong = player_num, .pos = 1};
    chess_struct->bishops[0] = { .x = 3, .y = first, .status = 1, .belong = player_num, .pos = 3};
    chess_struct->bishops[1] = { .x = 6, .y = first, .status = 1, .belong = player_num, .pos = 3};
    chess_struct->knights[0] = { .x = 2, .y = first, .status = 1, .belong = player_num, .pos = 4};
    chess_struct->knights[1] = { .x = 7, .y = first, .status = 1, .belong = player_num, .pos = 4};
    chess_struct->rooks[0] = { .x = 1, .y = first, .status = 1, .belong = player_num, .pos = 2};
    chess_struct->rooks[1] = { .x = 8, .y = first, .status = 1, .belong = player_num, .pos = 2};

    for(int i = 0; i < 8; i++)
        chess_struct->pawns[i] = { .x = i+1, .y = second, .status = 1, .belong = player_num, .pos = 5 };
}

//
// get pointer to PieceInfo struct
// else return NULL if not exist
//
// this function is involving pointer, so ignore this if you can't understand
//
PieceInfo *get_player_at_coordinate(ChessPlayer *player, int x, int y)
{
    for(int i = 0; i < 2; i++)
    {
        for(int z = 0, each_chessplayer = sizeof(ChessPlayer) / sizeof(PieceInfo); z < each_chessplayer; z++)
        {
            PieceInfo *each_piece = (PieceInfo *)((char *)(player + i) + (z * sizeof(PieceInfo)));

            if(each_piece->x == x && each_piece->y == y && each_piece->status == 1)
                return each_piece;
        }
    }

    return NULL;
}

int check_if_king_has_dead(ChessPlayer *player)
{
    for(int i = 0; i < 2; i++)
    {
        for(int z = 0, each_chessplayer = sizeof(ChessPlayer) / sizeof(PieceInfo); z < each_chessplayer; z++)
        {
            PieceInfo *each_piece = (PieceInfo *)((char *)(player + i) + (z * sizeof(PieceInfo)));

            if(each_piece->pos == 0 && each_piece->status == 0)
                return each_piece->belong;
        }
    }

    return -2;
}

int check_dest_can_move(ChessPlayer *player, int src_x, int src_y, int dest_x, int dest_y)
{
    PieceInfo *get, *get_temp;

    get = get_player_at_coordinate(player, src_x, src_y);
    get_temp = get_player_at_coordinate(player, dest_x, dest_y);

    char replace_error[] = "Error! You can't place step into your own piece!";

    if(get_temp != NULL && get_temp->belong == get->belong)
    {
        cout << endl << replace_error << endl << endl;
        return 0;
    }
    else if(get->pos == 0) //king
    {
        // king can't move more than 1 step
        if(abs(src_y - dest_y) > 1 || abs(src_x - dest_x) > 1)
        {
            cout << endl << "Error! King can only move 1 step!" << endl << endl;
            return 0;
        }
    }
    else if(get->pos == 1) // queen
    {
        double gradients[3] = { -1, 1, 0};

        int check = if_move_have_barrier(player, src_x, src_y, dest_x, dest_y, gradients, 3, 1);

        if(check != 1)
            return 0;
    }
    else if(get->pos == 2) // bishop
    {
        double gradients[1] = {0};

        int check = if_move_have_barrier(player, src_x, src_y, dest_x, dest_y, gradients, 1, 1);

        if(check != 1)
            return 0;
    }
    else if(get->pos == 3) // rooks
    {
        double gradients[2] = {-1, 1};

        int check = if_move_have_barrier(player, src_x, src_y, dest_x, dest_y, gradients, 2, 0);

        if(check != 1)
            return 0;
    }
    else if(get->pos == 4) // knight
    {
        // knight have 8 possible movements with L shape
        int move[8][2] =
        {
            {-2, 1}, {-1, 2}, {1, 2},
            {2, 1}, {2, -1}, {1, -2},
            {-1, -2}, {-2, -1}
        }, check = 0;

        for(int i = 0; i < 8 && !check; i++)
            if((src_x + move[i][0]) == dest_x && (src_y + move[i][1]) == dest_y)
                check++;

        if(!check)
        {
            cout << endl << "Error! Knight movement must equivalent to L shape movement!" << endl << endl;
            return 0;
        }
    }
    else // pawns
    {
        char movetwosteps[] = "Error! Pawn can only move 2 steps at the initial of the game!";
        char cantmovepawn[] = "Error! You can't move into that position!";

        // sure this is hard to get
        if((get->belong == 0 && src_y >= dest_y) ||
            (get->belong == 1 && src_y <= dest_y))

        {
            cout << endl << "Error! Pawn can only move forward!" << endl << endl;
            return 0;
        }

        // and this one too
        if((get->belong == 0 && (((src_x - 1) == dest_x && (src_y + 1) == dest_y) || ((src_x + 1) == dest_x && (src_y + 1) == dest_y))) ||
            (get->belong == 1 && (((src_x - 1) == dest_x && (src_y - 1) == dest_y) || ((src_x + 1) == dest_x && (src_y - 1) == dest_y))))
        {
            if(get_temp == NULL)
            {
                cout << endl << cantmovepawn << endl << endl;
                return 0;
            }
            else if(get->belong == get_temp->belong)
            {
                cout << endl << replace_error << endl << endl;
                return 0;
            }
        }

        //
        // abs = absolute value, because distant is always positive
        //
        if(abs(dest_y - src_y) == 2)
        {
            if((get->belong == 0 && src_y != 2) || (get->belong == 1 && src_y != 7))
            {
                cout << endl << movetwosteps << endl << endl;
                return 0;
            }
            else if(get->belong == 1 && src_y != 7)
            {
                cout << endl << movetwosteps << endl << endl;
                return 0;
            }
        }
        else if(abs(dest_y - src_y) > 1)
        {
            cout << endl << "Error! Pawn can only move 1 step!" << endl << endl;
            return 0;
        }
        else if(abs(dest_y - src_y) == 1 && src_x == dest_x && get_temp != NULL)
        {
            cout << endl << cantmovepawn << endl << endl;
            return 0;
        }

    }

    return 1;
}

/*
  return code value :-

   1 = no problem at all :)
  -3 = has problem(s)
*/
int if_move_have_barrier(ChessPlayer *player, int src_x, int src_y, int dest_x, int dest_y, double *gradients, int size_gradients, int check_x)
{

    char invalid_coordinate[] = "Error! Invalid destination coordinate! Please check again.";
    char barrier_error[] = "Error! Piece can't move because there's a barrier before destination.";

    // only 3 gradients, 1 is undefined (have to check manually)
    double m = 0, check = 0;
    PieceInfo *get;
    int test = 0;

    if(check_x && src_x == dest_x) // if same line at x, then +1 into check variable
    {
        check = 10.0, test++; // special gradient value
    }
    else if(src_x != dest_x)
        m = (dest_y - src_y)/(dest_x - src_x);

    for(int i = 0; i < size_gradients && !test; i++)
        if(m == gradients[i])
            check = gradients[i], test++;

    if(!test)
    {
        cout << endl << invalid_coordinate << endl << endl;
        return -3;
    }
    else if(check == 10.0 || check == -1.0 || check == 1.0 || check == 0.0) // if 4 graph gradients direction (10 is special value)
    {
        for(int i = 0; !(src_y == dest_y && src_x == dest_x); )
        {
            if(i++ && get_player_at_coordinate(player, src_x, src_y) != NULL)
            {
                cout << endl << barrier_error << endl << endl;
                return -3;
            }

            if(check) // if gradient is not zero (which is 1 ,-1 or 10)
            {
                if(dest_y > src_y)
                {
                    src_y++;

                    if(check == -1.0) src_x--;
                    else if(check == 1.0) src_x++;
                }
                else
                {
                    src_y--;

                    if(check == 1.0) src_x--;
                    else if(check == -1.0) src_x++;
                }
            }
            else
            {
                if(src_x < dest_x) src_x++;
                else src_x--; 
            }
        }
    }

    return 1;

}

//
// u can make ur own board if u want :)
//
void display_board(ChessPlayer *player)
{
    PieceInfo *get;

    char alphabet[] = "     1   2   3   4   5   6   7   8";
    char line[] = "   ---------------------------------";

    cout << alphabet << endl;
    cout << line << endl;

    for(int i = 1; i <= 8; i++) // y-axis
    {
        cout << " " << (9-i) << " |";

        for(int z = 1; z <= 8; z++) // x-axis
        {
            get = get_player_at_coordinate(player, z, 9 - i);

            if(get == NULL || !get->status)
                cout << "   |";
            else
                cout << " " << unicodePieces[get->belong][get->pos] << " |";
        }

        cout << " " << (9-i) << endl;
        cout << line << endl;
    }

    cout << alphabet << endl;
}

我还尝试使用SetConsoleOutputCP65001设置代码页,但Windows CMD仍未正确显示Unicode。

0 个答案:

没有答案