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

snake

view snake.py @ 169:4eec473f445b

added button work explanation in documentation.
author Alex Martynov
date Thu, 23 Dec 2010 20:37:13 +0300
parents cfe29cb793eb
children
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))
66 for number, rule in enumerate(self.rules):
67 rule.number = number
69 def fill (self):
70 """Mark every cell in `self.cells` as belonging to self."""
71 for cell in self.cells:
72 cell.snake = self
73 if self.cells == []:
74 return
75 for cell in self.cells:
76 cell.type = 'body'
77 self.cells[0].type = 'head'
78 self.cells[-1].type = 'tail'
80 class Rule(object):
81 """Rule defining possible behaviour of snake."""
83 codes = {
84 'h': 'head',
85 'b': 'body',
86 't': 'tail',
87 '#': 'wall',
88 ' ': 'any',
89 '-': 'empty',
90 }
92 def __init__ (self, snake):
93 self.snake = snake
94 self.direction = (0, -1)
95 self.pattern = {}
97 def load (self, file):
98 """Load rule definition from file.
100 Ignore any leading empty lines.
101 Return self.
102 """
103 y = 0
104 for line in file:
105 line = preprocess(line)
106 if y == 0 and line == '':
107 continue
108 assert len(line) == 8, "Rule lines must be exactly 7 chars long"
109 assert line[-1] == ';', "Rule lines must end with semicolon"
110 for x, char in enumerate(line[:7]):
111 self.parse_cell(x, y, char)
112 y += 1
113 if y == 7:
114 break
115 return self
117 def parse_cell(self, x, y, char):
118 """Parse definition of cell in rule file.
120 Cell is defined by one character.
121 """
122 is_my = char.islower()
123 char = char.lower()
124 assert char in self.codes, "Illegal symbol in rule: %s" % char
125 cell = engine.Cell(x, y)
126 cell.snake = self.snake
127 cell.snake_type = None
128 if char in 'htb':
129 if is_my:
130 cell.snake_type = 'my'
131 else:
132 cell.snake_type = 'enemy'
133 if char == 'h':
134 assert (x, y) == (3, 3), "Own head must in the center of rule"
135 if (x, y) == (3, 3):
136 assert char == 'h', "In the center of rule must be own head"
137 cell.type = self.codes[char]
138 self.pattern[x, y] = cell
140 def applies (self, field, x, y):
141 """True if the rule applies in the field at position (x,y)."""
142 wall = engine.Cell(-1, -1)
143 wall.type = 'void'
145 for px, fx in zip(range(7), range(x - 3, x + 4)):
146 for py, fy in zip(range(7), range(y - 3, y + 4)):
147 if field.get((fx, fy), wall) != self.pattern[px, py]:
148 return False
149 return True
151 def rotate (self, direction):
152 """Rotate rule pattern to head in `direction`."""
153 for i in range(4):
154 if self.direction == direction:
155 return
156 self.rotate_ccw()
157 raise AssertionError("Illegal direction: %s" % direction)
159 def rotate_ccw(self):
160 """Rotate rule pattern one time counterclockwise."""
161 pattern = {}
162 for x in range(7):
163 for y in range(7):
164 pattern[y, 6 - x] = self.pattern[x, y]
165 self.pattern = pattern
166 x, y = self.direction
167 self.direction = y, -x
169 # vim: set ts=4 sts=4 sw=4 et: