A notorious problem in molecular biology,is protein folding. A protein molecule consists of a chain of amino acids that spontaneously folds into a three-dimensional shape that is more energetically favorable . This binding energy depends on the mutual position of all amino acids. This provides so many options that even the most advanced supercomputers still crash here.

In order to make the problem somewhat easier we are going to simulate a protein molecule that folds in two dimensions. The initial state is a square grid in which each amino acid has a positive or negative charge. The folding is done by placing baffles between the boxes in such a way that a circuit is created through the grid that includes all the booths. The ends of the molecule do not have to be situated at the edge of the grid.

Whenever a baffle is positioned between two boxes, the molecule is folded and the amino acids are touching each other. If there is a baffle between a box with charge $$-3$$ and a box with charge $$4$$, this results in a binding energy of $$-3 \times 4 = -12$$. An amino acid can affect several other amino acids, and then yield binding energy with every neighbour. Of course, due to the minus signs, binding energy can be both positive and negative.

eiwitvouwen

For example, you can see a $$4\times4$$ grid above, in which a protein with 16 amino acids is folded to a configuration with binding energy equal to \[ \begin{multline} \phantom{xxxxxxxxxxxx}(-1 \times 2) + (2 \times -5) + (5 \times -3) + (4 \times 3) + (5\times -1) + \phantom{x}\\ (-1 \times 2) + (-4 \times 2) + (-5 \times 6) + (1 \times 2) =  -58\phantom{xxxxxxxxxxxx} \nonumber \end{multline} \]

Assignment

Define a class Protein with the following methods:

Example

>>> protein = Protein([-2, 5, -4, 2, 4, -1, 2])
Traceback (most recent call last):
AssertionError: invalid initial state

>>> protein = Protein([-2, 5, -4, 2, 4, -1, 2, 1, 3, 2, -5, 2, 5, -3, 6, 1])
>>> eiwit.bindingenergy()
0
>>> print(protein)
+----+----+----+----+
| -2   5    -4   2  |
+    +    +    +    +
| 4    -1   2    1  |
+    +    +    +    +
| 3    2    -5   2  |
+    +    +    +    +
| 5    -3   6    1  |
+----+----+----+----+

>>> protein.fold([(1, 1, 1, 2), (2, 1, 2, 2), (3, 0, 3, 1),
...                 (1, 0, 2, 0), (0, 1, 1, 1), (1, 1, 2, 1),
...                 (0, 2, 1, 2), (2, 2, 3, 2), (1, 3, 2, 3)])
>>> protein.bindingenergy()
-58
>>> print(protein)
+----+----+----+----+
| -2   5    -4   2  |
+    +----+----+    +
| 4    -1 | 2    1  |
+----+----+    +----+
| 3    2  | -5   2  |
+    +    +----+    +
| 5  | -3   6    1  |
+----+----+----+----+

>>> protein.fold([(1, 1, 1, 2), (2, 1, 2, 2), (4, 0, 4, 1)])
Traceback (most recent call last):
AssertionError: invalid configuration
>>> protein.fold([(1, 1, 1, 2), (2, 1, 3, 3), (3, 0, 3, 1)])
Traceback (most recent call last):
AssertionError: invalid configuration

>>> protein = Protein([7, -2, -4, 3], [(0, 1, 1, 1)])
>>> protein.bindingenergy()
-6
>>> print(protein)
+----+----+
| 7    -2 |
+    +----+
| -4   3  |
+----+----+