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

snake

view snake.py @ 109:7352863453bc

snake.*.load now reports the line number of error
author Daniil Alexeyevsky <me.dendik@gmail.com>
date Mon, 20 Dec 2010 12:50:42 +0300
parents c68b54a43501
children 2d048c0ed5e3 4cafedd51b69
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 def __iter__(self):
19 for line_no, line in enumerate(self.file, self.line_no):
20 self.line_no = line_no
21 yield line
23 class Snake(object):
24 """Snakes.
26 Attributes:
28 - `cells` -- list of cells belonging to the snake The first of these cells
29 becomes head, the last one becomes tail, the rest ar body. If snake has
30 only one cell, it is tail.
31 - `color` -- color of snake
32 - `rules` -- a list of Rule objects
33 """
35 def __init__ (self, cells, color):
36 self.cells = cells
37 self.color = color
38 self.rules = []
40 def load (self, file):
41 """Load snake description from file.
43 See program design docs for file syntax.
44 """
45 file = File(file)
46 try:
47 self._load(file)
48 except Exception, e:
49 raise Exception("%s:%s: %s" % (file.name, file.line_no, e))
51 def _load (self, file):
52 """Actually do the loading."""
53 for line in file:
54 magic, self.name = preprocess(line).split(' ', 1)
55 break
56 assert magic == "snake", "This is not snake file"
57 for line in file:
58 line = preprocess(line)
59 if line == 'end':
60 break
61 assert line == '', "Rules must be separated by empty lines"
62 self.rules.append(Rule(self).load(file))
64 def fill (self):
65 """Mark every cell in `self.cells` as belonging to self."""
66 for cell in self.cells:
67 cell.snake = self
68 self.cells[0].type = 'head'
69 for cell in self.cells[1:-1]:
70 cell.type = 'body'
71 self.cells[-1].type = 'tail'
72 return
74 class Rule(object):
75 """Rule defining possible behaviour of snake."""
77 codes = {
78 'h': 'head',
79 'b': 'body',
80 't': 'tail',
81 '#': 'wall',
82 ' ': 'any',
83 '-': 'empty',
84 }
86 def __init__ (self, snake):
87 self.snake = snake
88 self.direction = (0, -1)
89 self.pattern = {}
91 def load (self, file):
92 """Load rule definition from file.
94 Ignore any leading empty lines.
95 Return self.
96 """
97 y = 0
98 for line in file:
99 line = preprocess(line)
100 if y == 0 and line == '':
101 continue
102 assert len(line) == 8, "Rule lines must be exactly 7 chars long"
103 assert line[-1] == ';', "Rule lines must end with semicolon"
104 for x, char in enumerate(line[:7]):
105 self.parse_cell(x, y, char)
106 y += 1
107 if y == 7:
108 break
109 return self
111 def parse_cell(self, x, y, char):
112 """Parse definition of cell in rule file.
114 Cell is defined by one character.
115 """
116 is_my = char.islower()
117 char = char.lower()
118 assert char in self.codes, "Illegal symbol in rule: %s" % char
119 cell = engine.Cell(x, y, self.snake)
120 if char in 'htb':
121 if is_my:
122 cell.snake_type = 'my'
123 else:
124 cell.snake_type = 'enemy'
125 if char == 'h':
126 assert (x, y) == (3, 3), "Own head must in the center of rule"
127 if (x, y) == (3, 3):
128 assert char == 'h', "In the center of rule must be own head"
129 cell.type = self.codes[char]
130 self.pattern[x, y] = cell
132 def applies (self, field, x, y):
133 """True if the rule applies in the field at position (x,y)."""
134 for px, fx in zip(range(7), range(x - 3, x + 4)):
135 for py, fy in zip(range(7), range(y - 3, y + 4)):
136 if (fx, fy) in field:
137 if field[fx, fy] != self.pattern[px, py]:
138 return False
139 else:
140 if self.pattern[px, py].type != 'any':
141 return False
142 return True
144 def rotate (self, direction):
145 """Rotate rule pattern to head in `direction`."""
146 for i in range(4):
147 if self.direction == direction:
148 return
149 self.rotate_ccw()
150 raise AssertionError("Illegal direction: %s" % direction)
152 def rotate_ccw(self):
153 """Rotate rule pattern one time counterclockwise."""
154 pattern = {}
155 for x in range(7):
156 for y in range(7):
157 pattern[y, 6 - x] = self.pattern[x, y]
158 self.pattern = pattern
159 x, y = self.direction
160 self.direction = y, -x
162 # vim: set ts=4 sts=4 sw=4 et: