"""Game of Life simulation. life2 clone of life.py by me from freegames on 2018-11-09 Conway's game of life is a classic cellular automation created in 1970 by John Conway. https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life Exercises 1. Can you identify any Still Lifes, Oscillators, or Spaceships? 2. How can you make the simulation faster? Or bigger? ->process just living cells and build a list of their dead neighbors - birth any dead neighbors - kill any living cells that need killin - update just the newly dead and newly born cells on the screen - NOTE: after many loops the program slows down and garbage collection does not help. This is a mystery because the number of live cells doesn't seem to match how slow it runs (say, after 10 or 15 minutes.) 3. How would you modify the initial state? - alter the random number seed using a table of seeds and an index into the table that can be changed for each run. this is a way to collect interesting scenarios without specifying each individual starting cell. 4. Try changing the rules of life :) - well, not the birth/deaths but the rules call for an unbounded cell array; make it so by connecting the top edge of the board to the bottom edge, and the left to the right. - also, give each generation a new color. loop through the Tk colorstring names in a pleasing order. Free Python Games License ------------------------- Copyright 2017 Grant Jenks Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import gc import collections import random from turtle import * from freegames import square global boardTorus, loopCount, color, colorIndex, justDied, justBorn, livingCells BOARD_IS_A_TORUS = True GARBAGE_COLLECT_AT = 500 XY_MAX = 300 BOX_SIZE = 15 BOARD_SIDE = 2 * (XY_MAX + BOX_SIZE) LOOP_TIMER = 1 DEAD_COLOR = 'black' XY_INIT = 300 CHOICE = [1, 1, 1, 0, 0] RANDOM_SEEDS_INDEX = 1 RANDOM_SEEDS = [ None, 127, 131, '37', '13', '5', '29', '87', '101', 'remaining seeds yet to be tested:', 151, 157, 163 , 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 , 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349 , 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443 , 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557 , 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647 , 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757 , 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863 , 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983 , 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171 , 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471 , 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753 , 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081 , 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381 , 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699 , 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999] NEW_LIFE_COLORS = [ 'snow', 'old lace', 'bisque', 'ivory', 'azure', 'white', 'light slate gray', 'cornflower blue', 'medium blue', 'sky blue', 'powder blue', 'cyan', 'dark green', 'light sea green', 'chartreuse', 'forest green', 'light goldenrod yellow', 'goldenrod', 'sienna', 'sandy brown', 'dark salmon', 'coral', 'hot pink', 'maroon', 'plum', 'blue violet', 'snow3', 'AntiqueWhite1', 'bisque3', 'ghost white', 'linen', 'peach puff', 'lemon chiffon', 'alice blue', 'gray', 'dark slate blue', 'royal blue', 'light sky blue', 'pale turquoise', 'light cyan', 'dark olive green', 'pale green', 'medium spring green', 'olive drab', 'light yellow', 'dark goldenrod', 'peru', 'tan', 'salmon', 'light coral','deep pink', 'medium violet red', 'orchid', 'purple', 'snow4', 'AntiqueWhite2', 'bisque4', 'white smoke', 'antique white', 'navajo white', 'seashell', 'lavender', 'dark slate gray', 'light grey', 'slate blue', 'blue', 'steel blue', 'dark turquoise', 'cadet blue', 'dark sea green', 'spring green', 'green yellow', 'dark khaki', 'yellow', 'rosy brown', 'burlywood', 'chocolate', 'light salmon', 'tomato', 'pink', 'violet red', 'medium orchid', 'medium purple', 'seashell2', 'AntiqueWhite3', 'PeachPuff2', 'gainsboro', 'papaya whip', 'moccasin', 'honeydew', 'lavender blush', 'dim gray', 'midnight blue', 'medium slate blue', 'dodger blue', 'light steel blue', 'medium turquoise', 'medium aquamarine', 'sea green', 'lawn green', 'lime green', 'khaki', 'gold', 'indian red', 'beige', 'firebrick', 'orange', 'orange red', 'light pink', 'magenta', 'dark orchid', 'thistle', 'seashell3', 'AntiqueWhite4', 'PeachPuff3', 'floral white', 'blanched almond', 'cornsilk', 'mint cream', 'misty rose', 'slate gray', 'navy', 'light slate blue', 'deep sky blue', 'light blue', 'turquoise', 'aquamarine', 'medium sea green', 'green', 'yellow green', 'pale goldenrod', 'light goldenrod', 'saddle brown', 'wheat', 'brown', 'dark orange', 'red', 'pale violet red', 'violet', 'dark violet', 'snow2', 'seashell4', 'bisque2', 'PeachPuff4'] Point = collections.namedtuple('Point', ['x', 'y']) livingCells = set() justBorn = set() justDied = set() colorIndex = 0 color = NEW_LIFE_COLORS[colorIndex] loopCount = 0 def initialize(): "Randomly initialize the cells." random.seed(a=RANDOM_SEEDS[RANDOM_SEEDS_INDEX], version=2) for x in range(-XY_MAX, XY_MAX, BOX_SIZE): for y in range(-XY_MAX, XY_MAX, BOX_SIZE): if (-XY_INIT <= x <= XY_INIT and -XY_INIT <= y <= XY_INIT): c = random.choice(CHOICE) if c: justBorn.add(Point(x, y)) livingCells.add(Point(x, y)) else: justDied.add(Point(x, y)) else: justDied.add(Point(x, y)) def step(): "Compute one step in the Game of Life." global loopCount, color, colorIndex, justDied, justBorn, livingCells justBorn.clear() justDied.clear() loopCount = (loopCount + 1) % GARBAGE_COLLECT_AT if loopCount == 0: gc.collect() deadNeighbors = {} for p in livingCells: count = -1 for h in [-BOX_SIZE, 0, BOX_SIZE]: for v in [-BOX_SIZE, 0, BOX_SIZE]: qX = p.x + h qY = p.y + v if BOARD_IS_A_TORUS: if qX > XY_MAX: qX = -XY_MAX elif qX < -XY_MAX: qX = XY_MAX # next line to prevent eating the upper border line if qY >= XY_MAX - 1: qY = -XY_MAX elif qY < -XY_MAX: qY = XY_MAX - 2 q = Point(qX, qY) if q in livingCells: count += 1 elif (BOARD_IS_A_TORUS or (XY_MAX > q.x > -XY_MAX and XY_MAX > q.y >= -XY_MAX)): deadNeighbors[q] = (deadNeighbors.get(q, 0) + 1) if count < 2 or count > 3: justDied.add(p) for p in justDied: livingCells.remove(p) for p, count in deadNeighbors.items(): if count == 3: justBorn.add(p) livingCells.add(p) colorIndex = (colorIndex + 1) % len(NEW_LIFE_COLORS) color = NEW_LIFE_COLORS[colorIndex] def draw(): "Draw all the squares...that changed" for p in justDied: square(p.x, p.y, BOX_SIZE, DEAD_COLOR) for p in justBorn: square(p.x, p.y, BOX_SIZE, color) update() step() #ontimer(draw, LOOP_TIMER) #delay(LOOP_TIMER) setup(BOARD_SIDE, BOARD_SIDE, BOARD_SIDE, 0) hideturtle() tracer(False) clear() initialize() while True: draw() exitonclick() #mainloop()