(P) Binairo

Goal: I will practice using vectors and Git. I will also learn to follow good programming style.

Instructions: Retrieve the code template: templates/04/binairo -> student/04/binairo.

If you do not have subdirectory 04, see the left menu in Plussa: Fetching new templates.

The code template provides you the main program module, almost completed, and a skeleton of the print method in class GameBoard. Your task is

  • to complete the missing points (TODO) in the main program module
  • to complete the missing point in the print method in class GameBoard (TODO)
  • to complete other parts of GameBoard class.

You can also replace the given code (or parts of it) with your own code. Anyway, the aim is to implement a working binairo game.

Important

Before starting to write code, read carefully the whole assignment. Note especially the points Implementing the program in parts (required commits), Special requirements, and Evaluation.

From the point Evaluation note especially that the program must first pass all automated test. Otherwise the work will not be evaluated by assistants, and no points will be given.

Note

This project can be done either in pairs or independently. If you do the project in pairs, choose ”Form a group” from the menu on the left to register your group. In addition, the submission box at the very end of the current page shows two choices: “Submit alone” / “Submit with…”. You should be careful when selecting the choice, because you cannot change it afterwards. Enter only the address of the Git repository owned by either of you (not both) in the submit box. The code files must contain (in comments) the personal data of both of you.

You can look for a group via Kooditorio’s Discord link (see Timetable & links).

Header comment and feedback language

The Evaluation point in this section requires a header comment in the code file. It means something like below:

/* Binairo
 *
 * Desc:
 *   This program implements a Binairo game with the gameboard of size 6 x 6.
 * Each square in the gameboard has zero, one, or empty. The aim is to add
 * zeros and ones in the empty squares by following the rules:
 * - each horizontal and vertical line can have at most three identical numbers
 * - each horizontal and vertical line can have at most two identical number
 *   sequentially.
 *   At first, the user is asked, if the gameboard will be filled with
 * randomly drawn characters, or with user-given 36 characters. In the first
 * option, a seed value for the random number generator will be asked next.
 * In the latter option, the user is asked to input 36 characters, the
 * validity of which is checked.
 *   On each round, the user is asked for the coordinates and the identity
 * of the character to be added, i.e. three characters. The player wins if
 * the gameboard has been filled following the rules above. The program does
 * not allow additions violating the above rules, but it is possible to end up
 * to a situation where no addition is possible any more.
 *   The program checks the user-given inputs. The character to be added must
 * be zero or one. The coordinates must be inside the gameboard, and the
 * square indicated by them must be empty.
 *
 * Program author ( Fill with your own info )
 * Name: Teemu Teekkari
 * Student number: 123456
 * UserID: teekkart ( Necessary due to gitlab folder naming. )
 * E-Mail: teemu.teekkari@tuni.fi
 *
 * Notes about the program and it's implementation (if any):
 *
 * */

Add above kind of comment at the very beginning of the file main.cpp. Also the code files must include your personal information, but the description part is not necessary to repeat in every file, it is enough to put it in the main program file.

You can write the above comment also in Finnish (see Finnish assignment), but write all comments in the same language. Remember to replace parts of the above text with your personal data.

If you are working in pairs, add personal data of both of you.

The template code has comments both in Finnish and English, you remove those not needed.

The feedback language will be chosen in the submission box (at the very end of this page). By default, the feedback language is Finnish, but you can change it, if you want to have the feedback, given by an assistant, in English. We will use the language you have given in the submission box of the final submission.

Game rules

The game has very simple rules, and they were explained in the header comment above and listed below. The aim is to achieve a game board that fulfills the following requirements:

  • each row and each column must contain an equal number of 0s and 1s
  • more than two of the same digits cannot be adjacent.

The original Binairo game has one more rule. Moreover, the original Binairo game accepts game grids of different sizes, but in the project we use the fixed size 6 x 6.

Binairo vs waterdrop game

The materials of this round include a description of waterdrop game that uses a vector, the elements of which are vectors. Further the elements of the inner vector are squares (Square objects). This project has a similar structure in a sense that also the gameboard of Binairo is a vector, the elements of which are vectors. However, the elements of the inner vector are values of enum type, so they are simpler than the squares in the waterdrop game, and thus, there is no need to describe them as a class.

In the waterdrop game, each square has a pointer to the game board, since each square must know its adjacent squares. In the project, this is not needed, nor pointers at all.

Initial filling of the gameboard

Your task is to implement a Binairo game that follows the rules described above. Let us first consider how to initially fill the gameboard.

The program starts by asking how to fill the game board:

Select start (R for random, I for input): x
Select start (R for random, I for input): yy
Select start (R for random, I for input): x y z
Select start (R for random, I for input): r
Enter a seed value: 2
Bad seed
Select start (R for random, I for input):

The question is repeated until the user gives either the string "R" or "I" (in upper or lower case letters).

Since the user selected a way, where the gameboard is filled with randomly drawn numbers, the program asks next a seed value for the random number generator. The program checks if the given seed value does not belong in bad ones, i.e. those (evidently) producing an unsolvable gameboard. Bad seed values in the interval [1..50] have been collected into the vector BAD_SEEDS in template code file gameboard.hh. Above you can see that for example 2 is bad. In the case of a bad seed value, the program prints the error message Bad seed. After that the user can select starting way again.

Instead 1 is not a bad seed value:

Select start (R for random, I for input): r
Enter seed value: 1
===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 | 0 1       1 |
| 2 | 0           |
| 3 |   0 0     0 |
| 4 |   0         |
| 5 |     0       |
| 6 |       0     |
===================
Enter two coordinates and a fill symbol, or q to quit:

(Seed value 1 ei non-bad, since in the initial situation the gameboard follows the game rules. However, also non-bad seed values can lead to unsolvable situations, but you need not care about this.)

After receiving a non-bad seed value, the program prints the gameboard filled with random numbers generated based on the seed value.

If the user had chosen a non-random way to fill the board, the program would have proceeded e.g. as follows:

Select start (R for random, I for input): i
Input: " 1     10 0   0   0   0          10 "
===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 |   1         |
| 2 |   1 0   0   |
| 3 |     0       |
| 4 | 0       0   |
| 5 |             |
| 6 |       1 0   |
===================
Enter two coordinates and a fill symbol, or q to quit:

Now characters given by the user are set on the gameboard line by line.

From the user given input it must be checked if it only contains zeros, ones, and empty spaces and if there is a correct amount of these characters. Moreover, the input starts and ends with an additional character (e.g. quote mark as above), since otherwise it would be hard to know where the actual input ends, if there are empty spaces at the end. Therefore the correct size of the input is 38 (6 * 6 + 2) characters, but the first and last ones are ignored, so they can be any characters. (Note especially that in template code function select_start, in its else branch after calling getline, the quote marks or such are still left.)

The input can be erroneous in two ways:

Select start (R for random, I for input): i
Input: "   0  1"
Wrong size of input
Select start (R for random, I for input): i
Input: " 1     10 0   0   0   0          12 "
Wrong character
Select start (R for random, I for input): r
Enter a seed value: 1
===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 | 0 1       1 |
| 2 | 0           |
| 3 |   0 0     0 |
| 4 |   0         |
| 5 |     0       |
| 6 |       0     |
===================
Enter two coordinates and a fill symbol, or q to quit:

As shown above, in erroneous input, the program prints either Wrong size of input or Wrong character. After an erroneous input, the user can select starting way again.

Adding characters on the gameboard

After initial filling of the gameboard, the user can give a character to be added with its coordinates. If one of the coordinates does not belong in the interval [1..6], the program prints:

Out of board

If given character to be added is something else than zero or one, the program prints:

Invalid input

If the user gives coordinates of a nonempty square, or if adding would violate the rules, the program prints:

Can't add

After each of the above error message, the program asks for inputs again.

These cases can be seen in the following execution:

===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 |   1         |
| 2 |   1 0   0   |
| 3 |     0       |
| 4 | 0       0   |
| 5 |             |
| 6 |       1 0   |
===================
Enter two coordinates and a fill symbol, or q to quit: 1 7 0
Out of board
Enter two coordinates and a fill symbol, or q to quit: xx yy 0
Out of board
Enter two coordinates and a fill symbol, or q to quit: 2 3 xx yy
Invalid input
Enter two coordinates and a fill symbol, or q to quit: 2 3 4
Invalid input
Enter two coordinates and a fill symbol, or q to quit: 2 3
Invalid input
Enter two coordinates and a fill symbol, or q to quit: 2 2 1
Can't add
Enter two coordinates and a fill symbol, or q to quit: 5 1 0
Can't add
Enter two coordinates and a fill symbol, or q to quit: 2 3 1
Can't add
Enter two coordinates and a fill symbol, or q to quit: 2 3 0
===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 |   1         |
| 2 |   1 0   0   |
| 3 |   0 0       |
| 4 | 0       0   |
| 5 |             |
| 6 |       1 0   |
===================
Enter two coordinates and a fill symbol, or q to quit:

Note that if the given coordinates are not numeric, the program also now prints Out of board. Here the given function stoi_with_check is useful: It returns zero, if the given parameter string is not numeric, and zero is outside of the game board.

Note also that the game board is printed at start and after that only when there are changes in it.

We can continue from the above situation and play the game successfully, for example, as follows:

===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 | 0 1 1 0 1 0 |
| 2 | 0 1 0 1 0 1 |
| 3 | 1 0 0 1 1 0 |
| 4 | 0 1 1 0 0 1 |
| 5 | 1 0 1 0 1 0 |
| 6 | 1 0 0 1 0   |
===================
Enter two coordinates and a fill symbol, or q to quit: 6 6 1
===================
|   | 1 2 3 4 5 6 |
-------------------
| 1 | 0 1 1 0 1 0 |
| 2 | 0 1 0 1 0 1 |
| 3 | 1 0 0 1 1 0 |
| 4 | 0 1 1 0 0 1 |
| 5 | 1 0 1 0 1 0 |
| 6 | 1 0 0 1 0 1 |
===================
You won!

In the latest situation, the requirements described earlier were fulfilled, which means that the player won, and the program printed You won!.

The player can quit the game:

Enter two coordinates and a fill symbol, or q to quit: q
Quitting ...

Now the program prints Quitting ... and terminates its execution.

Different ways to initially fill the board

As have been seen earlier, there are two ways to fill the game board. With randomly selected numbers, the game board can be filled easily, but there is the drawback that in this way, the game will almost never be solvable (not even with non-bad seed values), but it will lead to an impossible situation and and the game must be quitted.

If you want to test your game with solvable inputs (which is, of course, highly recommended), fill the game board non-randomly with some of the following inputs:

" 1     10 0   0   0   0          10 "
"      1   0   11  1      0 0    1  0"
"  0 0 1        1    11         0  0 "
"   1       0    0 0  00   1  1      "
"   11  00   00          1  0       1"
"  01     1 1      01    0  0    0   "
" 1   1 00  0      1     00  0     0 "
"1    0   1  0 0    1  1    11       "
"        1 11 0    1  0      101 0   "
" 1 1  1    1      1  11  1  11      "

Note that in the non-random fill, the numbers must be placed in the game board row-by-row. If you place them column-by-column, your program will not pass automated tests.

When you are reading a line with 36 (38) characters, you can again use the function getline and split the input string into separate numbers. Another choice is to use the operator >> 36 (38) times (e.g. in a for loop).

You can assume that in non-random fill, only solvable inputs have been used. Therefore you need not check if the given input string follows game rules.

Tip

Inputting such many numbers one at a time can be hard. An easier way is to copy a whole line consisting of 36 (38) characters and paste it at the point, where the program asks for input. If you have a roller for scrolling in the middle of your mouse, pressing the roller down acts as a paste command.

By looking the above solvable inputs, you can see that each line has more empty spaces than zeros and ones. This is situation is desirable also in random filling. Namely, if the gameboard was filled randomly such that each character would have the same probability, the gameboard would be too full. Most probably, there would be three sequential zeros or ones already at the beginning.

Therefore, the template code introcudes the constant DISTR_UPPER_BOUND:

// Constant for the upper bound of probability distribution.
// Zeros and ones have the same probability, say x, and the estimated
// probability of empties is 6x, whereupon their sum is 8x, and thus,
// the interval must have eigth points, as [0..7].
const int DISTR_UPPER_BOUND = 7;

So you can draw random numbers from the interval [0..7] or [0..DISTR_UPPER_BOUND] such that the random number 0 yields the character 0 on the gameboard, the random number 1 yields the character 1, and the random number [2..7] yield empty spaces. In this way, you can achieve probability described in the comment above.

Besides this, it can happen so that there are three adjacent zeros or ones on the gameboard already at the beginning. Now the game does not allow add any character, but you can restart the program and try another seed. (However, numbers from the interval [1..50] have been tested, and bad ones have been collected in vector BAD_SEEDS in the template code.)

Implementing the program in parts

Use version control in your project such that there can be found at least five commits as follows:

  • The program prints the gameboard.
  • The program checks that there are not too much equal numbers in horizontal or vertical lines.
  • The program checks that there are not too much equal numbers sequentially in horizontal or vertical lines.
  • In addition, you must have at least two more commits (before, between, or after the aforementioned ones).

You must also mention the steps described above clearly enough in the commit messages to enable course assistant to find them easily when evaluating your project. However, you can section above commits into several ones.

Tips for completing the assignment

  • As said earlier, the program must check if the user-given character can be added in the given position. Consider which way is easier: check first and then add, or add first and then check if everything is still fine. If needed (if everything is not fine), previously added character must be removed, of course. You need not care about efficiency.
  • It is enough to use vector container from STL, but also other containers from STL are allowed.
  • From the waterdrop game, you can learn how define a vector, the elements of which are vectors (square., line 12). Otherwise, the example is not so important.

Special requirements

You must use the enum type (Element_type in file gameboard.hh) given in the template code. If you do not use it (but use e.g. string instead), you will miss 10 points.

You must use the class given in the template code (GameBoard). Consider which code naturally belong to this class and which code belong to the main program module. Which attributes the class could have? And which methods?

Write methods concerning the gameboard in the aforementioned class, while code concerning user interface (e.g. reading input) suits in the main program module.

Evaluation

To end up to assistents’ evaluation, your work must first pass the automatic tests. Automatic tests do not accept a program producing warnings while compiling. If the automated tests give 0 points for your work, also your final points will be 0, and your work will not be evaluated by an assistant.

The assistant evaluates the latest Plussa submission that has passed the automated testing (= 1 p) before the deadline, according to the following criteria:

  • The overall principle of the solution: 0-20 points:
    • The learning goals of the exercise have been achieved.
    • The program code has been split into logical, suitably long segments using functions, classes, and/or methods.
    • If the program uses classes and objects, these have been implemented according to the basics of object-oriented programming (see previous material section: About programming style, especially at Object-oriented programming).
    • The data structure does not include repetitive data nor unnecessary parts. The chosen data structures have been used in a reasonable way.
    • The program code does not include unnecessary repetitions nor other unnecessary parts.
    • The program code does not include unnecessary limitations or assumptions or other forced solutions.
    • The implementations of the program structures are easy to understand.
    • Global variables have not been used in the program code (global constants are OK).
    • The program does not terminate with the exit function.
  • Programming style: 0-20 points:
    • Variables and functions are named clearly and appropriately. These items have named by using only one language, not e.g. Finnish and English mixed.
    • Named constants have been used instead of magic numbers.
    • The program code is neatly formatted.
    • The length of program code lines do not exceed 80 characters.
    • At the beginning of each file, there is a comment explaining the purpose of the file, the creator(s) of the project and other necessary information (see the point Header comment).
    • At the beginning of each function/method there is a comment describing its working, return value and parameters. This comment is placed in the header file if such exists.
    • There are comments in the code where necessary.
    • Comments are related to the current version of the program, not to an older one.
    • All comments have written in the same language (fi/en), but comments can be written in a language different from that used in naming variables and such.
    • All the variables have been initialized.
    • The compiler does not give warnings while compiling.
  • Using the version control: 0-10 points:
    • There are enough commits.
    • The content of commit messages is clear and relevant.

Note about evaluation

Automated tests check if your program works, but assistants pay attention to your coding style and other evaluation criteria listed above. Therefore, it could be possible that a fully working program brings you only zero points, if the above criteria are not met.

Requirements concerning especially good programming style can be found from the earlier material section on the current round.

Note about submission versions

The version to be evaluated is the one that corresponds to your latest successful Plussa submission (within the deadline). A successful submission means such a submission that passed automated tests.

After the first successful submission, you most probably want to improve your coding style (e.g. add comments), assuming that the deadline is not too close.

Anyway, remember finally this: After the final Git push, submit your work also in Plussa.

A+ presents the exercise submission form here.