BlockuDoku is a block puzzle game getting popular recently. The main goal of the game is to
match blocks of different shapes to complete lines and squares to get them removed from a
9x9 grid board. Download our provided zip of source files that implement a C++ console
program simulating this game. Most of the program is already written. Your task is to finish a
few missing functions. We will explain the components used in the game below.
1. Board: The game board is a grid of 9 rows and 9 columns. We use row index 1-9 and
column index A-I to uniquely identify every cell on the board. For example, 2H and 5E are
the cell addresses of the indicated cells in the diagram below.
(1) (2) (3)
2. Blocks: they are building blocks to be placed onto the board, each of which has a given
shape. For each move, the player is presented with 3 random choices of blocks, and
should pick one to drop onto the board. Each successful move will score some basic
points that equal the number of tiles (or grid points) of a block. In the above diagram,
placing block (1) [vertical bar of 5 grid points] on the board scores 5 points while placing
block (3) gets 4 points. Extra points are rewarded if a move fills up a line or square.
3. Line: a group of 9 cells arranged in a vertical or horizontal
line. This game ignores diagonal lines. Filling up a line will
score 9 x 2 = 18 extra points. A line, once filled up, will be
destroyed, i.e. removed from the board. An example on
the right illustrates how a line isformed. The player places
block (2) on the board filling the gap at cell 6A. The whole
column A gets filled, i.e. a vertical line is formed, scoring
18 extra points. All the 9 cells of column A will be unfilled
right away to free space for new blocks.
4. Square: a group of 3x3 cells at specific locations. Filling up a square will score 9 x 2 = 18
extra points. Just like a line, a square, once filled up, will be destroyed. Note that there
are only 9 valid squares for scoring on the board as shown below:
They are numbered with indices 0 to 8. A square is obtained if all the 9 cells under one of
the above numbered squares are filled. Filling up 3x3 cells at locations other than the
above does not get a square and scores no points. On the left diagram below, if the player
drops block (1) at 1B, the top 3 cells of columns B, C and D (a square shape) are filled. But
this 3x3 cell group is not one of the 9 designated squares. So, it is not counted as a scoring
square. On the right diagram, if the player places block (1) at 1G, this will fill up the top 3
cells of columns G, H and I. This gets the designated square 2, scoring 18 extra points.
5. Combo: a combo is achieved if several elements (e.g. two lines, or two squares, or one
line and one square) are destroyed at once. A move getting a combo will score 50 bonus
points besides the basic points from the block and extra points from the elementsformed.
For example, on the left diagram below, placing block (2) at cell 1A gets two lines (row 1
and column A) at the same time, scoring total 1 + 2 x 18 + 50 points. On the right diagram,
placing block (3) at the indicated position gets two squares and one line (square 1 and
square 2 and row 1) at once, scoring total 5 + 3 x 18 + 50 points.
6. Streak: a streak is achieved if elements (lines or squares) are destroyed in two or more
consecutive moves. Assume that the k-th move has destroyed an element. If the (k+1)-th
move destroys another element, this will score 30 bonus points. If the (k+2)-th move also
destroys an element, this leads to 60 bonus points. The next will score 90 and so on until
a move fails to destroy any elements; bonus points will be reset to zero. A new streak will
score 30 bonus points again. Combo and streak can be obtained at the same move.
Simulating BlockuDoku using C++
A B C D E F G H I
As our program output is text-based, the board is represented by a 9x9 2D array of 1’s and
0’s which denote filled and empty cells respectively. When the board is printed to the screen,
a space instead of 0 gets printed for an empty cell for ease of viewing. Likewise, a block is
represented by a 5x5 2D array of 1’s and 0’s where 1’s denote its solid grid points.
There are two classes Board and Block encapsulating the core data and functionality for this
program.
Board class:
• Data members:
o int grid[9][9]: the 2D array of integers representing the game board;
o int score: the current score obtained by the player;
o int streak: a counter recording the level of streak achieved so far;
• Member functions:
o for printing the board, moving a block onto the board, updating score, checking if a
move is valid at a given location, checking if a move is valid on the board by scanning
all locations, counting number of lines (or squares) formed, deleting all lines (or
squares) formed, checking if the game is over (i.e. no more valid moves possible)
Block class:
• Data members:
o int rows: number of rows taken by the shape;
o int cols: number of columns taken by the shape;
o int grid[5][5]: the 2D array of integers representing the block shape;
o int value: the number of grid points (how many 1’s in grid);
o bool placed: a flag indicating if this block has been placed onto the board;
• Member functions:
o for printing the block, getting rows, cols, and value, getting and setting placed,
returning the value (1 or 0) of a grid point of the block at a specific position
The Block.h header file has predefined S (= 45) blocks of different sizes and shapes using
two constant arrays: SIZE[S][2] and SHAPE[S][25]. The Block() constructor will pick
randomly one of the S elements in these arrays to construct a Block object. For example, a
T-shaped block below is represented by a Block object with content below.
The grid array (5x5) of a Block object can support up to 5 rows and 5 columns but for most
shapes, only a subset of which is used. The unused array elements are initialized to zeros.
Block object:
int rows = 2;
int cols = 3; 0 1 0 0 0
int grid[5][5]; 1 1 1 0 0
int value = 4; 0 0 0 0 0
bool placed = false; 0 0 0 0 0
0 0 0 0 0
3 cols
2 rows
7
Block Placements (Moves)
Placing a block x at a specified cell address on the board means matching the top left corner,
i.e. x.grid[0][0], of the block to the cell. See illustrations below to understand this.
For block (1), note that it can’t be placed at location 8B because we count from the top left
corner of the block. Putting it at 8B will cause a conflict (overlapping 1’s) at cell 9D which
contains value 1 already. Block (1) can be put at location 8A however to destroy column A. Its
grid[0][0] is 0 (shown as a blank) and can overlap with cell 8A (whose value is 1). For block
(2) – a diagonal shape of 3 grid points, the only valid positions for placing it are 7F and 7G.
A Snapshot of Sample Run
Below is a snapshot of a sample run. For ease of understanding, we highlighted some areas
of the output in colour while the real output to the console screen has no colour. Please refer
to our provided sample run log files and the sample program executable to understand the
correct behaviour of this program. Note that the random number sequences generated by
different compilers (Visual Studio on Windows vs. XCode on Mac) for the same seed could be
different, thus different blocks may be presented across different platforms.
Score: 128
Choose which block to drop [2][3]: 2
Invalid choice!
Choose which block to drop [2][3]: 3
Enter position to drop ([1-9][A-I]): 1d
Got a combo: +50
Cleared 1 line(s): +18
Cleared 1 square(s): +18
Score: 222
Note that at some later stage of a game run, the board
may run out of sufficient space to let some blocks in.
Block (2) in this case is such an example. Since it is unfit
to the board, we show a special mark "[X]" next to it to
indicate that it is an invalid choice at the moment. The
player must choose block (3) instead in this case to let
the game continue. If placing block (3) can clear some
lines or squares freeing the space needed, then block (2)
will become a valid choice again for the next move.
For the column index, typing
lower case or upper case does
not matter.
… (skipped the rest of output)
Programming Tasks
Based on the above problem specification, complete the game program by implementing the
following member functions in Board.cpp. Apart from adding these member functions,
don’t change any other parts of our provided source code (including the header files).
(a) bool move(Block &block, char pos[]); (25%)
Simulates placing the specified block at the given cell address on the game board. The
grid array of this Board object is updated to reflect the block placement. It accepts two
parameters:
1. block: a Block object chosen by the player
2. pos[]: a 2-element array denoting the cell address, e.g. {'1','A'}
It returnstrue if block can be placed at the location denoted by pos and false otherwise.
Now block (2) becomes a valid choice again.
10
Steps to do in this function:
1. Translate the cell address to grid array indexes (r, c), e.g. 1A → (0,0), 3D → (2,3). This
step has been done for you. Finish the rest under the TODO comment in move().
2. Check whether the move of the block is valid at (r, c). Hint: think of which member
function can help, and just call it.
3. If valid, copy the block's grid onto the board's grid. The block's grid[0][0] (the
block's top left corner) should match with the board's grid[r][c] (i.e. the specified
cell address). Note: don't overwrite the existing 1's in the board’s grid array.
4. Check for any lines and squares formed due to this move.
o To get the count of lines, call countLines(), passing two 1D bool arrays of size
9 for marking which of the 9 rows and 9 columns have line(s).
o To get the count of squares, call countSquares(), passing one 1D bool array
of size 9 for marking which of the 9 designated squares are formed.
o Delete line(s) and square(s), if any, based on the marked bool arrays.
5. Update the score for the move by calling updateScore(), passing the block object,
the counts of lines and squares obtained from the last step.
(b) bool isMoveValid(Block &block, int r, int c) const; (20%)
Checksif a move (block placement) is valid at location (r, c). It returnstrue if the specified
block can be placed at (r, c) on the board, and false otherwise.
Suppose the block has y rows and x columns, and its top left corner is placed at (r, c).
The move is invalid (return false)
• if r or c exceeds the range of the board’s grid array indexes (0 – 8);
• if (r + y) or (c + x) exceeds the board’s width or height, i.e. some grid points of the
block are outside the board area;
• if any grid point of the block is 1 while the overlapping point on the board's grid is
already 1, i.e. a conflict.
If no such cases are found, the move is valid (return true).
(c) void deleteLines(bool rows[], bool cols[]); (10%)
Deletes the row(s) and column(s) indicated by rows[] and cols[] by changing all their
corresponding elements in board’s grid array from 1 to 0. For instance, if rows[2] is true,
all elements of the 3rd row of the board’s grid will be set to 0. The caller should pass a
1D bool array of size 9 with all elements initialized to zero for each of the parameters.
(d) int countSquares(bool squares[]) const; (15%)
Scansthe board’s grid array for any squares formed, and marks which of the 9 designated
squares are formed by setting the corresponding element(s) in squares[] to true. It
returnsthe total number of squares found. The caller should pass a 1D bool array of size
9 with all elements initialized to zero.
- The End -
版权所有:编程辅导网 2021 All Rights Reserved 联系方式:QQ:99515681 微信:codinghelp 电子信箱:99515681@qq.com
免责声明:本站部分内容从网络整理而来,只供参考!如有版权问题可联系本站删除。