@@ -999,7 +999,24 @@ game is a grid of squares, like an infinite piece of graph paper (though we'll
999
999
only work with finite boards, since our computers have finite memory). Each cell
1000
1000
on the board is either alive (value 1) or dead (value 0). The only human
1001
1001
interaction is to set the initial state of every square on the board to either
1002
- alive or dead. The game then proceeds as a series of
1002
+ alive or dead. The game then proceeds as a series of steps. At each step the new
1003
+ state of the board is calculated according to these rules:
1004
+
1005
+ 0. The neighbours of a square are the 8 immediately surrounding squares.
1006
+ 1. Any square with exactly 3 live neighbours on the old board is live on the new
1007
+ board.
1008
+ 2. Any square which is alive on the old board and has exactly 2 live neighbours
1009
+ on the old board remains alive on the new board.
1010
+ 3. All other squares on the new board are dead.
1011
+
1012
+ Using only these three rules, an amazingly complex array of behaviour can be
1013
+ generated, depending only on the pattern of cells which starts off alive.
1014
+ For example there are patterns of cells which are fixed, called "rocks",
1015
+ "gliders" that fly across the board and "oscillators" which repeatedly switch
1016
+ between a few states. It's simultaneously a fun toy and an important piece of
1017
+ mathematics. For example, it's possible to prove that any algorithm that can be
1018
+ executed on any computer can be represented by a suitable pattern of game of
1019
+ life cells, and running the game will execute the algorithm.
1003
1020
1004
1021
Glossary
1005
1022
--------
@@ -1044,18 +1061,148 @@ Exercises
1044
1061
1045
1062
The test should check that flake8 is importable.
1046
1063
1047
- .. note ::
1064
+ The :doc: `skeleton code for this week's exercises on GitHub Classroom
1065
+ <not_released>` contains a package :mod: `life ` which implements Conway's Game of
1066
+ Life. Accept the assignment, and clone the repository. Install the package in
1067
+ editable mode. This will also install some additional packages that the
1068
+ :mod: `life ` package depends on. This is achieved using an additional argument to
1069
+ :func: `setuptools.setup `.
1070
+
1071
+ .. code-block :: python3
1072
+ :caption: `setup.py` for the :mod:`life` package. The `install_requires`
1073
+ parameter is used to install other packages that :mod:`life` needs.
1074
+
1075
+ from setuptools import setup, find_packages
1076
+ setup(
1077
+ name="life",
1078
+ version="0.1",
1079
+ packages=find_packages(),
1080
+ install_requires=[
1081
+ "matplotlib",
1082
+ "scipy",
1083
+ "numpy"
1084
+ ]
1085
+ )
1086
+
1087
+ A couple of example scripts are provided which demonstrate the game of life.
1088
+ This one shows a glider flying across the board:
1048
1089
1049
- Use this example in the exercises or quiz:
1090
+ .. code-block :: console
1050
1091
1051
- False if src_petsc4py_exists and args.honour_petsc_dir else True
1092
+ $ python scripts/glider.py
1093
+
1094
+ Running the script will pop up a window showing the board. If Visual Studio Code
1095
+ is in full screen mode then that pop-up might appear on a different screen. It's
1096
+ therefore a good idea to unmaximise Visual Studio Code before running the
1097
+ script.
1098
+
1099
+ This script shows a `glider gun
1100
+ <https://en.wikipedia.org/wiki/Gun_(cellular_automaton)> `__, which generates a
1101
+ neverending sequence of gliders:
1102
+
1103
+ .. code-block :: console
1104
+
1105
+ $ python scripts/glider_gun.py
1106
+
1107
+ .. proof :exercise ::
1108
+
1109
+ The author of the :mod: `life ` package had clearly never heard of PEP8: the
1110
+ style of the code is awful. Fix the style in the package so that there are
1111
+ no flake8 errors.
1112
+
1113
+ .. proof :exercise ::
1114
+
1115
+ .. figure :: images/glider.png
1116
+ :height: 10em
1117
+ :align: right
1118
+
1119
+ An upright glider, live squares in black.
1120
+
1121
+ A pattern such as a glider clearly maintains its behaviour if translated,
1122
+ reflected or rotated.
1123
+
1124
+ 1. Add a class :class: `Pattern ` to :mod: `life.life `. The :term: `constructor ` should
1125
+ take in a :mod: `numpy ` array containing a pattern of 1s and 0s, and
1126
+ assign it to the :term: `attribute ` `grid `.
1127
+ 2. Add :class: `Pattern ` to the :keyword: `import ` statement in
1128
+ :mod: `life.__init__ `.
1129
+
1130
+ .. figure :: images/glider_v.png
1131
+ :height: 10em
1132
+ :align: right
1133
+
1134
+ Vertically flipped glider.
1135
+
1136
+ 3. Add a :term: `method ` :meth: `flip_vertical ` which returns a new
1137
+ :class: `Pattern ` whose rows are in reversed order, so that the pattern
1138
+ is upside down.
1139
+
1140
+ .. hint ::
1141
+
1142
+ A slice of the form `::-1 ` returns that dimension of an array in
1143
+ reverse order.
1144
+
1145
+ .. figure :: images/glider_h.png
1146
+ :height: 10em
1147
+ :align: right
1052
1148
1149
+ Horizontally flipped glider.
1053
1150
1054
- .. note ::
1151
+ 4. Add a :term: `method ` :meth: `flip_horizontal ` which returns a new
1152
+ :class: `Pattern ` whose rows are in reversed order, so that the pattern
1153
+ is reversed left-right.
1154
+
1155
+ .. figure :: images/glider_t.png
1156
+ :height: 10em
1157
+ :align: right
1158
+
1159
+ Transposed glider.
1160
+
1161
+ 5. Add a :term: `method ` :meth: `flip_diag ` which returns a new pattern which
1162
+ is the transpose of the original.
1163
+ 6. Add a :term: `method ` :meth: `rotate ` with a :term: `parameter ` `n `.
1164
+ This should return a new :class: `Pattern ` which is the original pattern
1165
+ rotated through `n ` right angles anticlockwise.
1166
+
1167
+ .. hint ::
1168
+
1169
+ A rotation is the composition of a transpose and a reflection.
1170
+
1171
+ .. figure :: images/glider_r.png
1172
+ :height: 10em
1173
+ :align: center
1174
+
1175
+ Gliders rotated by 1, 2, and 3 right angles anticlockwise.
1176
+
1177
+
1178
+ .. proof :exercise ::
1179
+
1180
+ Add a method :meth: `insert ` to the :class: `Game ` class. This should take two
1181
+ paramaters, a :class: `Pattern ` and a pair of integers representing a square
1182
+ on the game board. The method should modify the game board so as to insert
1183
+ the pattern provided at a location centred on the location given by the pair
1184
+ of integers.
1185
+
1186
+ .. figure :: images/glider_inserted.png
1187
+ :width: 60%
1188
+ :align: center
1189
+
1190
+ A glider inserted at the location (2, 5) (highlighted in orange).
1191
+
1192
+ Once you have completed the exercises, the third script provided will work. This
1193
+ sets up two gliders which collide and eventually turn into a pattern of six
1194
+ oscillating blinkers:
1195
+
1196
+ .. code-block :: console
1197
+
1198
+ $ python scripts/two_gliders.py
1199
+
1200
+ .. note ::
1201
+
1202
+ Use this example in the quiz:
1203
+
1204
+ False if src_petsc4py_exists and args.honour_petsc_dir else True
1055
1205
1056
- TBC. We don't actually want a whole week of exercises on style. We want to do
1057
- more creation of classes and objects, but somehow requiring nontrivial
1058
- compliance with style rules.
1059
1206
1060
1207
.. rubric :: Footnotes
1061
1208
0 commit comments