Thread: checkers v2 finished

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    808

    checkers v2 finished

    i have finished version 2 of checkers i have made it a lot smaller (i think) and added some features to it like colouring the selected piece red. I think the function take piece is a cop-out but i cant think of another way that i can make work without wiered behavour that defies logic.

    GitHub - cooper1200/checkers-v2

    any feedback appreciated
    coop

  2. #2
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Have you considered using a graph for your board instead of an array?

    Think of a linked list, but instead of next/previous you have 4 pointers; something like NorthWest/NorthEast/SouthWest/SouthEast - Any edge is a NULL, and you can have other members of the square struct such as current contents (use an enum for black, white, or empty), last x amount of move's contents, a member for calculating next moves...

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I would have done this from the start as a thinking aid, but generally I like to introduce abstractions, e.g.,
    Code:
    typedef struct
    {
        char label[MESSAGE];
    } Square;
    
    typedef struct
    {
        Square squares[COL_MAX + 1][ROW_MAX + 1];
    } Board;
    This would mean that when you think of a board, you think of it as a 2D array of squares, then when you think of a square, it is clear that the square is denoted by a string label. It does mean that your implementation might be a little more verbose than it currently is though, but in the long run it may be more maintainable.

    I wonder if you actually need the label to be a string: from what I see, the labels are basically strings of length 1, so perhaps they could just be chars.

    I would suggest writing initialize_game like this:
    Code:
    enum player initalize_game(char board[][ROW_MAX +1][MESSAGE])
    {
        enum player current_player = PLAYER_WHITE;
    
        int x_coordinate, y_coordinate;
    
        for (y_coordinate = ROW_MIN; y_coordinate < 3; y_coordinate++)
        {
            for (x_coordinate = COLUMN_MIN; x_coordinate <= COLUMN_MAX; x_coordinate++)
            {
                update_board_array(board, WHITE_PIECE, x_coordinate, y_coordinate);
            }
        }
    
        for (y_coordinate = 3; y_coordinate < 5; y_coordinate++)
        {
            for (x_coordinate = COLUMN_MIN; x_coordinate <= COLUMN_MAX; x_coordinate++)
            {
                update_board_array(board, EMPTY_SQUARE, x_coordinate, y_coordinate);
            }
        }
    
        for (y_coordinate = 5; y_coordinate <= ROW_MAX; y_coordinate++)
        {
            for (x_coordinate = COLUMN_MIN; x_coordinate <= COLUMN_MAX; x_coordinate++)
            {
                update_board_array(board, BLACK_PIECE, x_coordinate, y_coordinate);
            }
        }
    
        return current_player;
    }
    Instead of int, I used enum player as the return type because you conveniently declared the enum, so you might as well use it. Notice that I turned the current_player parameter into a local variable: you're always setting it to PLAYER_WHITE, so it is useless as a paramter. Then, I wrote three loops instead of one, and got rid of the piece_colour array as you can use the string constants directly (which is good because it avoids repeated copying).

    I suggest that you keep your use of the conditional operator to a minimum. Notice that one restriction of the conditional operator is that the second and third operands must have the same, or compatible, types. Consequently, it is usually used when you want to make use of its result, i.e., to conditionally select one of two possible results. So, you might see it frequently used when you want to conditionally assign to a variable, or in other similiar contexts like say in a printf call to conditionally choose a value to print. If you aren't using the result of the conditional operator, I suggest thinking twice. If the operands are verbose, you should also avoid the conditional operator, e.g. in this double whammy:
    Code:
                        current_player ? printf(" %d *********   %s   *********   %s   *********   %s   *********   %s   *\n",y_coordinate,
                                         temp_array[7-1][7-y_coordinate], temp_array[7-3][7-y_coordinate],
                                         temp_array[7-5][7-y_coordinate], temp_array[7-7][7-y_coordinate]) :
                                 printf(" %d *********   %s   *********   %s   *********   %s   *********   %s   *\n",y_coordinate,
    board[1][y_coordinate], board[3][y_coordinate], board[5][y_coordinate], board[7][y_coordinate]);
    which would have been much more readable if it were:
    Code:
                        if (current_player)
                        {
                            printf(" %d *********   %s   *********   %s   *********   %s   *********   %s   *\n",
                                y_coordinate,
                                temp_array[7-1][7-y_coordinate], temp_array[7-3][7-y_coordinate],
                                temp_array[7-5][7-y_coordinate], temp_array[7-7][7-y_coordinate]);
                        }
                        else
                        {
                            printf(" %d *********   %s   *********   %s   *********   %s   *********   %s   *\n",
                                y_coordinate,
                                board[1][y_coordinate], board[3][y_coordinate],
                                board[5][y_coordinate], board[7][y_coordinate]);
                        }
    As I noted elsewhere, you really don't need to be so verbose:
    Code:
    return (strcmp(board[x_coordinate][y_coordinate], EMPTY_SQUARE) == 0) ? true : false;
    just write:
    Code:
    return strcmp(board[x_coordinate][y_coordinate], EMPTY_SQUARE) == 0;
    The result of the == operator is already a boolean value even though it is of type int, so you don't have to use the conditional operator to decide whether or not to return true or false. If you insist, then I insist that instead of this:
    Code:
    if (off_board(*p_x, *p_y) == false)
    you should write:
    Code:
    if ((off_board(*p_x, *p_y) == false) ? true : false)
    absurd, isn't it?

    Speaking of which, that should be:
    Code:
    if (!off_board(*p_x, *p_y))
    Also, don't do this:
    Code:
    scanf(" %1d", &*p_x);
    just write:
    Code:
    scanf(" %1d", p_x);
    but remember to check the return value of scanf.

    In calculate_move, this:
    Code:
    if (take_piece(board, is_king, piece_coordinate_x, piece_coordinate_y, move_coordinate_x, move_coordinate_y, current_player) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
    can be simplified to:
    Code:
    return take_piece(board, is_king, piece_coordinate_x, piece_coordinate_y, move_coordinate_x, move_coordinate_y, current_player);
    In take_piece, this:
    Code:
    if ((entered_x_coordinate - temp_x == 1 * multiplyer_x)  && (entered_y_coordinate - temp_y == 1 * multiplyer_y))
    {
        if (validate_piece(temp_board, piece_to_take, entered_x_coordinate, entered_y_coordinate))
        {
            if (off_board((temp_x + 2 * multiplyer_x), (temp_y + 2 * multiplyer_y)) == false)
            {
                if (valid_square(temp_board, temp_x + 2 * multiplyer_x, temp_y + 2 * multiplyer_y))
                {
                    strcpy(temp_board[temp_x + 1 * multiplyer_x][temp_y + 1 * multiplyer_y], TAKEN_PIECE);
                    temp_x += 2 * multiplyer_x;
                    temp_y += 2 * multiplyer_y;
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    else
    {
        break;
    }
    can be simplified to:
    Code:
    if ((entered_x_coordinate - temp_x == 1 * multiplyer_x) &&
        (entered_y_coordinate - temp_y == 1 * multiplyer_y) &&
        validate_piece(temp_board, piece_to_take, entered_x_coordinate, entered_y_coordinate) &&
        !off_board(temp_x + 2 * multiplyer_x, temp_y + 2 * multiplyer_y) &&
        valid_square(temp_board, temp_x + 2 * multiplyer_x, temp_y + 2 * multiplyer_y))
    {
        strcpy(temp_board[temp_x + 1 * multiplyer_x][temp_y + 1 * multiplyer_y], TAKEN_PIECE);
        temp_x += 2 * multiplyer_x;
        temp_y += 2 * multiplyer_y;
    }
    else
    {
        break;
    }
    Last edited by laserlight; 05-10-2019 at 05:54 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    Wow thank you for you for the time you have taken to respond. The reason message is an array is so i can include the escape codes for changing the colour of the piece on the screen, which i guess is a little childish and probably added dozens of lines of code. with the deceleration of the struct board are u declaring an array of the square struct? and would i address the inner member by strcpy(board.square[x][y].label, "hello there").

    writing an if clause like if (my_function == true) helps at time of debugging that i am expecting it to return false and remembering what i wanted the function to return when writing the function call. I guess this is a bad habit of mine as your way of using the not operator is just as clear in terms of is it going to return false or true to pass the test.

    what is clear from your comments is i need to really think about what each statement is doing your example of me using the ?: operator on a return statement is classic of what i mean. i didnt think about what strcmp was returning so used a conditional operator to determin weather it was true or false. BUT the logic of that use says that strcmp is returning true or false duh!!!
    many many thanks for your input
    coop

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Consider that you may be inclined to read off_board(*p_x, *p_y) == false as "if off_board returns false for the piece at those coordinates", upon which you still have to interpret the significance of that, whereas !off_board(*p_x, *p_y) lends itself to "if the piece at those coordinates is not off the board", i.e., if you have descriptive function names, especially those involving verbs, it can make your code more readable in this way.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    sorry meant to ask rather than having the nested if statements in take piece you would join them together using the && operator. would you do this after you were sure the function worked as you wanted or right from the start if so how would you debug it to find out which part was causing the entire clause to fail.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    First, test each function to be sure that they work (unit testing). Then test them together (integration testing). Use a debugger to help you figure out which one returned an unexpected value.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    i tried ti impliment declaring the player enum in initialize_game and altered the decelerations to suit but now when i run it throws an error saying current_player undeclared
    Code:
    int main()
    {
        char board[COLUMN_MAX + 1][ROW_MAX + 1][MESSAGE], code[ESCAPE_CODE], error_message[ERROR_MESSAGE];
        char *p_make_king;
        int x_coordinate_of_piece, y_coordinate_of_piece, x_coordinate_to_move_to, y_coordinate_to_move_to;
        int number_of_white_pieces_left, number_of_black_pieces_left;
        bool is_king = false;
    
        current_player = initalize_game(board);
        clear_screen();
        draw_board(board, current_player);
        //move_test(board);
        //current_player = PLAYER_WHITE;
        for(;;)
    coop

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That's right. Look in the main function: where did you declare current_player?

    Don't say you declared it in initialize_game: yes, you did, but that's a local variable.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. checkers game finally finished
    By cooper1200 in forum C Programming
    Replies: 18
    Last Post: 05-03-2019, 04:46 PM
  2. checkers!!
    By salmanriaz in forum Game Programming
    Replies: 0
    Last Post: 04-20-2009, 11:02 AM
  3. C++ Checkers Game
    By SnS CEO in forum C++ Programming
    Replies: 9
    Last Post: 09-07-2005, 01:21 AM
  4. Help with Checkers
    By Luke2525 in forum C++ Programming
    Replies: 1
    Last Post: 05-20-2002, 05:46 PM
  5. Checkers/Tic-Tac-Toe
    By Dummies102 in forum C++ Programming
    Replies: 3
    Last Post: 04-12-2002, 05:07 PM

Tags for this Thread