Skip to content

Instantly share code, notes, and snippets.

@ijp
Last active May 17, 2020 16:25
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 ijp/ef0bada930217416f5ff715007e0444e to your computer and use it in GitHub Desktop.
Save ijp/ef0bada930217416f5ff715007e0444e to your computer and use it in GitHub Desktop.
Road to Yokozuna - Slohyo prototype
class StdioLogger(object):
def log(self, msg):
print(msg)
class NullLogger(object):
def log(self, msg):
pass
# Discord logger, Coloured logger, etc.
class Commentator(object):
def __init__(self, logger=StdioLogger):
self.logger = logger()
def log(self, msg):
self.logger.log(msg)
def announce_wrestlers(self, east, west):
# FIXME: probably unnecessary
self.announce_wrestler("east", east)
self.announce_wrestler("west", west)
def announce_wrestler(self, side, wrestler):
self.log(f"On the {side}~~~ {wrestler.shikona}")
def new_round(self):
self.log("---")
def attempt_move(self, rikishi, move, roll):
self.log(f"{rikishi.shikona} attempting {move.name} rolls {roll}")
def matta(self):
self.log("Matta!")
def mono_ii(self):
self.log("The judges have called for a mono-ii")
def gunbai_dori(self, attacker, defender):
self.log(f"Gyoji gunbai dori. The victory goes to {attacker.shikona}")
def gunbai_sashichigae(self, attacker, defender):
# FIXME: better name
self.log(f"Gyoji gunbai sashichigae. The decision is reversed, and {defender.shikona} is awarded the victory")
def torinaoshi(self, attacker, defender):
self.log("Torinaoshi. We're going to have a playoff")
def successful_tachiai(self, attacker, move):
self.log(f"{attacker.shikona} has the advantage...transitioning to {move.transition}")
def successful_defense(self, defender, defense):
self.log(f"A great defense by {defender.shikona} and the momentum is now in their favour")
self.log(f"They transition to {defense.transition}")
def announce_victor(self, attacker):
self.log(f"Yes, a great victory for {attacker.shikona}")
def match_over(self, attacker):
self.log(f"It looks like {attacker.shikona} has succeeded")
from rikishi import Rikishi
from slohyo import Game
import argparse
import json
parser = argparse.ArgumentParser(description="Run a slohyo")
parser.add_argument('east_file', help="JSON file for east wrestler")
parser.add_argument('west_file', help="JSON file for west wrestler")
args = parser.parse_args()
def wrestler_from_file(filename):
with open(filename) as fp:
j = json.load(fp)
return Rikishi.from_slohyo_form(j)
east = wrestler_from_file(args.east_file)
west = wrestler_from_file(args.west_file)
g = Game(east, west)
g.run()
from techniques import tachiai, kimarite, defense
class Rikishi(object):
def __init__(self, shikona, base_die, power, balance, footwork, skill, spirit, strategy):
self.shikona = shikona
self.base_die = base_die
self.power = power
self.balance = balance
self.footwork = footwork
self.skill = skill
self.spirit = spirit
self.strategy = strategy
def tachiai(self):
name, transition = self.strategy["tachiai"]
return tachiai(self, name, transition)
def offensive_technique(self, state):
return kimarite(self, self.strategy[state]["offense"])
def defensive_technique(self, state):
name, transition = self.strategy[state]["defense"]
return defense(self, name, transition)
@staticmethod
def from_slohyo_form(slohyo_form):
shikona = slohyo_form["shikona"]
base_die = slohyo_form["base_die"]
power = slohyo_form["power"]
balance = slohyo_form["balance"]
footwork = slohyo_form["footwork"]
skill = slohyo_form["skill"]
spirit = slohyo_form["spirit"]
states = ['tachiai', 'grip', 'push', 'pull', 'rear', 'throw']
strategy = {k: slohyo_form[k] for k in states}
return Rikishi(shikona, base_die, power, balance, footwork, skill, spirit, strategy)
def validate_strategy(self):
pass
{
"shikona": "chiyochiyochiyo",
"base_die": 20,
"power": 3,
"balance": 4,
"footwork": 3,
"skill": 4,
"spirit": 5,
"tachiai": ["powerful charge", "grip"],
"grip": {
"offense": "yorikiri",
"defense": ["makekai", "grip"]
},
"push": {
"offense": null,
"defense": ["makekai", "grip"]
},
"pull": {
"offense": "hikiotoshi",
"defense": ["sidestep", "pull"]
},
"rear": {
"offense": null,
"defense": ["makekai", "grip"]
},
"throw": {
"offense": null,
"defense": ["sidestep", "pull"]
}
}
{
"shikona": "wakawakawaka",
"base_die": 20,
"power": 4,
"balance": 3,
"footwork": 3,
"skill": 5,
"spirit": 4,
"tachiai": ["low", "pull"],
"grip" : {
"offense": null,
"defense": ["tawara ballet", "throw"]
},
"push" : {
"offense": null,
"defense": ["sidestep", "pull"]
},
"pull" : {
"offense": "hatakikomi",
"defense": ["tawara ballet", "throw"]
},
"rear" : {
"offense": null,
"defense": ["sidestep", "pull"]
},
"throw" : {
"offense": "kotenage",
"defense": ["sidestep", "pull"]
}
}
from commentator import Commentator
import random
MATTA_THRESHOLD = 2
MONO_II_THRESHOLD = 2
# game_states = ["tachiai", "grip", "pull", "throw", "lock", "push", "defense", "DONE"]
# Possible states: make sure they match slohyo terms, maybe use: yotsu, pull, nagete, limblock, oshi
class Game(object):
def __init__(self, east, west, commentator=Commentator):
self.east = east
self.west = west
self.attacker = self.defender = None
self.c = commentator()
def run(self):
self.state = "tachiai"
self.pre_bout()
self.tachiai()
while self.state != "DONE":
self.do_round()
def pre_bout(self):
self.c.announce_wrestlers(self.east, self.west)
self.c.new_round()
def tachiai(self):
east_move = self.east.tachiai()
west_move = self.west.tachiai()
east_roll = east_move.roll(west_move)
west_roll = west_move.roll(east_move)
self.c.attempt_move(self.east, east_move, east_roll)
self.c.attempt_move(self.west, west_move, west_roll)
if abs(east_roll - west_roll) <= MATTA_THRESHOLD:
self.c.matta()
self.state = "DONE"
elif east_roll > west_roll:
self.c.successful_tachiai(self.east, east_move)
self.state = east_move.transition
self.attacker = self.east
self.defender = self.west
else:
self.c.successful_tachiai(self.west, west_move)
self.state = west_move.transition
self.attacker = self.west
self.defender = self.east
def do_round(self):
self.c.new_round()
attack = self.attacker.offensive_technique(self.state)
defense = self.defender.defensive_technique(self.state)
atk_roll = attack.roll(defense)
def_roll = defense.roll(attack)
self.c.attempt_move(self.attacker, attack, atk_roll)
self.c.attempt_move(self.defender, defense, def_roll)
if atk_roll >= def_roll:
self.c.match_over(self.attacker)
if atk_roll <= def_roll + MONO_II_THRESHOLD:
self.c.mono_ii()
roll = random.randint(1, 10)
if roll <= 7:
self.c.gunbai_dori(self.attacker, self.defender)
elif roll >= 9:
self.c.gunbai_sashichigae(self.attacker, self.defender)
else:
self.c.torinaoshi(self.attacker, self.defender)
else:
self.c.announce_victor(self.attacker)
self.state = "DONE"
else:
self.c.successful_defense(self.defender, defense)
self.state = defense.transition
self.attacker, self.defender = self.defender, self.attacker
import random
class Technique(object):
def __init__(self, name, state, stats, counters):
self.name = name
self.state = state
self.stats = stats
self.counter_list = counters
def counters(self, other):
return other.name in self.counter_list
techniques = {}
def add_technique(name, state, stats, counters):
techniques[name] = Technique(name, state, stats, counters)
add_technique("powerful charge", "tachiai", ["power", "balance"], ["reserved"])
# FIXME: transition to grip, throw
add_technique("reserved", "tachiai", ["footwork", "spirit"], ["low"])
# FIXME: transition to lock, push
add_technique("low", "tachiai", ["power", "skill"], ["surprise"])
# FIXME: transition to grip, pull
add_technique("surprise", "tachiai", ["balance", "spirit"], ["lateral"])
# FIXME: transition to throw, push
add_technique("lateral", "tachiai", ["footwork", "skill"], ["powerful charge"])
# FIXME: transition to lock, pull
add_technique("yorikiri", "grip", ["power", "balance"], ["sidestep"]) # Y1
add_technique("shitatenage", "grip", ["footwork", "balance"], ["makekai"]) # Y2
add_technique("harimanage", "grip", ["power", "spirit"], ["tawara ballet"]) # Y3
add_technique("uwatenage", "grip", ["power", "skill"], ["momentum stop"]) # Y4
add_technique("hatakikomi", "pull", ["skill", "spirit"], ["defensive tsuppari"]) # P1
add_technique("hikiotoshi", "pull", ["footwork", "skill"], ["sidestep"]) # P2
add_technique("uwatedashinage", "pull", ["balance", "skill"], ["makekai"]) # P3
add_technique("tsukiotoshi", "pull", ["power", "spirit"], ["tawara ballet"]) # P4
add_technique("kotenage", "throw", ["power", "balance"], ["momentum stop"]) # N1
add_technique("sukuinage", "throw", ["footwork", "balance"], ["sidestep"]) # N2
add_technique("kubinage", "throw", ["skill", "balance"], ["defensive tsuppari"]) # N3
add_technique("okurinage", "throw", ["skill", "spirit"], ["makekai"]) # N4
add_technique("ashitori", "lock", ["footwork", "spirit"], ["momentum stop"]) # L1
add_technique("kimedashi", "lock", ["footwork", "power"], ["tawara ballet"]) # L2
add_technique("sotogake", "lock", ["footwork", "skill"], ["defensive tsuppari"]) # L3
add_technique("katasukashi", "lock", ["balance", "spirit"], ["sidestep"]) # L4
add_technique("oshidashi", "push", ["balance", "spirit"], ["makekai"]) # O1
add_technique("okuridashi", "push", ["power", "skill"], ["tawara ballet"]) # O2
add_technique("tsukidashi", "push", ["footwork", "power"], ["momentum stop"]) # O3
add_technique("waridashi", "push", ["footwork", "spirit"], ["defensive tsuppari"]) # O4
add_technique("sidestep", "defense", ["skill", "spirit"], ["shitatenage", "uwatedashinage", "kubinage", "ashitori"]) # D1
# FIXME: transition to pull, push
add_technique("makekai", "defense", ["power", "footwork"], ["harimanage", "tsukiotoshi", "kotenage", "okuridashi"]) # D2
# FIXME: transition to grip, lock
add_technique("tawara ballet", "defense", ["balance", "footwork"], ["uwatenage", "hatakikomi", "sotogake", "tsukidashi"]) # D3
# FIXME: transition to throw, lock
add_technique("momentum stop", "defense", ["balance", "skill"], ["yorikiri", "sukuinage", "kimedashi", "waridashi"]) # D4
# FIXME: transition to throw, pull
add_technique("defensive tsuppari", "defense", ["power", "spirit"], ["hikiotoshi", "okurinage", "katasukashi", "oshidashi"]) # D5
# FIXME: transition to grip, push
class Move(object):
def __init__(self, rikishi, technique, offensive_advantage=False, transition=False):
self.rikishi = rikishi
self.technique = technique
self.name = technique.name
self.offensive_advantage = offensive_advantage
self.transition = transition
def roll(self, opponent_move):
die_size = self.rikishi.base_die
if self.offensive_advantage:
die_size += 2
die_size += self.stat_advantage(opponent_move)
total = 0
counter = self.counters(opponent_move)
for i in range(5):
roll = random.randint(1, die_size)
if counter:
roll = max(roll, 7)
total += roll
return total
def stat_advantage(self, opponent_move):
sdiff = self.lookup_stats() - opponent_move.lookup_stats()
if 1 <= sdiff <= 4:
return 1
elif 5 <= sdiff <= 9:
return 2
elif 10 <= sdiff:
return 3
else:
return 0
def counters(self, opponent_move):
return self.technique.counters(opponent_move.technique)
def lookup_stats(self):
stat1, stat2 = self.technique.stats
return getattr(self.rikishi, stat1) + getattr(self.rikishi, stat2)
def tachiai(rikishi, name, transition):
m = techniques.get(name)
return Move(rikishi, m, transition=transition)
def kimarite(rikishi, name):
m = techniques.get(name)
return Move(rikishi, m, offensive_advantage=True)
def defense(rikishi, name, transition):
m = techniques.get(name)
return Move(rikishi, m, transition=transition)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment