1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 """An email interface for players.
20 from ..base import Player
22 class EmailPlayer (Player):
23 """Human Player with an email interface.
25 TODO: details on procmail setup
27 def __init__(self, name, address, return_address):
28 Player.__init__(self, name)
29 self.address = address
30 self.return_address = return_address
31 def _send_email(self, world, log, subject, body):
32 wpart = self._world_part(world)
33 lpart = self._world_part(log)
34 print 'Subject: %s\n\n%s\n' % (subject, body)
36 body = raw_input('response? ')
37 body = body.replace(r'\n', '\n')
38 if len(body) == 0 or body[-1] != '\n':
41 def _world_part(self, world):
43 def _log_part(self, log):
45 def report(self, world, log):
46 """Send reports about death and game endings.
48 These events mark the end of contact and require no change in
49 player status or response, so they get a special command
50 seperate from the usual action family. The action commands in
51 Player subclasses can notify the player (possibly by calling
52 report internally) if they feel so inclined.
56 draw - another notification-only method
58 self._send_email(world, log, 'Report', Player.report())
59 def draw(self, world, log, cards=[]):
60 """Only called if you earned a new card (or cards).
64 report - another notification-only method
66 Player.draw(self, world, log, cards)
68 body.extend([' %s' % c for c in cards])
69 body = ['Current Hand:']
71 if c.territory != None and c.territory.player == self:
72 body.append(' %s (owned)' % c)
74 body.append(' %s' % c)
75 self._send_email(world, log, 'Drawing cards', '\n'.join(body))
76 def select_territory(self, world, log):
77 """Return the selected territory's name.
80 'Reply with first line of the body of your email set',
81 'to the name (long or short, case insenitive) of the',
82 'territory you wish to occupy. Available territories',
84 for t in world.territories():
86 body.append(' %s' % t)
87 self._send_email(world, log, 'Select territory', '\n'.join(body))
88 body = self._get_email()
89 name = body.splitlines()[0].strip()
91 def play_cards(self, world, log, play_required=True):
92 """Decide whether or not to turn in a set of cards.
94 Return a list of cards to turn in or None. If play_required
95 is True, you *must* play.
97 possibles = list(self.hand.possible())
98 if len(possibles) == 0:
100 subject = 'Play cards'
101 if play_required == True:
102 subject += ' (required)'
104 'Reply with first line of the body of your email set',
105 'to the number of the set you wish to play (leave body',
106 'blank to pass). Available sets are:']
107 for i,h in enumerate(possibles):
108 body.append(' %d: %s' % (i, h))
109 self._send_email(world, log, subject, '\n'.join(body))
110 body = self._get_email()
111 text = body.splitlines()[0].strip()
114 return possibles[int(text)]
115 def place_armies(self, world, log, remaining=1, this_round=1):
116 """Both during setup and before each turn.
118 Return {territory_name: num_armies, ...}
120 subject = 'Place %d of %d armies' % (this_round, remaining)
122 'You can place %d armies this round (out of %d in'
123 % (this_round, remaining),
126 'Reply with first line(s) of the body of your email set',
127 'to "<number_of_armies> : <territory_name>" followed by',
128 'a blank line. For example',
133 'Your current disposition is:']
134 for t in self.territories(world):
135 body.append(' %d : %s' % (t.armies, t))
136 self._send_email(world, log, subject, '\n'.join(body))
137 body = self._get_email()
139 for line in body.splitlines():
143 armies,terr_name = [x.strip() for x in line.split(':')]
144 placements[terr_name] = int(armies)
146 def attack_and_fortify(self, world, log, mode='attack'):
147 """Return list of (source, target, armies) tuples. Place None
148 in the list to end this phase.
151 subject = 'Attack and fortify'
153 'You can attack as many times as you like, and fortify',
154 'once at the end of the round. Reply with first line(s)',
155 'of the body of your email set to',
156 ' "<source_name> : <target_name> : <number_of_armies>',
157 'When you are done attacking or in place of a',
158 'fortification, insert the line "Pass". For example',
171 assert mode == 'fortify', mode
174 'You can fortify once. Reply with first line of the',
175 'body of your email set to',
176 ' "<source_name> : <target_name> : <number_of_armies>',
177 'Or, if you choose to pass, either a blank line or',
178 '"Pass". For example',
184 self._send_email(world, log, subject, '\n'.join(body))
185 body = self._get_email()
186 if mode == 'fortify':
187 return [self._parse_attack_or_fortify_line(
188 body.splitlines()[0], mode)]
191 for line in body.splitlines():
192 action = self._parse_attack_or_fortify_line(line, mode)
197 actions.append(action)
199 def _parse_attack_or_fortify_line(self, line, mode):
201 if line.count(':') == 2:
202 fields = [x.strip() for x in line.split(':')]
203 fields[2] = int(fields[2])
205 elif line.lower() == 'pass' \
206 or (mode == 'fortify' and len(line) == 0):
208 def support_attack(self, world, log, source, target):
209 """Follow up on a conquest by moving additional armies.
211 subject = 'Support conquest of %s by %s' % (target, source)
213 'You can move up to %d of the %d armies remaining on'
214 % (source.armies - 1, source.armies),
215 '%s to %s following your conquest.'
218 'Reply with first line(s) of the body of your email set',
219 'to "<number_of_armies>", or leave the first line blank',
221 self._send_email(world, log, subject, '\n'.join(body))
222 body = self._get_email()
223 text = body.splitlines()[0].strip()