Документ взят из кэша поисковой машины. Адрес оригинального документа : http://kodomo.fbb.msu.ru/hg/snake/raw-annotate/008be193a0a3/snake.py
Дата изменения: Unknown
Дата индексирования: Fri Feb 11 14:21:29 2011
Кодировка:

me@44: """Guts of snakes."""
me@44:
me@34: import engine
me@34:
me@34: def preprocess(line):
me@44: """Remove comments and junk spaces from line of snake definition file."""
me@34: if '//' in line:
me@34: line = line[:line.index('//')]
me@34: line = line.rstrip()
me@34: return line
martiran@30:
me@109: class File(object):
me@109: """Wrapper around file that saves the current line number."""
me@109: def __init__(self, file):
me@109: self.file = file
me@109: self.name = file.name
me@109: self.line_no = 0
me@120: self.iterator = self.enumerate_lines()
me@109: def __iter__(self):
me@120: return self.iterator
me@120: def enumerate_lines(self):
me@109: for line_no, line in enumerate(self.file, self.line_no):
me@109: self.line_no = line_no
me@109: yield line
me@109:
martiran@30: class Snake(object):
me@44: """Snakes.
me@44:
me@44: Attributes:
me@44:
me@44: - `cells` -- list of cells belonging to the snake The first of these cells
me@44: becomes head, the last one becomes tail, the rest ar body. If snake has
me@44: only one cell, it is tail.
me@44: - `color` -- color of snake
me@44: - `rules` -- a list of Rule objects
me@44: """
me@44:
martiran@32: def __init__ (self, cells, color):
martiran@32: self.cells = cells
martiran@32: self.color = color
martiran@32: self.rules = []
me@34:
me@34: def load (self, file):
me@44: """Load snake description from file.
me@44:
me@44: See program design docs for file syntax.
me@44: """
me@109: file = File(file)
me@109: try:
me@109: self._load(file)
me@109: except Exception, e:
me@109: raise Exception("%s:%s: %s" % (file.name, file.line_no, e))
me@109:
me@109: def _load (self, file):
me@109: """Actually do the loading."""
me@65: for line in file:
me@88: magic, self.name = preprocess(line).split(' ', 1)
me@65: break
me@34: assert magic == "snake", "This is not snake file"
me@65: for line in file:
me@65: line = preprocess(line)
me@34: if line == 'end':
me@34: break
me@34: assert line == '', "Rules must be separated by empty lines"
me@51: self.rules.append(Rule(self).load(file))
me@139: for number, rule in enumerate(self.rules):
me@139: rule.number = number
me@34:
martiran@30: def fill (self):
me@44: """Mark every cell in `self.cells` as belonging to self."""
martiran@32: for cell in self.cells:
martiran@32: cell.snake = self
me@129: if self.cells == []:
me@129: return
martiran@111: for cell in self.cells:
martiran@111: cell.type = 'body'
Alex@75: self.cells[0].type = 'head'
Alex@75: self.cells[-1].type = 'tail'
me@34:
martiran@30: class Rule(object):
me@44: """Rule defining possible behaviour of snake."""
me@34:
me@34: codes = {
me@34: 'h': 'head',
me@34: 'b': 'body',
me@34: 't': 'tail',
me@34: '#': 'wall',
me@34: ' ': 'any',
me@34: '-': 'empty',
me@34: }
me@34:
martiran@32: def __init__ (self, snake):
martiran@32: self.snake = snake
me@80: self.direction = (0, -1)
me@34: self.pattern = {}
me@34:
me@34: def load (self, file):
me@70: """Load rule definition from file.
me@70:
me@70: Ignore any leading empty lines.
me@70: Return self.
me@70: """
me@34: y = 0
me@34: for line in file:
me@34: line = preprocess(line)
me@34: if y == 0 and line == '':
me@34: continue
me@41: assert len(line) == 8, "Rule lines must be exactly 7 chars long"
me@34: assert line[-1] == ';', "Rule lines must end with semicolon"
me@63: for x, char in enumerate(line[:7]):
me@34: self.parse_cell(x, y, char)
me@34: y += 1
me@68: if y == 7:
me@68: break
me@70: return self
me@34:
me@34: def parse_cell(self, x, y, char):
me@44: """Parse definition of cell in rule file.
me@44:
me@44: Cell is defined by one character.
me@44: """
me@73: is_my = char.islower()
me@73: char = char.lower()
me@73: assert char in self.codes, "Illegal symbol in rule: %s" % char
me@115: cell = engine.Cell(x, y)
me@115: cell.snake = self.snake
me@124: cell.snake_type = None
me@34: if char in 'htb':
me@73: if is_my:
me@51: cell.snake_type = 'my'
me@34: else:
me@51: cell.snake_type = 'enemy'
me@37: if char == 'h':
me@37: assert (x, y) == (3, 3), "Own head must in the center of rule"
me@37: if (x, y) == (3, 3):
me@37: assert char == 'h', "In the center of rule must be own head"
me@73: cell.type = self.codes[char]
me@34: self.pattern[x, y] = cell
me@34:
martiran@32: def applies (self, field, x, y):
me@44: """True if the rule applies in the field at position (x,y)."""
me@115: wall = engine.Cell(-1, -1)
me@115: wall.type = 'void'
me@115:
me@38: for px, fx in zip(range(7), range(x - 3, x + 4)):
me@38: for py, fy in zip(range(7), range(y - 3, y + 4)):
me@115: if field.get((fx, fy), wall) != self.pattern[px, py]:
me@115: return False
me@38: return True
me@34:
me@104: def rotate (self, direction):
me@104: """Rotate rule pattern to head in `direction`."""
me@104: for i in range(4):
me@104: if self.direction == direction:
me@104: return
me@39: self.rotate_ccw()
me@104: raise AssertionError("Illegal direction: %s" % direction)
me@39:
me@39: def rotate_ccw(self):
me@44: """Rotate rule pattern one time counterclockwise."""
me@39: pattern = {}
me@39: for x in range(7):
me@39: for y in range(7):
me@39: pattern[y, 6 - x] = self.pattern[x, y]
me@39: self.pattern = pattern
me@39: x, y = self.direction
me@39: self.direction = y, -x
me@34:
me@34: # vim: set ts=4 sts=4 sw=4 et: