Reversi Game –Move Legality Checking in C programming

10k Views Asked by At

The program should ask for user configuration once it initializes the board and then it prints the board using the user configuration. Then it prints the available moves for 'W' & 'B' accordingly. The last step is to ask for a move from the used and if it matches with the available moves printed before then it prints a message of the move is valid, then it prints the board for the last time using the valid move. My code works fine till it prints the configured board, but after then I am getting some weird output here. please help here, thank you. In the following program input should be of the form: U- unoccupied,B- occupied by black,W-occupied by white. here is an example input and expected output: Example

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void boardInitialize(char board[26][26], int n);
void printBoard(char board[26][26], int n);
void checkLegalMovesAvailable(char board[26][26], int N, char colour);
bool positionInBounds(int N, char row, char col);
void printMove(char board[26][26], int n);
void checkLegalInDirection(char board[26][26],int N,char row,char col,char colour,int deltaRow,int deltaCol);
bool checkLegalInMove(char board[26][26], int N, char row, char col, char colour);

int main(void){
    int n;
    char board[26][26];
    printf("Enter the board dimension: ");
    scanf("%d",&n);
    boardInitialize(board,n);
    printBoard(board,n);
    checkLegalMovesAvailable(board,n,'W');
    checkLegalMovesAvailable(board,n,'B');
    printMove(board,n);

    return (EXIT_SUCCESS);
}

//Function to initialize board
void boardInitialize(char board[26][26], int n){
    printf("  ");
    for(int i=0;i<n;i++){
        printf("%c",97+i);
    }
    printf("\n");
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            board[i][j]='U';
        }
    }
    board[(n/2)-1][(n/2)-1]='W';
    board[n/2][n/2]='W';
    board[(n/2)-1][n/2]='B';
    board[n/2][(n/2)-1]='B';
    for(int i=0;i<n;i++){
        printf("%c ",97+i);
        for(int j=0;j<n;j++){
            printf("%c",board[i][j]);
        }
        printf("\n");
    }
}

//Function to print board after configuration
void printBoard(char board[26][26], int n){
    printf("Enter board configuration:");
    printf("\n");
    char color,row,col;
    for(int i=0;(color!='!' && row!='!' && col!='!');i++){
        scanf(" %c%c%c",&color,&row,&col);
            board[row-'a'][col-'a']=color;
    }
    printf("  ");
    for(int i=0;i<n;i++){
        printf("%c",97+i);
    }
    printf("\n");
    for(int i=0;i<n;i++){
        printf("%c ",97+i);
        for(int j=0;j<n;j++){
            printf("%c",board[i][j]);
        }
        printf("\n");
    }   
}

//function to print available moves after configuration
void checkLegalMovesAvailable(char board[26][26], int N, char colour){
    printf("Available moves for %c:\n",colour);
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(board[i][j]==colour){
                for(int deltaRow=-1;deltaRow<=1;deltaRow++){
                    for(int deltaCol=-1;deltaCol<=1;deltaCol++){
                        if(deltaRow==0 && deltaCol==0)
                            ;
                        else
                            if(positionInBounds(N,('a'+i+deltaRow), ('a'+j+deltaCol)))
                                checkLegalInDirection(board,N,('a'+i+deltaRow),('a'+j+deltaCol),colour,deltaRow,deltaCol);
                        }
                    }
                }   
            }
        }
    }

//function to check if any move is legal in a specific direction
void checkLegalInDirection(char board[26][26],int N,char row,char col,char colour,int deltaRow,int deltaCol){
    int r=row-'a', c=col-'a',count=0;
    while((positionInBounds(N,'a'+r+(count*deltaRow),'a'+c+(count*deltaCol))) && (board[r+(count*deltaRow)][c+(count*deltaCol)]!=colour) && (board[r+(count*deltaRow)][c+(count*deltaCol)]!='U')){
        count++;
        if((positionInBounds(N,'a'+r+(count*deltaRow),'a'+c+(count*deltaCol))) && (board[r+(count*deltaRow)][c+(count*deltaCol)]=='U')){
        printf("%c%c\n",(row+(count*deltaRow)),(col+(count*deltaCol)));
        break;
        }
    }
}

//function to check if the specified row,col lies within the board dimensions
bool positionInBounds(int N, char row, char col){
    int p=row-'a',q=col-'a';
    if(p>=0 && q>=0 && p<N && q<N)
        return true;
    else
        return false;
}

//function to print board after a legal move 
void printMove(char board[26][26], int n){
    char color,row,col,temp;
    printf("Enter a move:\n");
    scanf(" %c%c%c",&color,&row,&col);
    temp=board[row-'a'][col-'a'];
    board[row-'a'][col-'a']=color;
    if(checkLegalInMove(board,n,row,col,color)){
        printf("  ");
        for(int i=0;i<n;i++){
            printf("%c",97+i);
        }
        printf("\n");
        for(int i=0;i<n;i++){
            printf("%c ",97+i);
            for(int j=0;j<n;j++){
                printf("%c",board[i][j]);
            }
            printf("\n");
        }
    }
    else{
        board[row-'a'][col-'a']=temp;
        printf("  ");
        for(int i=0;i<n;i++){
            printf("%c",97+i);
        }
        printf("\n");
        for(int i=0;i<n;i++){
            printf("%c ",97+i);
            for(int j=0;j<n;j++){
                printf("%c",board[i][j]);
            }
            printf("\n");
        }
    }
}

//function to check if any specific move is legal
bool checkLegalInMove(char board[26][26], int N, char row, char col, char colour){
    int r=row-'a',c=col-'a';
    for(int deltaRow=-1;deltaRow<=1;deltaRow++){
        for(int deltaCol=-1;deltaCol<=1;deltaCol++){
            if(positionInBounds(N,row,col)){
                checkLegalInDirection(board,N,('a'+r),('a'+c),colour,deltaRow,deltaCol);
                printf("Valid move.\n");
                return true;
            }
            else
                printf("Invalid move.\n");
            return false;
        }
    }
}
3

There are 3 best solutions below

3
Tom Karzes On

Ok, here's one simple observation for you. It looks like you changed checkLegalMovesAvailable so that it now always returns true, correct? So here's a question for you: Does that make sense? If so, then perhaps it shouldn't return anything at all, and its callers should always treat it as if it returned true. If not, then perhaps you should re-think your logic, and figure out under which circumstances it should return true vs. false. Does that make sense?

2
Tom Karzes On

Ok, here are a few more fixes for you:

(1) In positionInBounds, you're checking if p<=N and q<=N. I believe those checks should be p<N and q<N, right? So they're both in the range 0...(N-1).

(2) In checkLegalMovesAvailable, you should skip the call to checkLegalInDirection if both deltaRow and deltaCol are 0. Only 8 of the 9 combinations are valid.

(3) In checkLegalMovesAvailable you check to see if the first square in the desired direction is in bounds. But then in checkLegalInDirection, you keep looking further and further in that same direction without ever checking to see if you're still in bounds. I suspect that's causing some real problems that you've been seeing.

(4) In checkLegalInDirection, you keep looking in that direction as long as the square isn't empty or your color, i.e. as long as it's your opponent's color. That's fine, but at the end, you need to check that the final square is empty, as opposed to your own color. That check is missing.

See if you can make some progress on these fixes. That should keep you busy for a bit. If you're still having problems after that, I might be able to look at it again.

0
Tom Karzes On

Ok, here's another change for you which should solve several problems. When searching for available moves, you're checking the board for squares that already have a player's piece on them, then you're looking in all directions to see if there's a move in that direction. This is backwards from how one would normally do it, and it will also cause problems (duplicate moves).

For example, suppose you are looking for moves for player X, and the board looks like:

*OOOX
O
X

I've marked the interesting open postion with *. As you can see, that position is a double-move, since legal captures exist in two different directions from the same position.

Your current approach would list this move twice. It would find it first starting from one of the X positions, and then it would find it again when it encounters the second X position.

We can fix this bug, and solve your move-ordering problem, with a easy fix which might actually simplify your program.

Currently, you examine each square on the board to see if it's the player's color. If it is, then you look for adjacent runs of the opponent's color, terminated by an empty square, which is then recognized as a legal move.

Instead, you should reverse this: Examine each square on the board to see if it's empty. If it is, then look for adjacent runs of the opponent's color, terminated by a square of your color. If you find it, then the starting square (the empty one) becomes your move.

This change is actually very simple, and it solves two things: (1) You will no longer find duplicate moves (as in the example above), and (2) the moves will be printed in order.

Edit: I should add that, once you find a move and print it, you should immediately move to the next empty square. Otherwise, if you keep looking in other directions, you may find duplicates. A good way to do this is to break it into two functions. The first just iterates over all square (rows, columns), and calls the second to check if there's a legal move there. The second checks for a legal move. If it finds one, it immediately stops looking and returns.