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

snake

view snake.py @ 115:4cafedd51b69

Added The Void Cell to represent everything outside of field, used in snake.Rule.applies
author Daniil Alexeyevsky <me.dendik@gmail.com>
date Mon, 20 Dec 2010 14:32:26 +0300
parents 7352863453bc
children 10d32d7755ff
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)
120 cell.snake = self.snake
121 if char in 'htb':
122 if is_my:
123 cell.snake_type = 'my'
124 else:
125 cell.snake_type = 'enemy'
126 if char == 'h':
127 assert (x, y) == (3, 3), "Own head must in the center of rule"
128 if (x, y) == (3, 3):
129 assert char == 'h', "In the center of rule must be own head"
130 cell.type = self.codes[char]
131 self.pattern[x, y] = cell
133 def applies (self, field, x, y):
134 """True if the rule applies in the field at position (x,y)."""
135 wall = engine.Cell(-1, -1)
136 wall.type = 'void'
138 for px, fx in zip(range(7), range(x - 3, x + 4)):
139 for py, fy in zip(range(7), range(y - 3, y + 4)):
140 if field.get((fx, fy), wall) != self.pattern[px, py]:
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: