Skip to content

Instantly share code, notes, and snippets.

@deontologician
Created August 6, 2017 09:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deontologician/c8851755669f463f97a9715dfae6eb62 to your computer and use it in GitHub Desktop.
Save deontologician/c8851755669f463f97a9715dfae6eb62 to your computer and use it in GitHub Desktop.
Bad RPG
import random
from collections import Counter
from pprint import pprint
import string
DAMAGE_TYPES = [
'fire',
'water',
'earth',
'air',
'plant',
'biological',
'crystal',
'acid',
'magma',
'divine',
'cursed',
'spirit',
'necro',
'living',
'mechanical',
'electrical',
'nuclear',
'quantum',
'bone',
'emotional',
'psychological',
]
MAX_HP = 300
def rand_name():
vowels = "aeiouy"
consonants = "".join(set(string.ascii_lowercase) - set(vowels))
name = ""
for i in range(0, random.randint(4, 6)):
if i % 2 == 0:
name += random.choice(consonants)
else:
name += random.choice(vowels)
return name.title()
def print_hist(hist, indent=4):
for type, dmg in hist.most_common():
print(' '*(indent-1), type, ':', dmg)
def make_dmg_table():
types = DAMAGE_TYPES[:]
random.shuffle(types)
table = {}
for t in types:
for i, x in enumerate(types):
if t == x:
table.setdefault(t, {})[x] = 0
elif i > len(types) // 2:
table.setdefault(t, {})[x] = -(random.randint(1, 4))
else:
table.setdefault(t, {})[x] = random.randint(1, 4)
return table
class Player:
def __init__(self):
self.reset_hp()
self.name = rand_name()
self.defend_hist = Counter({t: MAX_HP // 2 for t in DAMAGE_TYPES})
self.attack_hist = Counter({t: MAX_HP // 2 for t in DAMAGE_TYPES})
self.wins = 0
self.losses = 0
def reset_hp(self):
self.hp = MAX_HP
def attack(self):
return self._select(self.attack_hist)
def defend(self):
return self._select(self.defend_hist)
def attack_result(self, type, dmg):
self.attack_hist[type] = max(0, self.attack_hist[type] + dmg)
def defend_result(self, type, dmg):
self.defend_hist[type] = max(0, self.attack_hist[type] - dmg)
self.hp = min(self.hp + dmg, MAX_HP)
def alive(self):
return self.hp > 0
def _select(self, hist):
total = sum(hist.values())
stop = random.randint(0, total)
running_total = 0
for type, dmg in hist.items():
running_total += dmg
if running_total >= stop:
return type
class Game:
def __init__(self):
self.attacker = Player()
print('Player A is {a.name}'.format(a=self.attacker))
self.defender = Player()
print('Player B is {b.name}'.format(b=self.defender))
self.dmg_table = make_dmg_table()
self.round_num = 1
self.match_num = 1
def next_match(self):
self.attacker.reset_hp()
self.defender.reset_hp()
self.round_num = 1
self.match_num += 1
def play_round(self):
#print('\n== Round', self.round_num, '=>\n')
atck = self.attacker.attack()
dfnd = self.defender.defend()
b_dmg = self.dmg_table[atck][dfnd] * random.choice([1, 1, 1, 2, 2, 3])
self.attacker.attack_result(atck, b_dmg)
self.defender.defend_result(dfnd, b_dmg)
#self.describe_round(atck, dfnd, b_dmg)
self.round_num += 1
def do_match(self):
while True:
self.play_round()
if not self.defender.alive():
print(self.defender.name, 'died, so the match is over.')
break
else:
self.defender, self.attacker = self.attacker, self.defender
self.attacker.wins += 1
self.defender.losses += 1
self.summarize_match()
def summarize_match(self):
# defender has always lost when we summarize
print('Match {self.match_num} is over. After {self.round_num} rounds '
'{self.attacker.name} has killed {self.defender.name}'
.format(self=self))
def describe_round(self, atck, dfnd, b_dmg):
args = {
'a': self.attacker.name,
'b': self.defender.name,
'atck': atck.title(),
'dfnd': dfnd.title(),
'b_hp_b': self.defender.hp - b_dmg,
'disp': 'Luckily' if b_dmg >= 0 else 'Unfortunately',
'dir': 'increased' if b_dmg >= 0 else 'reduced',
'b_hp_a': self.defender.hp,
}
print('{a} attacked {b} with {atck}, {b} defended with {dfnd}.'.format(**args))
print('{disp}, this {dir} {b}\'s health from {b_hp_b} to {b_hp_a}'.format(**args))
def main():
game = Game()
for _ in range(10):
game.do_match()
game.next_match()
print(game.attacker.name, "'s histograms")
print("attacker")
print_hist(game.attacker.attack_hist)
print("defender")
print_hist(game.attacker.defend_hist)
print(game.defender.name, "'s histograms")
print("attacker")
print_hist(game.defender.attack_hist)
print("defender")
print_hist(game.defender.defend_hist)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment