1 """An email interface for players.
4 from ..base import Player
6 class EmailPlayer (Player):
7 """Human Player with an email interface.
9 TODO: details on procmail setup
11 def __init__(self, name, address, return_address):
12 Player.__init__(self, name)
13 self.address = address
14 self.return_address = return_address
15 def _send_email(self, world, log, subject, body):
16 wpart = self._world_part(world)
17 lpart = self._world_part(log)
18 print 'Subject: %s\n\n%s\n' % (subject, body)
20 body = raw_input('response? ')
21 body = body.replace(r'\n', '\n')
22 if len(body) == 0 or body[-1] != '\n':
25 def _world_part(self, world):
27 def _log_part(self, log):
29 def report(self, world, log):
30 """Send reports about death and game endings.
32 These events mark the end of contact and require no change in
33 player status or response, so they get a special command
34 seperate from the usual action family. The action commands in
35 Player subclasses can notify the player (possibly by calling
36 report internally) if they feel so inclined.
40 draw - another notification-only method
42 self._send_email(world, log, 'Report', Player.report())
43 def draw(self, world, log, cards=[]):
44 """Only called if you earned a new card (or cards).
48 report - another notification-only method
50 Player.draw(self, world, log, cards)
52 body.extend([' %s' % c for c in cards])
53 body = ['Current Hand:']
55 if c.territory != None and c.territory.player == self:
56 body.append(' %s (owned)' % c)
58 body.append(' %s' % c)
59 self._send_email(world, log, 'Drawing cards', '\n'.join(body))
60 def select_territory(self, world, log):
61 """Return the selected territory's name.
64 'Reply with first line of the body of your email set',
65 'to the name (long or short, case insenitive) of the',
66 'territory you wish to occupy. Available territories',
68 for t in world.territories():
70 body.append(' %s' % t)
71 self._send_email(world, log, 'Select territory', '\n'.join(body))
72 body = self._get_email()
73 name = body.splitlines()[0].strip()
75 def play_cards(self, world, log, play_required=True):
76 """Decide whether or not to turn in a set of cards.
78 Return a list of cards to turn in or None. If play_required
79 is True, you *must* play.
81 possibles = list(self.hand.possible())
82 if len(possibles) == 0:
84 subject = 'Play cards'
85 if play_required == True:
86 subject += ' (required)'
88 'Reply with first line of the body of your email set',
89 'to the number of the set you wish to play (leave body',
90 'blank to pass). Available sets are:']
91 for i,h in enumerate(possibles):
92 body.append(' %d: %s' % (i, h))
93 self._send_email(world, log, subject, '\n'.join(body))
94 body = self._get_email()
95 text = body.splitlines()[0].strip()
98 return possibles[int(text)]
99 def place_armies(self, world, log, remaining=1, this_round=1):
100 """Both during setup and before each turn.
102 Return {territory_name: num_armies, ...}
104 subject = 'Place %d of %d armies' % (this_round, remaining)
106 'You can place %d armies this round (out of %d in'
107 % (this_round, remaining),
110 'Reply with first line(s) of the body of your email set',
111 'to "<number_of_armies> : <territory_name>" followed by',
112 'a blank line. For example',
117 'Your current disposition is:']
118 for t in self.territories(world):
119 body.append(' %d : %s' % (t.armies, t))
120 self._send_email(world, log, subject, '\n'.join(body))
121 body = self._get_email()
123 for line in body.splitlines():
127 armies,terr_name = [x.strip() for x in line.split(':')]
128 placements[terr_name] = int(armies)
130 def attack_and_fortify(self, world, log, mode='attack'):
131 """Return list of (source, target, armies) tuples. Place None
132 in the list to end this phase.
135 subject = 'Attack and fortify'
137 'You can attack as many times as you like, and fortify',
138 'once at the end of the round. Reply with first line(s)',
139 'of the body of your email set to',
140 ' "<source_name> : <target_name> : <number_of_armies>',
141 'When you are done attacking or in place of a',
142 'fortification, insert the line "Pass". For example',
155 assert mode == 'fortify', mode
158 'You can fortify once. Reply with first line of the',
159 'body of your email set to',
160 ' "<source_name> : <target_name> : <number_of_armies>',
161 'Or, if you choose to pass, either a blank line or',
162 '"Pass". For example',
168 self._send_email(world, log, subject, '\n'.join(body))
169 body = self._get_email()
170 if mode == 'fortify':
171 return [self._parse_attack_or_fortify_line(
172 body.splitlines()[0], mode)]
175 for line in body.splitlines():
176 action = self._parse_attack_or_fortify_line(line, mode)
181 actions.append(action)
183 def _parse_attack_or_fortify_line(self, line, mode):
185 if line.count(':') == 2:
186 fields = [x.strip() for x in line.split(':')]
187 fields[2] = int(fields[2])
189 elif line.lower() == 'pass' \
190 or (mode == 'fortify' and len(line) == 0):
192 def support_attack(self, world, log, source, target):
193 """Follow up on a conquest by moving additional armies.
195 subject = 'Support conquest of %s by %s' % (target, source)
197 'You can move up to %d of the %d armies remaining on'
198 % (source.armies - 1, source.armies),
199 '%s to %s following your conquest.'
202 'Reply with first line(s) of the body of your email set',
203 'to "<number_of_armies>", or leave the first line blank',
205 self._send_email(world, log, subject, '\n'.join(body))
206 body = self._get_email()
207 text = body.splitlines()[0].strip()