Йордан обнови решението на 15.05.2013 13:59 (преди над 11 години)
+import copy
+import operator
+import math
+
+
+class Vec2D:
+ """2d vector class, supports vector and scalar operators."""
+ __slots__ = ['x', 'y']
+
+ def __init__(self, x_or_pair, y=None):
+ if y is None:
+ self.x = x_or_pair[0]
+ self.y = x_or_pair[1]
+ else:
+ self.x = x_or_pair
+ self.y = y
+
+ def __len__(self):
+ return 2
+
+ def __getitem__(self, key):
+ if key == 0:
+ return self.x
+ elif key == 1:
+ return self.y
+ else:
+ raise IndexError("Invalid subscript "+str(key)+" to Vec2D")
+
+ def __setitem__(self, key, value):
+ if key == 0:
+ self.x = value
+ elif key == 1:
+ self.y = value
+ else:
+ raise IndexError("Invalid subscript "+str(key)+" to Vec2D")
+
+ # String representation (for debugging)
+ def __repr__(self):
+ return 'Vec2D(%s, %s)' % (self.x, self.y)
+
+ # Comparison
+ def __eq__(self, other):
+ if hasattr(other, "__getitem__") and len(other) == 2:
+ return self.x == other[0] and self.y == other[1]
+ else:
+ return False
+
+ def __ne__(self, other):
+ if hasattr(other, "__getitem__") and len(other) == 2:
+ return self.x != other[0] or self.y != other[1]
+ else:
+ return True
+
+ def __nonzero__(self):
+ return bool(self.x or self.y)
+
+ # Generic operator handlers
+ def _o2(self, other, f):
+ "Any two-operator operation where the left operand is a Vec2D"
+ if isinstance(other, Vec2D):
+ return Vec2D(f(self.x, other.x),
+ f(self.y, other.y))
+ elif (hasattr(other, "__getitem__")):
+ return Vec2D(f(self.x, other[0]),
+ f(self.y, other[1]))
+ else:
+ return Vec2D(f(self.x, other),
+ f(self.y, other))
+
+ def _r_o2(self, other, f):
+ "Any two-operator operation where the right operand is a Vec2D"
+ if (hasattr(other, "__getitem__")):
+ return Vec2D(f(other[0], self.x),
+ f(other[1], self.y))
+ else:
+ return Vec2D(f(other, self.x),
+ f(other, self.y))
+
+ def _io(self, other, f):
+ "inplace operator"
+ if (hasattr(other, "__getitem__")):
+ self.x = f(self.x, other[0])
+ self.y = f(self.y, other[1])
+ else:
+ self.x = f(self.x, other)
+ self.y = f(self.y, other)
+ return self
+
+ # Addition
+ def __add__(self, other):
+ if isinstance(other, Vec2D):
+ return Vec2D(self.x + other.x, self.y + other.y)
+ elif hasattr(other, "__getitem__"):
+ return Vec2D(self.x + other[0], self.y + other[1])
+ else:
+ return Vec2D(self.x + other, self.y + other)
+ __radd__ = __add__
+
+ def __iadd__(self, other):
+ if isinstance(other, Vec2D):
+ self.x += other.x
+ self.y += other.y
+ elif hasattr(other, "__getitem__"):
+ self.x += other[0]
+ self.y += other[1]
+ else:
+ self.x += other
+ self.y += other
+ return self
+
+ # Subtraction
+ def __sub__(self, other):
+ if isinstance(other, Vec2D):
+ return Vec2D(self.x - other.x, self.y - other.y)
+ elif (hasattr(other, "__getitem__")):
+ return Vec2D(self.x - other[0], self.y - other[1])
+ else:
+ return Vec2D(self.x - other, self.y - other)
+
+ def __rsub__(self, other):
+ if isinstance(other, Vec2D):
+ return Vec2D(other.x - self.x, other.y - self.y)
+ if (hasattr(other, "__getitem__")):
+ return Vec2D(other[0] - self.x, other[1] - self.y)
+ else:
+ return Vec2D(other - self.x, other - self.y)
+
+ def __isub__(self, other):
+ if isinstance(other, Vec2D):
+ self.x -= other.x
+ self.y -= other.y
+ elif (hasattr(other, "__getitem__")):
+ self.x -= other[0]
+ self.y -= other[1]
+ else:
+ self.x -= other
+ self.y -= other
+ return self
+
+ # Multiplication
+ def __mul__(self, other):
+ if isinstance(other, Vec2D):
+ return Vec2D(self.x*other.x, self.y*other.y)
+ if (hasattr(other, "__getitem__")):
+ return Vec2D(self.x*other[0], self.y*other[1])
+ else:
+ return Vec2D(self.x*other, self.y*other)
+ __rmul__ = __mul__
+
+ def __imul__(self, other):
+ if isinstance(other, Vec2D):
+ self.x *= other.x
+ self.y *= other.y
+ elif (hasattr(other, "__getitem__")):
+ self.x *= other[0]
+ self.y *= other[1]
+ else:
+ self.x *= other
+ self.y *= other
+ return self
+
+ # Division
+ def __div__(self, other):
+ return self._o2(other, operator.truediv)
+
+ def __rdiv__(self, other):
+ return self._r_o2(other, operator.truediv)
+
+ def __idiv__(self, other):
+ return self._io(other, operator.truediv)
+
+ def __floordiv__(self, other):
+ return self._o2(other, operator.floordiv)
+
+ def __rfloordiv__(self, other):
+ return self._r_o2(other, operator.floordiv)
+
+ def __ifloordiv__(self, other):
+ return self._io(other, operator.floordiv)
+
+ def __truediv__(self, other):
+ return self._o2(other, operator.truediv)
+
+ def __rtruediv__(self, other):
+ return self._r_o2(other, operator.truediv)
+
+ def __itruediv__(self, other):
+ return self._io(other, operator.floordiv)
+
+ # Modulo
+ def __mod__(self, other):
+ return self._o2(other, operator.mod)
+
+ def __rmod__(self, other):
+ return self._r_o2(other, operator.mod)
+
+ def __divmod__(self, other):
+ return self._o2(other, operator.mod)
+
+ def __rdivmod__(self, other):
+ return self._r_o2(other, operator.mod)
+
+ # Power
+ def __pow__(self, other):
+ return self._o2(other, operator.pow)
+
+ def __rpow__(self, other):
+ return self._r_o2(other, operator.pow)
+
+ # Bitwise operators
+ def __lshift__(self, other):
+ return self._o2(other, operator.lshift)
+
+ def __rlshift__(self, other):
+ return self._r_o2(other, operator.lshift)
+
+ def __rshift__(self, other):
+ return self._o2(other, operator.rshift)
+
+ def __rrshift__(self, other):
+ return self._r_o2(other, operator.rshift)
+
+ def __and__(self, other):
+ return self._o2(other, operator.and_)
+ __rand__ = __and__
+
+ def __or__(self, other):
+ return self._o2(other, operator.or_)
+ __ror__ = __or__
+
+ def __xor__(self, other):
+ return self._o2(other, operator.xor)
+ __rxor__ = __xor__
+
+ # Unary operations
+ def __neg__(self):
+ return Vec2D(operator.neg(self.x), operator.neg(self.y))
+
+ def __pos__(self):
+ return Vec2D(operator.pos(self.x), operator.pos(self.y))
+
+ def __abs__(self):
+ return Vec2D(abs(self.x), abs(self.y))
+
+ def __invert__(self):
+ return Vec2D(-self.x, -self.y)
+
+
+class Death(Exception):
+ pass
+
+
+class World:
+ def __init__(self, width):
+ self.width = width
+ self.reset_rows()
+
+ def reset_rows(self):
+ width_range = range(self.width)
+ self.rows = [[Cell() for _ in width_range] for _ in width_range]
+
+ def update(self):
+ for y, row in enumerate(self.rows):
+ for x, cell in enumerate(row):
+ if not isinstance(cell.contents, Food):
+ self.rows[x][y] = Cell()
+
+ def __getitem__(self, key):
+ return self.rows[key]
+
+ def __setitem(self, key, value):
+ self.rows[key] = value
+
+ def __len__(self):
+ return self.width
+
+
+class Cell:
+ def __init__(self, contents=None):
+ if contents is not None and not isinstance(contents, WorldObject):
+ raise TypeError
+ self.contents = contents
+
+ def is_empty(self):
+ return self.contents is None
+
+
+class WorldObject:
+ coords = Vec2D(0, 0)
+
+
+class Food(WorldObject):
+ def __init__(self, energy=0):
+ self.energy = energy
+
+
+class PythonPart(WorldObject):
+ pass
+
+
+class PythonHead(PythonPart):
+ pass
+
+
+class Python:
+ LEFT = Vec2D(-1, 0)
+ RIGHT = Vec2D(1, 0)
+ UP = Vec2D(0, -1)
+ DOWN = Vec2D(0, 1)
+
+ def __init__(self, world, coords, size, direction):
+ self.world = world
+ self.coords = coords
+ self.size = size
+ self.direction = direction
+ self.energy = 0
+ self.build()
+
+ def build(self):
+ self.parts = []
+ for index in range(self.size):
+ if not index:
+ part = PythonHead()
+ part.coords = self.coords
+ else:
+ last_part = self.parts[-1]
+ part = PythonPart()
+ part.coords = last_part.coords - self.direction
+ self.parts.append(part)
+ self.update()
+
+ def update(self):
+ self.world.update()
+ for part in self.parts:
+ x = part.coords[0]
+ y = part.coords[1]
+ self.world[x][y].contents = part
+
+ def eat(self, food):
+ self.size += 1
+ self.parts.append(PythonPart())
+
+ def detect_collision(self):
+ head = self.parts[0]
+ new_coords = head.coords + self.direction
+ x = new_coords.x
+ y = new_coords.y
+ width = self.world.width
+ if x < 0 or y < 0 or x >= width or y >= width:
+ raise Death("You hit the border of the area!")
+ world_object = self.world[x][y].contents
+ if isinstance(world_object, Food):
+ self.eat(world_object)
+ if isinstance(world_object, PythonPart):
+ raise Death("Your Snake moved to another part if it.")
+
+ def move(self, direction):
+ if (direction * -1) == self.direction:
+ raise ValueError("Trying to move in opposite direction")
+
+ self.direction = direction
+ old_coords = copy.deepcopy([part.coords for part in self.parts])
+ for index, part in enumerate(self.parts):
+ if isinstance(part, PythonHead):
+ self.detect_collision()
+ self.parts[index].coords += direction
+ else:
+ self.parts[index].coords = old_coords[index-1]
+ self.update()