0

I'm a beginner in programming and I'm trying to create a chess game in C. I've made a start but I keep getting this problem where a piece in the top left corner of the board (the first element of the array) gets turned into '-' after every turn.

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

enum Type {
    NONE = 0,
    PAWN,
    ROOK,
    BISHOP,
    KNIGHT,
    QUEEN,
    KING,
};

enum Color {
    BLACK,
    WHITE,
};

struct Piece {
    enum Type type;
    enum Color color;
};

char piece_to_char(struct Piece piece) {
    switch (piece.type) {
        case PAWN:
            return (piece.color == WHITE) ? 'P' : 'p';
        case ROOK:
            return (piece.color == WHITE) ? 'R' : 'r';
        case BISHOP:
            return (piece.color == WHITE) ? 'B' : 'b';
        case KNIGHT:
            return (piece.color == WHITE) ? 'N' : 'n';
        case QUEEN:
            return (piece.color == WHITE) ? 'Q' : 'q';
        case KING:
            return (piece.color == WHITE) ? 'K' : 'k';
        case NONE:
            return '-';
    }
}

int main() {
    struct Piece board[8][8] = {
        {{ROOK, BLACK}, {KNIGHT, BLACK}, {BISHOP, BLACK}, {QUEEN, BLACK}, {KING, BLACK}, {BISHOP, BLACK}, {KNIGHT, BLACK}, {ROOK, BLACK}},
        {{PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}, {PAWN, BLACK}},
        {{NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}},
        {{NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}},
        {{NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}},
        {{NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}, {NONE, BLACK}},
        {{PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}, {PAWN, WHITE}},
        {{ROOK, WHITE}, {KNIGHT, WHITE}, {BISHOP, WHITE}, {QUEEN, WHITE}, {KING, WHITE}, {BISHOP, WHITE}, {KNIGHT, WHITE}, {ROOK, WHITE}},
    };

    for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                printf("%c ", piece_to_char(board[i][j]));
            }
            printf("\n");
        }
        
    float moveNum = 0.5;
    while(1) {
        char move[4];
        printf("Move Number: %.f\n",ceil(moveNum));
        printf("Enter move: ");
        scanf("%s", move);

        int originalFile = move[0] - 'a';
        int originalRank = 8 - (move[1] - '0');
        int destFile = move[2] - 'a';
        int destRank = 8 - (move[3] - '0');

        struct Piece* originalPiece = &board[originalRank][originalFile];
        struct Piece* destPiece = &board[destRank][destFile];

        if (originalRank < 0 || originalRank > 7 || originalFile < 0 || originalFile > 7 || destRank < 0 || destRank > 7 || destFile < 0 || destFile > 7) {
            printf("Invalid move: outside board\n");
            return 1;
        }

        if (originalRank == destRank && originalFile == destFile) {
            printf("Invalid move: origin and destination are the same\n");
            return 1;
        }

        if (originalPiece->type == NONE) {
            printf("Invalid move: no piece at original position\n");
            return 1;
        }

        if (originalPiece->color == destPiece->color && destPiece->type != NONE) {
            printf("Invalid move: destination is occupied by friendly piece\n");
            return 1;
        }

        *destPiece = *originalPiece;
        *originalPiece = (struct Piece) { NONE, BLACK };

        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                printf("%c ", piece_to_char(board[i][j]));
            }
            printf("\n");
        }
        moveNum += 0.5;
    }
    return 0;
}

Here is the output after the first move is made

Move Number: 1
Enter move: e2e4
- n b q k b n r 
p p p p p p p p
- - - - - - - -
- - - - - - - -
- - - - P - - -
- - - - - - - -
P P P P - P P P
R N B Q K B N R

The first element changes to '-' if you move another piece there as well.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Have you tried running your code line-by-line in a debugger while monitoring the control flow and the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Apr 29 '23 at 05:53
  • one issue, not all code paths in `piece_to_char` return a value – yano Apr 29 '23 at 05:55

1 Answers1

1

This:

char move[4];

Can only hold three letters plus the null terminating char for the associated scanf call:

scanf("%s", move);

But when you type e2e4, which is a string that consists of 4 chars + 1 null char, that's going to create some undefined behavior that might explain the bug you are seeing. It seems highly probably that when the null char gets written 1 past the last value index of move, that it smashes the stack and overwrites the first byte in board with a 0. It makes sense that move would be aligned in stack memory right next to board given the curly brace enclosure that it's declared in.

This is technically an implementation detail of the compiler - but it's consistent across most compilers - but this assumption could easily break in a retail build or with other compiler flags set, but I digress...

And 0 is also the value for you enum value, NONE, which maps to a - when you print the board.

Declare move an array of at least 5 chars

char move[5];

Preferably more:

char move[80];

That may not be your only bug.

selbie
  • 100,020
  • 15
  • 103
  • 173