Документ взят из кэша поисковой машины. Адрес оригинального документа : http://kodomo.fbb.msu.ru/hg/snake/file/8b332ca44e25/snake.py
Дата изменения: Unknown
Дата индексирования: Sun Feb 3 08:31:39 2013
Кодировка:
snake: 8b332ca44e25 snake.py

snake

view snake.py @ 127:8b332ca44e25

save changes
author Alex Martynov <martiran@kodomo.fbb.msu.ru>
date Mon, 20 Dec 2010 15:50:05 +0300
parents 10d32d7755ff
children bc310be50e73
line source
1 """Guts of snakes."""
3 import engine
5 def preprocess(line):
6 """Remove comments and junk spaces from line of snake definition file."""
7 if '//' in line:
8 line = line[:line.index('//')]
9 line = line.rstrip()
10 return line
12 class File(object):
13 """Wrapper around file that saves the current line number."""
14 def __init__(self, file):
15 self.file = file
16 self.name = file.name
17 self.line_no = 0
18 self.iterator = self.enumerate_lines()
19 def __iter__(self):
20 return self.iterator
21 def enumerate_lines(self):
22 for line_no, line in enumerate(self.file, self.line_no):
23 self.line_no = line_no
24 yield line
26 class Snake(object):
27 """Snakes.
29 Attributes:
31 - `cells` -- list of cells belonging to the snake The first of these cells
32 becomes head, the last one becomes tail, the rest ar body. If snake has
33 only one cell, it is tail.
34 - `color` -- color of snake
35 - `rules` -- a list of Rule objects
36 """
38 def __init__ (self, cells, color):
39 self.cells = cells
40 self.color = color
41 self.rules = []
43 def load (self, file):
44 """Load snake description from file.
46 See program design docs for file syntax.
47 """
48 file = File(file)
49 try:
50 self._load(file)
51 except Exception, e:
52 raise Exception("%s:%s: %s" % (file.name, file.line_no, e))
54 def _load (self, file):
55 """Actually do the loading."""
56 for line in file:
57 magic, self.name = preprocess(line).split(' ', 1)
58 break
59 assert magic == "snake", "This is not snake file"
60 for line in file:
61 line = preprocess(line)
62 if line == 'end':
63 break
64 assert line == '', "Rules must be separated by empty lines"
65 self.rules.append(Rule(self).load(file))
67 def fill (self):
68 """Mark every cell in `self.cells` as belonging to self."""
69 for cell in self.cells:
70 cell.snake = self
71 for cell in self.cells:
72 cell.type = 'body'
73 self.cells[0].type = 'head'
74 self.cells[-1].type = 'tail'
75 return
77 class Rule(object):
78 """Rule defining possible behaviour of snake."""
80 codes = {
81 'h': 'head',
82 'b': 'body',
83 't': 'tail',
84 '#': 'wall',
85 ' ': 'any',
86 '-': 'empty',
87 }
89 def __init__ (self, snake):
90 self.snake = snake
91 self.direction = (0, -1)
92 self.pattern = {}
94 def load (self, file):
95 """Load rule definition from file.
97 Ignore any leading empty lines.
98 Return self.
99 """
100 y = 0
101 for line in file:
102 line = preprocess(line)
103 if y == 0 and line == '':
104 continue
105 assert len(line) == 8, "Rule lines must be exactly 7 chars long"
106 assert line[-1] == ';', "Rule lines must end with semicolon"
107 for x, char in enumerate(line[:7]):
108 self.parse_cell(x, y, char)
109 y += 1
110 if y == 7:
111 break
112 return self
114 def parse_cell(self, x, y, char):
115 """Parse definition of cell in rule file.
117 Cell is defined by one character.
118 """
119 is_my = char.islower()
120 char = char.lower()
121 assert char in self.codes, "Illegal symbol in rule: %s" % char
122 cell = engine.Cell(x, y)
123 cell.snake = self.snake
124 if char in 'htb':
125 if is_my:
126 cell.snake_type = 'my'
127 else:
128 cell.snake_type = 'enemy'
129 if char == 'h':
130 assert (x, y) == (3, 3), "Own head must in the center of rule"
131 if (x, y) == (3, 3):
132 assert char == 'h', "In the center of rule must be own head"
133 cell.type = self.codes[char]
134 self.pattern[x, y] = cell
136 def applies (self, field, x, y):
137 """True if the rule applies in the field at position (x,y)."""
138 wall = engine.Cell(-1, -1)
139 wall.type = 'void'
141 for px, fx in zip(range(7), range(x - 3, x + 4)):
142 for py, fy in zip(range(7), range(y - 3, y + 4)):
143 if field.get((fx, fy), wall) != self.pattern[px, py]:
144 return False
145 return True
147 def rotate (self, direction):
148 """Rotate rule pattern to head in `direction`."""
149 for i in range(4):
150 if self.direction == direction:
151 return
152 self.rotate_ccw()
153 raise AssertionError("Illegal direction: %s" % direction)
155 def rotate_ccw(self):
156 """Rotate rule pattern one time counterclockwise."""
157 pattern = {}
158 for x in range(7):
159 for y in range(7):
160 pattern[y, 6 - x] = self.pattern[x, y]
161 self.pattern = pattern
162 x, y = self.direction
163 self.direction = y, -x
165 # vim: set ts=4 sts=4 sw=4 et: