1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

class GameOfLife: 

def __init__(self, sizex, sizey): 

assert sizex > 0 

assert sizey > 0 

 

self.sizex = sizex 

self.sizey = sizey 

self.cells = [[NoUnit(i, j) for j in range(sizey)] for i in range(sizex)] 

 

def parse_field(self, field): 

assert len(field) == self.sizex 

 

x = 0 

for line in field: 

y = 0 

assert len(line) == self.sizey 

for char in line: 

if char == 'f': 

self.cells[x][y] = FishUnit(x, y) 

if char == 's': 

self.cells[x][y] = ShrimpUnit(x, y) 

if char == 'r': 

self.cells[x][y] = RockUnit(x, y) 

y += 1 

x += 1 

 

def print_field(self): 

dict = { 

'NoUnit': 'n', 

'RockUnit': 'r', 

'ShrimpUnit': 's', 

'FishUnit': 'f' 

} 

for x in range(self.sizex): 

for y in range(self.sizey): 

print(dict[self.cells[x][y].type], sep='', end='') 

print() 

 

def correct_coors(self, x, y): 

return 0 <= x < self.sizex and 0 <= y < self.sizey 

 

def iterate(self): 

new_cells = [[NoUnit(i, j) for j in range(self.sizey)] for i in range(self.sizex)] 

 

neighbour_diffs = [ 

[-1, -1], 

[0, -1], 

[1, -1], 

[-1, 0], 

[1, 0], 

[-1, 1], 

[0, 1], 

[1, 1] 

] 

 

for x in range(self.sizex): 

for y in range(self.sizey): 

neighbours = [self.cells[x - d[0]][y - d[1]] 

if self.correct_coors(x - d[0], y - d[1]) else 

NoUnit(0, 0) 

for d in neighbour_diffs] 

# print(x, y, neighbours) 

if not self.cells[x][y].should_be_killed(neighbours): 

new_cells[x][y] = self.cells[x][y] 

 

if self.cells[x][y].can_spawn_fish(neighbours): 

new_cells[x][y] = FishUnit(x, y) 

elif self.cells[x][y].can_spawn_shrimp(neighbours): 

new_cells[x][y] = ShrimpUnit(x, y) 

 

self.cells = new_cells 

 

class Unit: 

def __init__(self, posx, posy): 

self.posx = posx 

self.posy = posy 

self.type = 'Unit' 

 

def should_be_killed(self, neighbours): 

return False 

 

def can_spawn_shrimp(self, neighbours): 

return False 

 

def can_spawn_fish(self, neighbours): 

return False 

 

def __str__(self): 

return self.type + '(' + str(self.posx) + ', ' + str(self.posy) + ')' 

 

def __repr__(self): 

return self.type + '(' + str(self.posx) + ', ' + str(self.posy) + ')' 

 

def __eq__(self, other): 

return self.type == other.type and self.posx == other.posx and self.posy == other.posy 

 

 

class NoUnit(Unit): 

def __init__(self, posx, posy): 

super().__init__(posx, posy) 

self.type = 'NoUnit' 

 

def can_spawn_shrimp(self, neighbours): 

ns_num = sum(1 if neighbour.type == 'ShrimpUnit' else 0 for neighbour in neighbours) 

return ns_num == 3 

 

def can_spawn_fish(self, neighbours): 

ns_num = sum(1 if neighbour.type == 'FishUnit' else 0 for neighbour in neighbours) 

return ns_num == 3 

 

 

class FishUnit(Unit): 

def __init__(self, posx, posy): 

super().__init__(posx, posy) 

self.type = 'FishUnit' 

 

def should_be_killed(self, neighbours): 

ns_num = sum(1 if neighbour.type == 'FishUnit' else 0 for neighbour in neighbours) 

return ns_num < 2 or ns_num >= 4 

 

 

class ShrimpUnit(Unit): 

def __init__(self, posx, posy): 

super().__init__(posx, posy) 

self.type = 'ShrimpUnit' 

 

def should_be_killed(self, neighbours): 

ns_num = sum(1 if neighbour.type == 'ShrimpUnit' else 0 for neighbour in neighbours) 

return ns_num < 2 or ns_num >= 4 

 

 

class RockUnit(Unit): 

def __init__(self, posx, posy): 

super().__init__(posx, posy) 

self.type = 'RockUnit' 

 

def should_be_killed(self, neighbours): 

return False