@@ -63,15 +63,110 @@ def __eq__(self, other):
63
63
def __neq__ (self , other ):
64
64
return not self .__eq__ (other )
65
65
66
+ def __add__ (self , other ):
67
+ return Position (x = self .x + other .x , y = self .y + other .y )
68
+
69
+ def __sub__ (self , other ):
70
+ return Position (x = self .x - other .x , y = self .y - other .y )
71
+
66
72
def serialize (self ):
67
- return { 'x' : self .x , 'y' : self .y }
73
+ return [ self .x , self .y ]
68
74
69
75
def deserialize (self , attrs ):
70
- self .x = attrs ['x' ]
71
- self .y = attrs ['y' ]
76
+ self .x = attrs [0 ]
77
+ self .y = attrs [1 ]
72
78
return self
73
79
74
80
81
+ def _direction_between_points (startpos , endpos , allow_jumps = False ):
82
+ ret = None
83
+ diff = endpos - startpos
84
+
85
+ if (not allow_jumps ) and ((abs (diff .x ) > 1 ) or (abs (diff .y ) > 1 )):
86
+ return None
87
+
88
+ if diff .x < 0 :
89
+ ret = Direction .LEFT
90
+ elif diff .x > 0 :
91
+ ret = Direction .RIGHT
92
+ elif diff .y < 0 :
93
+ ret = Direction .DOWN
94
+ elif diff .y > 0 :
95
+ ret = Direction .UP
96
+
97
+ return ret
98
+
99
+ def _serialize_snake_positions (positions ):
100
+ """
101
+ Compress all snake segment positions to a list of only the head, tail and corner positions
102
+ """
103
+ ret = []
104
+ chunk = []
105
+ last_pos = None
106
+ last_direction = None
107
+
108
+ for pos in positions :
109
+ if last_pos is None :
110
+ chunk .append ([pos .x , pos .y ])
111
+ else :
112
+ direction = _direction_between_points (last_pos , pos )
113
+ if direction is None :
114
+ # Wall wrap
115
+ if not ((chunk [- 1 ][0 ] == last_pos .x ) and (chunk [- 1 ][1 ] == last_pos .y )):
116
+ chunk .append ((last_pos .x , last_pos .y ))
117
+
118
+ ret .append (chunk )
119
+ chunk = [(pos .x , pos .y )]
120
+ last_pos = pos
121
+ else :
122
+ if last_direction is not None :
123
+ if last_direction != direction :
124
+ chunk .append ((last_pos .x , last_pos .y ))
125
+
126
+ last_direction = direction
127
+
128
+ last_pos = pos
129
+
130
+ chunk .append ((positions [- 1 ].x , positions [- 1 ].y ))
131
+ ret .append (chunk )
132
+
133
+ return ret
134
+
135
+ def _draw_line (startpos , endpos ):
136
+ diff = endpos - startpos
137
+ direction = _direction_between_points (startpos , endpos , allow_jumps = True )
138
+ move = _MOVEMAP [direction ]
139
+
140
+ ret = [startpos ]
141
+ newpos = startpos
142
+ while newpos != endpos :
143
+ newpos = Position (x = newpos .x + move [0 ], y = newpos .y + move [1 ])
144
+ ret .append (newpos )
145
+
146
+ return ret
147
+
148
+ def _deserialize_snake_positions (attrs ):
149
+ """
150
+ Convert a serialized list of snake head, tail and corner positions, to a full
151
+ list of snake segment positions
152
+ """
153
+ ret = []
154
+ for chunk in attrs :
155
+ for i in range (len (chunk [:- 1 ])):
156
+ x = chunk [i ][0 ]
157
+ y = chunk [i ][1 ]
158
+ nextx = chunk [i + 1 ][0 ]
159
+ nexty = chunk [i + 1 ][1 ]
160
+
161
+ newps = _draw_line (Position (x = x , y = y ), Position (x = nextx , y = nexty ))
162
+ if ret and (newps [0 ] == ret [- 1 ]) and (len (newps ) > 2 ):
163
+ newps .pop (0 )
164
+
165
+ ret .extend (newps )
166
+
167
+ return ret
168
+
169
+
75
170
@dataclass
76
171
class SnakeGameState (object ):
77
172
"""
@@ -112,7 +207,7 @@ def serialize(self):
112
207
return {
113
208
'area_width' : self .area_width ,
114
209
'area_height' : self .area_height ,
115
- 'snake_segments' : [ x . serialize () for x in self .snake_segments ] ,
210
+ 'snake_segments' : _serialize_snake_positions ( self .snake_segments ) ,
116
211
'snake_direction' : self .snake_direction ,
117
212
'score' : self .score ,
118
213
'apple_position' : self .apple_position .serialize (),
@@ -128,7 +223,7 @@ def deserialize(self, attrs):
128
223
"""
129
224
self .area_width = attrs ['area_width' ]
130
225
self .area_height = attrs ['area_height' ]
131
- self .snake_segments = [ Position (). deserialize ( x ) for x in attrs ['snake_segments' ]]
226
+ self .snake_segments = _deserialize_snake_positions ( attrs ['snake_segments' ])
132
227
self .snake_direction = attrs ['snake_direction' ]
133
228
self .score = attrs ['score' ]
134
229
self .apple_position = Position ().deserialize (attrs ['apple_position' ])
0 commit comments