kat
kat

Reputation: 23

Searching in a valid direction in 2D array

I'm looking to implement a board that looks something like this:

UUUU
UWBU
UBWU
UUUU

or 

UUBU
BWBU
WBWU
UUUU

Conditions for legal move:

edit updated code I've looked up some more resources and I've changed the logic of my code, however the configured board is now printing incorrectly and the function runs to print some moves, but not all, is something flawed in my logic?

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h> 

void initializeBoard(char board[][26], int n){
  int i, j;
  for (i=0; i<n; i++){
    for (j=0; j<n; j++){
      board[i][j] = 'U'; 
    }
  }
  board[(n/2)-1][(n/2)-1] = 'W';
  board[(n/2)-1][n/2] = 'B';
  board[n/2][n/2] = 'W';
  board[n/2][(n/2)-1] = 'B';
  // prints alphabet 
  char rowletter[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
  printf("  "); 
  int c; 
  for(c=0; c<n; c++){
    printf("%c", rowletter[c]);
  }
  printf("\n"); 
//prints board with alphabet
  int e=0; 
  int a, b;
  for (a=0; a<n; a++){
    printf("%c ", rowletter[e]);
    for (b=0; b<n; b++){
      printf("%c", board[a][b]); 
    }
    e++; 
    printf("\n"); 
  }
}

//prints board depending on what player inputs 
void configuredBoard(char playerBoard[][26], int n){
  char colour=0, row = 0, col = 0; 
  //player enters move for desired colour i.e Wba is white on row b column a 
  scanf("%c%c%c", &colour, &row, &col); 

  int i, j;
  for (i=0; i<n; i++){
    for (j=0; j<n; j++){
      playerBoard[i][j] = 'U'; 
    }
  }
  playerBoard[(n/2)-1][(n/2)-1] = 'W';
  playerBoard[(n/2)-1][n/2] = 'B';
  playerBoard[n/2][n/2] = 'W';
  playerBoard[n/2][(n/2)-1] = 'B';

  while(colour != '!'){
    row = (int)row-97;
    col = (int)col-97;
    playerBoard[row][col] = colour; 
    scanf(" %c%c%c", &colour, &row, &col);
  }

  // prints alphabet 
  char rowletter[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
  printf("  "); 
  int c; 
  for(c=0; c<n; c++){
    printf("%c", rowletter[c]);
  }
  printf("\n"); 
//prints board with alphabet
  int e=0; 
  int a, b;
  for (a=0; a<n; a++){
    printf("%c ", rowletter[e]);
    for (b=0; b<n; b++){
      printf("%c", playerBoard[a][b]); 
    }
    e++; 
    printf("\n"); 
  }
}


bool checkLineMatch(char colour, int dr, int dc, int r, int c, char playerBoard[][26], int n){
  if(playerBoard[r][c] == colour){
    return true; 
  }
  if((r+dr < 0) || (r+dr > n)){
    return false;
  }
  if((c+dc <0 ) || (c+dc >n)){
    return false;
  }
  if (playerBoard[r][c] == 'U'){
    return false; 
  }
  checkLineMatch(colour, dr, dc, r+dr, c+dc, playerBoard, n); 
}

bool validMove(char colour, int dr, int dc, int r, int c, char playerBoard[][26], int n){
char oppositeColour;
  if(colour == 'B'){
    oppositeColour = 'W';
  }
  else if(colour == 'W'){
    oppositeColour = 'B'; 
  }

  if((r+dr < 0) || (r+dr > n)){
    return false;
  }
  if((c+dc <0 ) || (c+dc >n)){
    return false;
  }
  if(playerBoard[r+dr][c+dc] != oppositeColour){
    return false; 
  }
  if((r+dr+dr < 0) || (r+dr+dr > n)){
    return false;
  }
  if((c+dc+dc <0 ) || (c+dc+dc >n)){
    return false;
  }

  return checkLineMatch(colour, dr, dc, r+dr+dr, r+dc+dc, playerBoard, n);

}

void findAvailableMoves(char colour, char playerBoard[][26], int n){
  printf("Available Moves for %c: \n", colour);
  int i, j; 
  for (int i=0; i<n; i++){
    for (int j=0; j<n; j++){
      if (playerBoard[i][j] == 'U'){
        //nw is northwest, etc. 
          bool nw = validMove(colour, -1, -1, i, j, playerBoard, n);
          bool nn = validMove(colour, -1, 0, i, j, playerBoard, n);
          bool ne = validMove(colour, -1, 1, i, j, playerBoard, n);

          bool ww = validMove(colour, 0, -1, i, j, playerBoard, n);
          bool ee = validMove(colour, 0, 1, i, j, playerBoard, n);

          bool sw = validMove(colour, 1, -1, i, j, playerBoard, n);
          bool ss = validMove(colour, 1, 0, i, j, playerBoard, n);
          bool se = validMove(colour, 1, 1, i, j, playerBoard, n);

        // if direction is valid, 
        if (nw || nn || ne || ww || ee || sw || ss ||se){
          //is valid move

          printf("%c%c\n", (char)i+97, (char)j+97); //typecast to ascii
        }
      }
    }
  }
}



int main(void){
  int n; 
  char board[26][26];
  printf("Enter the board dimension: ");
  scanf("%d", &n);
  initializeBoard(board, n); 

  char playerBoard[26][26];
  printf("Enter board configuration: \n");
  configuredBoard(playerBoard, n); 

  findAvailableMoves('W', playerBoard, n); 
  findAvailableMoves('B', playerBoard, n);

  printf("Enter a move: "); 



}

Here is expected output vs actual output:

Screen-Shot-2020-03-27-at-8-00-54-PM.png

Screen-Shot-2020-03-27-at-8-03-34-PM.png

Upvotes: 1

Views: 432

Answers (2)

Ardent Coder
Ardent Coder

Reputation: 3995

I've modified your code with explanation in the code comments.

Now it compiles and matches the expected output:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

/*
I have used this format of commenting
So that it does not conflict with your comments that are in // format
*/

/* Prefer 4 space indentation over 2 spaces, just a matter of taste */

/* It would have been better to have function prototypes to make the code more readable */

/* You are reusing this code many times, so I moved it to a function */
void displayBoard(char board[26][26], int n)
{
    /*
    // prints alphabet
    char rowletter[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    printf("  ");
    int c;
    for(c=0; c<n; c++){
        printf("%c", rowletter[c]);
    }
    printf("\n");
    A Better way:
    */
    char marker = 'a';
    printf("  ");
    for (int i = 0; i < n; ++i, ++marker)
        printf("%c", marker);
    printf("\n");

    /*
    //prints board with alphabet
    int e=0;
    int a, b;
    for (a=0; a<n; a++){
        printf("%c ", rowletter[e]);
        for (b=0; b<n; b++){
            printf("%c", board[a][b]);
        }
        e++;
        printf("\n");
    }
    A better way:
    */
    marker = 'a';
    for (int i = 0; i < n; ++i, ++marker)
    {
        printf("%c ", marker);
        for (int j = 0; j < n; ++j)
        {
            printf("%c", board[i][j]);
        }
        printf("\n");
    }
}

void initializeBoard(char board[][26], int n){
    int i, j;
    for (i=0; i<n; i++){
        for (j=0; j<n; j++){
            board[i][j] = 'U';
        }
    }
    board[(n/2)-1][(n/2)-1] = 'W';
    board[(n/2)-1][n/2] = 'B';
    board[n/2][n/2] = 'W';
    board[n/2][(n/2)-1] = 'B';

    /* INITIALIZE != DISPLAY
    // prints alphabet
    char rowletter[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    printf("  ");
    int c;
    for(c=0; c<n; c++){
        printf("%c", rowletter[c]);
    }
    printf("\n");
    //prints board with alphabet
    int e=0;
    int a, b;
    for (a=0; a<n; a++){
        printf("%c ", rowletter[e]);
        for (b=0; b<n; b++){
            printf("%c", board[a][b]);
        }
        e++;
        printf("\n");
    }
    */
}

/*
//prints board depending on what player inputs
NO, CONFIGURING != PRINTING
Each function should serve a specific purpose, not multiple purposes
You are violating the modular design and making your code less maintainable
*/
/*
// void configuredBoard(char playerBoard[][26], int n){
configured?
*/
void configureBoard(char playerBoard[][26], int n){
    char colour=0, row = 0, col = 0;

    /* Also have two ints for storing the coordinates of char input */
    int x, y;

    /*
    You are doing this inside the while loop
    //player enters move for desired colour i.e Wba is white on row b column a
    scanf("%c%c%c", &colour, &row, &col);
    */

    /*
    You have already done this in initializeBoard()
    int i, j;
    for (i=0; i<n; i++){
        for (j=0; j<n; j++){
            playerBoard[i][j] = 'U';
        }
    }
    playerBoard[(n/2)-1][(n/2)-1] = 'W';
    playerBoard[(n/2)-1][n/2] = 'B';
    playerBoard[n/2][n/2] = 'W';
    playerBoard[n/2][(n/2)-1] = 'B';
    */

    /* Make this an infinite loop and break it when the user enters "!!!"
       Otherwise, playerBoard[!][!] = '!' will happen at the end of the loop
    while(colour != '!'){/
    */
    while (true) {
        scanf(" %c%c%c", &colour, &row, &col);

        /* Check for "!!!" */
        if (colour == '!' && row == '!' && col == '!')
            break;

        /*
        Array subscript has type 'char'
        row = (int)row-97;
        col = (int)col-97;
        playerBoard[row][col] = colour;
        */
        x = row - 97;
        y = col - 97;
        playerBoard[x][y] = colour;
        /* Problem with the order of execution
        playerBoard[x][y] = colour;
        scanf(" %c%c%c", &colour, &row, &col);
        */
    }

    /* I guess, I don't have to repeat it again
    // prints alphabet
    char rowletter[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    printf("  ");
    int c;
    for(c=0; c<n; c++){
        printf("%c", rowletter[c]);
    }
    printf("\n");
    //prints board with alphabet
    int e=0;
    int a, b;
    for (a=0; a<n; a++){
    printf("%c ", rowletter[e]);
    for (b=0; b<n; b++){
        printf("%c", playerBoard[a][b]);
    }
    e++;
    printf("\n");
    }
    */
}

/*
x and y would have been a better choice over r and c in this function
Just a matter of convention:
    r and c are more like constants
    x and y are more like arbitrary constants
    i and j are more like variables
Your r and c are actually the (x, y) coordinates of the board here
*/

/*
I'm finding it hard to correct the following three functions because
I'm unable to understand the logic:
Unwanted recursion,
Control reaches the end of non-void function,
Ambiguous comparisons,
...
Though you tried to implement Alin's approach,
I'll make it clear
*/

/*
bool checkLineMatch(char colour, int dr, int dc, int r, int c, char playerBoard[][26], int n){
    if(playerBoard[r][c] == colour){
        return true;
    }
    if((r+dr < 0) || (r+dr > n)){
        return false;
    }
    if((c+dc <0 ) || (c+dc >n)){
        return false;
    }
    if (playerBoard[r][c] == 'U'){
        return false;
    }
    checkLineMatch(colour, dr, dc, r+dr, c+dc, playerBoard, n);
}

bool validMove(char colour, int dr, int dc, int r, int c, char playerBoard[][26], int n){
    char oppositeColour;
    if(colour == 'B'){
        oppositeColour = 'W';
    }
    else if(colour == 'W'){
        oppositeColour = 'B';
    }

    if((r+dr < 0) || (r+dr > n)){
        return false;
    }
    if((c+dc <0 ) || (c+dc >n)){
        return false;
    }
    if(playerBoard[r+dr][c+dc] != oppositeColour){
        return false;
    }
    if((r+dr+dr < 0) || (r+dr+dr > n)){
        return false;
    }
    if((c+dc+dc <0 ) || (c+dc+dc >n)){
        return false;
    }

    return checkLineMatch(colour, dr, dc, r+dr+dr, r+dc+dc, playerBoard, n);
}

void findAvailableMoves(char colour, char playerBoard[][26], int n){
    printf("Available Moves for %c: \n", colour);
    int i, j;
    for (int i=0; i<n; i++){
        for (int j=0; j<n; j++){
            if (playerBoard[i][j] == 'U'){
                //nw is northwest, etc.
                bool nw = validMove(colour, -1, -1, i, j, playerBoard, n);
                bool nn = validMove(colour, -1, 0, i, j, playerBoard, n);
                bool ne = validMove(colour, -1, 1, i, j, playerBoard, n);

                bool ww = validMove(colour, 0, -1, i, j, playerBoard, n);
                bool ee = validMove(colour, 0, 1, i, j, playerBoard, n);

                bool sw = validMove(colour, 1, -1, i, j, playerBoard, n);
                bool ss = validMove(colour, 1, 0, i, j, playerBoard, n);
                bool se = validMove(colour, 1, 1, i, j, playerBoard, n);

                // if direction is valid,
                if (nw || nn || ne || ww || ee || sw || ss ||se){
                    //is valid move

                    printf("%c%c\n", (char)i+97, (char)j+97); //typecast to ascii
                }
            }
        }
    }
}
*/

/* Bring back your old function */
bool positionInBounds(int n, int x, int y)
{
    return (x >= 0 && x < n && y >= 0 && y < n);
}

/* I've rewritten this function */
void findAvailableMoves(const char colour, const char board[][26], const int n)
{
    int x, y;
    const int dx[8] = {1, 1, 0, -1, -1, -1, 0, 1};
    const int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};

    const char oppositeColour = colour == 'W' ? 'B' : 'W';

    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] == 'U')
            {
                for (int k = 0; k < 8; k++)
                {
                    x = i + dx[k];
                    y = j + dy[k];
                    while (positionInBounds(n, x, y) && board[x][y] == oppositeColour)
                    {
                        x += dx[k];
                        y += dy[k];
                        if (positionInBounds(n, x, y) && board[x][y] == colour)
                        {
                            printf("%c%c\n", (char)i + 97, (char)j + 97);
                            break;
                        }
                    }
                }
            }
        }
    }
}

int main(void){
    int n;
    char board[26][26];

    printf("Enter the board dimension: ");
    scanf("%d", &n);
    initializeBoard(board, n);

    /* Make a separate call to displayBoard instead of putting it inside initializeBoard */
    displayBoard(board, n);

    /* THIS TOOK A LOT OF TIME TO FIGURE OUT!
       Why are you having a different board here!?
    char playerBoard[26][26];
    */
    printf("Enter board configuration: \n");
    // configuredBoard(playerBoard, n);
    configureBoard(board, n);

    /* Make a separate call to displayBoard instead of putting it inside configureBoard */
    displayBoard(board, n);

    /* This would have been much cleaner if OOP was available */
    // findAvailableMoves('W', playerBoard, n);
    // findAvailableMoves('B', playerBoard, n);
    findAvailableMoves('W', board, n);
    findAvailableMoves('B', board, n);

    printf("Enter a move: ");
    /*
    There are still many issues regarding
    Formatting
    Algorithm efficiency
    Invalid input handling
    and much more...
        But, I hope that I've removed the 'errors'
    */
}

Upvotes: 1

Alin Lupu
Alin Lupu

Reputation: 51

I'm stuck on how to stay within the bounds of the outer ring, i.e only checking 3 directions for corner pieces

Based on this objective, of checking the neighbors, if they exist, this function should help:

bool checkNeighbours( int n, int row, int col ) {
    // set up directions for all the neighbor cells
    int dx[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
    int dy[8] = { 0, 1, 1, 1, 0, -1, -1, -1 }; 

    int x, y;
    for( int i=0; i<8; i++ ) {
        x = row + dx[i];
        y = col + dy[i];
        if( positionInBounds( n, x, y ) ) { // check if out of bounds
            if( playerBoard[x][y] == oppositeColor ) { // add legalibility condition
                return true;

                // I don't understand exactly what this legality means 
                // but here you can add up any logic you want
                // The idea is that here you can return either true or false based on your legality meaning
            }
        }
    }
}

Upvotes: 1

Related Questions