PyCodeBattler β

Pythonista 達の熱き闘いが,

今,始まる...!!

[2010/12/19 00:44:00] 登録

名前

クジンシー

ステータス

HP SP 攻撃力 集中力 防御力 素早さ
2038 31 101 64 12 7 2

必殺技

名前 タイプ レベル 消費 SP
ナイアガラバスター SingleAttackType 2 8
無想転生 SingleAttackType 4 33

コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  Copyright (C) 2010 by Atzm WATANABE <atzm@atzm.org>
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License (version 2) as
#  published by the Free Software Foundation.  It is distributed in the
#  hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
#  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#  PURPOSE.  See the GNU General Public License for more details.
#
# $Id: battle.py 71 2010-12-22 12:40:03Z atzm $
#

import os
import sys
import random
import pycodebattler


class DrawGame(Exception):
    pass


class BattleProto:
    HANDLER_COMMAND = 0

    def __init__(self, warriors, max_turn=sys.maxint - 1):
        self._warriors = warriors
        self._max_turn = max_turn
        self._handlers = {}

        self.register_handler(self.HANDLER_COMMAND,
                              self._handle_command_random)

    def winner(self):
        living = [w for w in self._warriors if not w.is_dead()]
        if not living:
            raise DrawGame()
        if len(living) == 1:
            return living[0]
        return None

    def loosers(self):
        return [w for w in self._warriors if w.is_dead()]

    def battle(self):
        for i in xrange(1, self._max_turn + 1):
            if self.winner():
                break
            yield self.turn()
        else:
            raise DrawGame()

    def turn(self):
        for attacker in self._sorted_by_agility():
            if attacker in self.loosers():
                continue

            targets = [w for w in self._warriors
                       if w not in self.loosers() + [attacker]]

            yield self._call_handler(self.HANDLER_COMMAND, attacker, targets)

            if self.winner():
                break

    def register_handler(self, id_, handler, *ext_args):
        self._handlers[id_] = (handler, ext_args)

    def _call_handler(self, id_, *args):
        handler, ext_args = self._handlers[id_]
        return handler(self, *(args + ext_args))

    def _sorted_by_agility(self):
        def cmp_agility(w1, w2):
            agi1 = w1.agility()
            agi2 = w2.agility()
            agi1 += random.randint(0 - agi1 / 8, agi1 / 8)
            agi2 += random.randint(0 - agi2 / 8, agi2 / 8)
            return agi2 - agi1
        return sorted(self._warriors, cmp=cmp_agility)

    @staticmethod
    def _handle_command_random(self, attacker, targets):
        target = random.choice(targets)

        try:
            skname = random.choice(attacker.skill_list())
        except IndexError:
            skname = None

        if attacker.can_invoke(skname) and random.randint(1, 10) > 8:
            sk = attacker.skill(skname)
            tt = sk.selectable(attacker, self._warriors)

            if sk.skilltype() is pycodebattler.skill.SuicideAttackType:
                damages = attacker.invoke(skname, tt, self._warriors)
                return attacker, skname, damages

            if tt:
                r = min([len(tt), sk.range(attacker)])
                t = random.sample(tt, random.randint(1, r))
                damages = attacker.invoke(skname, t, self._warriors)
                return attacker, skname, damages

        dmg, miss, crit = attacker.attack_to(target)
        return attacker, None, [(target, dmg, miss, crit)]


def _main_entry():
    from optparse import OptionParser

    parser = OptionParser(usage='%prog [options] file1 file2 ...')
    parser.add_option('-C', action='store_true', help='no color output')
    parser.add_option('-W', action='store_true', help='no wait per each turn')
    options, args = parser.parse_args()

    if len(args) <= 1:
        parser.print_help()
        return

    pycodebattler.util.set_color_enable(not options.C)

    skills = [pycodebattler.skill.Skill(*sk) for sk in [
        ['Chakra', 3, pycodebattler.skill.HealType, 1],
        ['Resurrection', 2, pycodebattler.skill.ResurrectionType, 1],
        ['Psychokinesis', 13, pycodebattler.skill.SingleAttackType, 2],
        ['Flame Radiation', 8, pycodebattler.skill.RangeAttackType, 1],
        ['Meltdown', 7, pycodebattler.skill.MultiAttackType, 1],
        ['Big Bang', 23, pycodebattler.skill.SuicideAttackType, 1],
    ]]
    players = [
        pycodebattler.warrior.Warrior(
            pycodebattler.util.path2name(f),
            open(f),
            random.sample(skills, random.randint(1, len(skills)))
        )
        for f in args
    ]
    proto = BattleProto(players)

    def print_warriors(warriors, all=False):
        print('Warriors:')
        print(pycodebattler.warrior.pformat(players))

        if not all:
            return

        for w in warriors:
            print("%s's skill:" % w)
            print(pycodebattler.skill.pformat(
                  [w.skill(n) for n in w.skill_list()]))

    def print_match_result(attacker, skname, damages):
        if skname:
            print("-> %s invokes %s!!!" %
                  (attacker, pycodebattler.util.cyan(skname)))
        else:
            print("-> %s's attack!" % attacker)

        if not damages:
            print('   but no effect...\n')
            return

        for victim, damage, miss, critical in damages:
            if critical:
                print('   %s!!!' % pycodebattler.util.red('CRITICAL'))
            if miss:
                print('   ...but %s!! %s got no damage!' %
                      (pycodebattler.util.green('MISS'), victim))
                continue

            if damage < 0:
                print('   %s is %s cured!' %
                      (victim, pycodebattler.util.green(0 - damage)))
            else:
                print('   %s got %s damage!' %
                      (victim, pycodebattler.util.yellow(damage)))

            if victim.is_dead():
                print(pycodebattler.util.red('   %s is DEAD...' % victim))

        print('')

    try:
        print_warriors(players, True)

        if not options.W:
            raw_input('> Hit enter key... ')
            print('')

        num_turn = 1
        for turn in proto.battle():
            print(pycodebattler.util.green(
                  '============= turn %d =============' % num_turn))

            for attacker, skname, damages in turn:
                print_match_result(attacker, skname, damages)

            print_warriors(players)
            num_turn += 1

            if not options.W:
                raw_input('> Hit enter key... ')
                print('')

        print('')
        print(pycodebattler.util.green(
              '>>> %s is WINNER!! <<<' % proto.winner()))

    except (KeyboardInterrupt, EOFError, DrawGame):
        print('\n')
        print(pycodebattler.util.green('>>> Draw Game! <<<'))

    print('')
    print_warriors(players)


if __name__ == '__main__':
    _main_entry()