Nim is a two-player strategy game. The player that goes first chooses a number ($$n \geq 2$$) of heaps. Then the same player puts any number of matches in each heap. Heaps may be empty and the number of matches may differ between heaps. To refer to the individual heaps, they are numbered sequentially from 1 to $$n$$. Here's a possible initial configuration with five heaps, with heap #4 being empty.

nim
Possible configuration at the start of a game of Nim.

The two players take turns removing matches from the heaps. On each turn, a player must remove at least one match, and may remove any number of matches provided they all come from the same heap. The player that removes the last match wins the game.

Assignment

Define a class Nim that can be used to simulate games of Nim. Two or more natural numbers (int) must be passed when creating a new game (Nim). The numbers describe the initial configuration of the game: the number of arguments corresponds to the number of heaps and each argument indicates how many matches are in the heap at the start of the game. In case no two or more natural numbers are passed, an AssertionError must be raised with the message invalid heaps.

If a game $$g$$ (Nim) is passed to the built-in function repr, it must return a string representation (str) that reads as a Python expression to create a new game (Nim) with an initial configuration that corresponds with the current number of matches in the heaps of $$g$$. Take a look at the example below to see how this string representation must be formatted.

If a game $$g$$ (Nim) is passed to the built-in function str, it must return an overview (str) of the current number of matches per heap in $$g$$. The overview must list the heaps in increasing order by number, one heap per line. Each heap is represented by its number, a colon (:), a space and a number of vertical bars (|) that corresponds to the number of matches in the heap. Take a look at the example below to see how this string representation must be formatted.

Make sure the following methods can be called on a game $$g$$ (Nim):

For two games $$g$$ and $$g'$$ (Nim) the operation $$g + g'$$ must yield a new game $$g''$$ (Nim) that has the same number of heaps as the maximum number of heaps of $$g$$ and $$g'$$. The number of matches in each heap of $$g''$$ must correspond to the sum of the number of matches in the corresponding heaps of $$g$$ and $$g'$$, with non-existing heaps containing no matches by definition. The operation may not change the games $$g$$ and $$g'$$.

Example

>>> nim = Nim(3, 4, 2, 0, 7)
>>> nim
Nim(3, 4, 2, 0, 7)
>>> print(nim)
1: |||
2: ||||
3: ||
4:
5: |||||||
>>> nim.take_away(2, 3)
Nim(3, 1, 2, 0, 7)
>>> print(nim)
1: |||
2: |
3: ||
4:
5: |||||||
>>> nim.take_away(5, 2).take_away(5, 1)
Nim(3, 1, 2, 0, 4)
>>> nim.take_away(1, 4)            # not enough matches in heap
Traceback (most recent call last):
AssertionError: invalid move
>>> nim.take_away(7, 1)            # heap does not exist
Traceback (most recent call last):
AssertionError: invalid move
>>> nim.take_away(3, 0)            # at least one match must be taken away
Traceback (most recent call last):
AssertionError: invalid move
>>> print(nim)
1: |||
2: |
3: ||
4:
5: ||||
>>> nim.isfinished()
False
>>> nim.take_away(1, 3).take_away(2, 1).take_away(3, 2).take_away(5, 4)
Nim(0, 0, 0, 0, 0)
>>> nim.isfinished()
True

>>> Nim(4, 3, 0, 5) + Nim(3, 0, 2, 1, 6, 2)
Nim(7, 3, 2, 6, 6, 2)

>>> Nim(1.0, 2.0, 3.0, 4.0, 5.0)     # all arguments must be integers
Traceback (most recent call last):
AssertionError: invalid heaps
>>> Nim('three', 'seven', 'two')     # all arguments must be integers
Traceback (most recent call last):
AssertionError: invalid heaps
>>> Nim(7)                           # there must be at least one argument
Traceback (most recent call last):
AssertionError: invalid heaps