BloxorzCS109 Programming ProjectsEliza2048 game

2048 game

In this project we implement the 2048 game.

The Board class

We also practice working with classes. Your task will be to complete the implementation of the Board class that represents the state of the game. A Board object contains an 4x4 array of integers. A zero represents an empty cell, other numbers represent themselves.

Start with the template board.kt, which contains a complete definition of the Board class. I have already written a nice toString() method, and also made it possible for you to create boards with a given contents.

You can compile the Board class and check the existing methods:

$ ktc board.kt 
$ ktc
Welcome to Kotlin version 1.0.5-2 
Type :help for help, :quit for quit
>>> val b = Board()
>>> b
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o

>>> val b1 = Board(2, 0, 4, 8, 16, 32, 0, 4, 128, 1024, 0, 16, 2, 2, 2048, 2)
>>> b1
o----o----o----o----o
|    |    |    |    |
|  2 |    |  4 |  8 |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
| 16 | 32 |    |  4 |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|128 |1024|    | 16 |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  2 |  2 |2048|  2 |
|    |    |    |    |
o----o----o----o----o

Insert

Your first task is to implement the insert() method. It needs to randomly select an empty cell (a cell with contents zero) and set its contents to \(2\) or \(4\). A good approach is to make a list (for instance of type List<Pair<Int,Int>>) with the coordinates of all empty cells. Then choose a random element from this list. You should set the cell to \(2\) with probability 90%, and to \(4\) with probability 10%.

Here is an example of a working insert() method:

$ ktc board.kt
$ ktc
Welcome to Kotlin version 1.0.5-2
Type :help for help, :quit for quit
>>> val b = Board()
>>> b
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o

>>> b.insert()
>>> b.insert()
>>> b
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |  2 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |    |    |  2 |
|    |    |    |    |
o----o----o----o----o

>>> for (i in 1..7)
...   b.insert()
>>> b
o----o----o----o----o
|    |    |    |    |
|  2 |  4 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |  2 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |  2 |  2 |  2 |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |  2 |  2 |  2 |
|    |    |    |    |
o----o----o----o----o

Pushing

The 2048 game has four basic moves: Pushing cells left, right, up, and down. The four methods pushLeft(), pushRight(), pushUp(), and pushDown() implement these moves.

Here is a precise description of the move, for the example of pushLeft():

The pushLeft method returns the number of points received by the left push.

Here are some examples to clarify the rules:

>>> b
o----o----o----o----o
|    |    |    |    |
|  2 |  2 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |    |  2 |  2 |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  2 |  2 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|    |  2 |    |  4 |
|    |    |    |    |
o----o----o----o----o

>>> b.pushLeft()
12
>>> b
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |  4 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  2 |  4 |    |    |
|    |    |    |    |
o----o----o----o----o

>>> b.insert(); b.insert()
>>> b
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |  4 |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  2 |  4 |  2 |  2 |
|    |    |    |    |
o----o----o----o----o

>>> b.pushLeft()
12
>>> b
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  8 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  4 |    |    |    |
|    |    |    |    |
o----o----o----o----o
|    |    |    |    |
|  2 |  4 |  4 |    |
|    |    |    |    |
o----o----o----o----o

The other three moves work exactly the same, only the direction is different. One way to implement this would be to write private methods for mirroring the board horizontally and for transposing it (that is, flipping rows and columns). Then you can implement the right push as mirror, left push, mirror, and the upwards push as transpose, left push, transpose, etc.

I have created a test suite check.kt that checks the four push methods of the Board class. (You can read about unit testing in the tutorial—but it's not necessary to read that to do this project.)

You need to compile the test suite only once, by saying

$ ktc check.kt
You can then run it as often as needed by saying
$ kttest Game2048Check
(Note the samewhat unusual command.)

Here is what the output looks like before you implement the four push methods:

$ kttest Game2048Check
JUnit version 4.12
.E.E.E.E..E
Time: 0.012
There were 5 failures:
1) points(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
... many more lines ...
2) rightPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
... many more lines ...
3) upPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
... many more lines ...
4) downPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
... many more lines ...
5) leftPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
... many more lines ...

FAILURES!!!
Tests run: 6,  Failures: 5
Note that one test (for the toString method) already passes correctly.

After implementing pushLeft correctly:

$ kttest Game2048Check
JUnit version 4.12
.E.E.E.E..
Time: 0.031
There were 4 failures:
1) points(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
2) rightPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
3) upPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.
4) downPushes(Game2048Check)
kotlin.NotImplementedError: An operation is not implemented.

FAILURES!!!
Tests run: 6,  Failures: 4
Note that the leftPushes test now passed.

Finally, when all four push methods have been implemented:

$ kttest Game2048Check
JUnit version 4.12
......
Time: 0.037

OK (6 tests)
That's when you can start singing and dancing!

The isFull method

We will need one last, short method: isFull must return true if no cell of the board is zero.

Running the game

With the Board class finished, you can run the game.

Download and run game.kt:

$ ktc game.kt
$ kt GameKt

Try it! You need to press the keys 'l', 'r', 'u', and 'd' to perform the pushes.

Graphical user interface

Maybe you are not satisfied with this simple text display?

Download and run uigame.kt:

$ ktc uigame.kt
$ kt UigameKt

(You can also try my web-based implementation. It is written in Kotlin and compiled to Javascript, so that it runs in your web browser.)

BloxorzCS109 Programming ProjectsEliza2048 game