source: pycodebattler/trunk/pycodebattler/battle.py @ 45

Revision 45, 6.3 KB checked in by atzm, 13 years ago (diff)

add pycodebattler

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: d51d6cbc0b293385b0dccb6e8ed3bd1e15b285dc $
4
5import os
6import sys
7import random
8import pycodebattler
9
10
11class DrawGame(Exception):
12    pass
13
14
15class BattleProto:
16    HANDLER_COMMAND = 0
17
18    def __init__(self, warriors, max_turn=sys.maxint - 1):
19        self._warriors = warriors
20        self._max_turn = max_turn
21        self._handlers = {}
22
23        self.register_handler(self.HANDLER_COMMAND,
24                              self._handle_command_random)
25
26    def winner(self):
27        living = [w for w in self._warriors if not w.is_dead()]
28        if not living:
29            raise DrawGame()
30        if len(living) == 1:
31            return living[0]
32        return None
33
34    def loosers(self):
35        return [w for w in self._warriors if w.is_dead()]
36
37    def battle(self):
38        for i in xrange(1, self._max_turn + 1):
39            if self.winner():
40                break
41            yield self.turn()
42        else:
43            raise DrawGame()
44
45    def turn(self):
46        for attacker in self._sorted_by_agility():
47            if attacker in self.loosers():
48                continue
49
50            targets = [w for w in self._warriors
51                       if w not in self.loosers() + [attacker]]
52
53            yield self._call_handler(self.HANDLER_COMMAND, attacker, targets)
54
55            if self.winner():
56                break
57
58    def register_handler(self, id_, handler, *ext_args):
59        self._handlers[id_] = (handler, ext_args)
60
61    def _call_handler(self, id_, *args):
62        handler, ext_args = self._handlers[id_]
63        return handler(self, *(args + ext_args))
64
65    def _sorted_by_agility(self):
66        def cmp_agility(w1, w2):
67            agi1 = w1.agility()
68            agi2 = w2.agility()
69            agi1 += random.randint(0 - agi1 / 8, agi1 / 8)
70            agi2 += random.randint(0 - agi2 / 8, agi2 / 8)
71            return agi2 - agi1
72        return sorted(self._warriors, cmp=cmp_agility)
73
74    @staticmethod
75    def _handle_command_random(self, attacker, targets):
76        target = random.choice(targets)
77
78        try:
79            skname = random.choice(attacker.skill_list())
80        except IndexError:
81            skname = None
82
83        if attacker.can_invoke(skname) and random.randint(1, 10) > 8:
84            sk = attacker.skill(skname)
85            tt = sk.selectable(attacker, self._warriors)
86
87            if sk.skilltype() == 'SuicideAttackType':
88                damages = attacker.invoke(skname, tt, self._warriors)
89                return attacker, skname, damages
90
91            if tt:
92                r = min([len(tt), sk.range(attacker)])
93                t = random.sample(tt, random.randint(1, r))
94                damages = attacker.invoke(skname, t, self._warriors)
95                return attacker, skname, damages
96
97        dmg, miss, crit = attacker.attack_to(target)
98        return attacker, None, [(target, dmg, miss, crit)]
99
100
101def _main_entry():
102    from optparse import OptionParser
103
104    parser = OptionParser(usage='%prog [options] file1 file2 ...')
105    parser.add_option('-C', action='store_true', help='no color output')
106    parser.add_option('-W', action='store_true', help='no wait per each turn')
107    options, args = parser.parse_args()
108
109    if len(args) <= 1:
110        parser.print_help()
111        return
112
113    pycodebattler.util.set_color_enable(not options.C)
114
115    skills = [pycodebattler.skill.Skill(*sk) for sk in [
116        ['Chakra', 3, pycodebattler.skill.HealType, 1],
117        ['Resurrection', 2, pycodebattler.skill.ResurrectionType, 1],
118        ['Psychokinesis', 13, pycodebattler.skill.SingleAttackType, 2],
119        ['Flame Radiation', 8, pycodebattler.skill.RangeAttackType, 1],
120        ['Meltdown', 7, pycodebattler.skill.MultiAttackType, 1],
121        ['Big Bang', 23, pycodebattler.skill.SuicideAttackType, 1],
122    ]]
123    players = [
124        pycodebattler.warrior.Warrior(
125            pycodebattler.util.path2name(f),
126            open(f),
127            random.sample(skills, random.randint(1, len(skills)))
128        )
129        for f in args
130    ]
131    proto = BattleProto(players)
132
133    def print_warriors(warriors, all=False):
134        print('Warriors:')
135        print(pycodebattler.warrior.pformat(players))
136
137        if not all:
138            return
139
140        for w in warriors:
141            print("%s's skill:" % w)
142            print(pycodebattler.skill.pformat(
143                  [w.skill(n) for n in w.skill_list()]))
144
145    def print_match_result(attacker, skname, damages):
146        if skname:
147            print("-> %s invokes %s!!!" %
148                  (attacker, pycodebattler.util.cyan(skname)))
149        else:
150            print("-> %s's attack!" % attacker)
151
152        if not damages:
153            print('   but no effect...\n')
154            return
155
156        for victim, damage, miss, critical in damages:
157            if critical:
158                print('   %s!!!' % pycodebattler.util.red('CRITICAL'))
159            if miss:
160                print('   ...but %s!! %s got no damage!' %
161                      (pycodebattler.util.green('MISS'), victim))
162                continue
163
164            if damage < 0:
165                print('   %s is %s cured!' %
166                      (victim, pycodebattler.util.green(0 - damage)))
167            else:
168                print('   %s got %s damage!' %
169                      (victim, pycodebattler.util.yellow(damage)))
170
171            if victim.is_dead():
172                print(pycodebattler.util.red('   %s is DEAD...' % victim))
173
174        print('')
175
176    try:
177        print_warriors(players, True)
178
179        if not options.W:
180            raw_input('> Hit enter key... ')
181            print('')
182
183        num_turn = 1
184        for turn in proto.battle():
185            print(pycodebattler.util.green(
186                  '============= turn %d =============' % num_turn))
187
188            for attacker, skname, damages in turn:
189                print_match_result(attacker, skname, damages)
190
191            print_warriors(players)
192            num_turn += 1
193
194            if not options.W:
195                raw_input('> Hit enter key... ')
196                print('')
197
198        print('')
199        print(pycodebattler.util.green(
200              '>>> %s is WINNER!! <<<' % proto.winner()))
201
202    except (KeyboardInterrupt, EOFError, DrawGame):
203        print('\n')
204        print(pycodebattler.util.green('>>> Draw Game! <<<'))
205
206    print('')
207    print_warriors(players)
208
209
210if __name__ == '__main__':
211    _main_entry()
Note: See TracBrowser for help on using the repository browser.