Skip to content

Instantly share code, notes, and snippets.

@prakol16
Created March 26, 2017 19:15
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 prakol16/f0a306efd63a977a95c034b4b6e00ef1 to your computer and use it in GitHub Desktop.
Save prakol16/f0a306efd63a977a95c034b4b6e00ef1 to your computer and use it in GitHub Desktop.
For codegolf
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.5.1+ (/usr/bin/python3.5)" project-jdk-type="Python SDK" />
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Darwin.iml" filepath="$PROJECT_DIR$/.idea/Darwin.iml" />
</modules>
</component>
</project>
import random
DEFENSE_CONSTANT = 25
MIN_DAMAGE = 0.25
# Just for fun
# Generated at http://listofrandomnames.com/index.cfm
names = ["Ashanti","Jeanett","Charlyn","Micki","Dell","Dacia","Jenni","Cristi","Ethelene","Geraldine","Johnny",
"Arianna","Orville","Jarrett","Ute","Candis","Rhona","Beth","Hilaria","Ava","Kamala","Louetta","Twila",
"Kristle","Adrianne","Ouida","Gregorio","Kenna","David","Nona","Marshall","Melany","Berna","Vivienne",
"Genevieve","Jewel","Jennell","Sharell","Shelba","Darrell","Deedra","Belia","Betsey","Kimberely","Eveline",
"Erin","Allyson","Angele","Cordelia","Kacie"]
class Damager:
def __init__(self, starting_health=1.0, defense=0.0, attack=0.0):
self.health = starting_health
self.starting_health = self.health
self.defense = defense
self.attack = attack
def get_stats(self):
return [self.health, self.defense, self.attack]
def get_hit(self, damage):
self.health -= max(damage * (1 - self.defense / DEFENSE_CONSTANT), MIN_DAMAGE * damage)
return self.health <= 0
def hit(self, other):
return other.get_hit(self.attack)
class Enemy(Damager):
ids = 0
def __init__(self, blur=0, reproduction=1, **kwargs):
mutated_kwargs = {}
self.mutation_variation = 0.3
caps = {"starting_health": 1.0, "attack": 0, "defense": 0}
for key in caps:
mutated_kwargs[key] = self.mutate_stat(kwargs[key] if key in kwargs else caps[key], cap=caps[key])
assert "attack" in mutated_kwargs
super().__init__(**mutated_kwargs)
self.reproduction = self.mutate_stat(reproduction, cap=1.0)
self.blur = self.mutate_stat(blur, cap=0.0)
self.name = random.choice(names)
self.enemy_id = Enemy.ids
self.steps_survived = 0
Enemy.ids += 1
def blur_stat(self, x):
return max(x - random.random() * self.blur, 0)
def mutate_stat(self, x, cap):
return max(x + random.normalvariate(0, self.mutation_variation), cap)
def combine_stat(self, x, y):
return (x + y) / 2
def get_stats(self):
stats = super().get_stats()
stats.append(self.reproduction)
return list(map(self.blur_stat, stats))
def can_reproduce(self, num_enemies):
return random.random() < self.reproduction / num_enemies
def choose_mate(self, all_enemies, total_attack):
r = random.random() * total_attack
for e in all_enemies:
r -= e.attack
if r <= 0:
return e
return random.choice(all_enemies)
def reproduce_with(self, other):
return Enemy(starting_health=self.combine_stat(self.starting_health, other.starting_health),
defense=self.combine_stat(self.defense, other.defense),
attack=self.combine_stat(self.attack, other.attack),
blur=self.combine_stat(self.blur, other.blur),
reproduction=self.combine_stat(self.blur, other.blur))
def __str__(self):
return "Enemy {id} {name} stats=[health={:.2f}, defense={:.2f}," \
"attack={:.2f}, blur={blur:.2f}, repr={reproduction:.2f}]".format(
*super().get_stats(), id=self.enemy_id, name=self.name, blur=self.blur, reproduction=self.reproduction)
INITIAL_STATS = 10
STARTING_ENEMIES = 5
class Player(Damager):
def __init__(self, attack=10, defense=0, regeneration=0):
super().__init__(starting_health=100, attack=attack, defense=defense)
self.min_health = 100
self.regeneration = regeneration
if attack + defense + regeneration > INITIAL_STATS:
raise ValueError("Sum of stats is bigger than {}".format(INITIAL_STATS))
def get_attack(self, enemies, round_num, nuke_recharge):
print("\nRound num: {}; Nuke recharge {}\n".format(round_num, nuke_recharge))
for ind, stat in enumerate(enemies):
print("Enemy {} with h {:.2f} d {:.2f} a {:.2f} r {:.2f}".format(ind, *stat))
return list(map(int, input("What indices to attack? ").split()))
def restore(self):
if self.health < self.min_health:
self.min_health = self.health
self.health = self.starting_health
def get_health(self):
return self.health
def regenerate(self):
self.health += self.regeneration
if self.health > self.starting_health:
self.health = self.starting_health
NUKE_RECHARGE_TIME = 10
ENEMIES_HIT_PER_TURN = 3
class Controller:
def __init__(self, logger=print, pclass=Player):
self.player = pclass()
self.logger = logger
self.enemies_defeated = 0
self.rounds = 0
self.nuke_recharge = 0
self.round_stats = {"starting_health": 0, "attack": 0, "defense": 0, "reproduction": 0, "blur": 0}
self.enemies = [Enemy() for _ in range(STARTING_ENEMIES)]
self.round_num_enemies = 0
def kill_enemy(self, e):
self.round_stats["starting_health"] += e.starting_health * e.steps_survived
self.round_stats["attack"] += e.attack * e.steps_survived
self.round_stats["defense"] += e.defense * e.steps_survived
self.round_stats["reproduction"] += e.reproduction * e.steps_survived
self.round_stats["blur"] += e.blur * e.steps_survived
self.round_num_enemies += e.steps_survived
def attack_enemies(self, enemy_indices):
to_die = []
for enemy_ind in enemy_indices:
enemy_ind %= len(self.enemies)
self.logger("Player chose to attack " + str(self.enemies[enemy_ind]))
if self.player.hit(self.enemies[enemy_ind]):
# Enemy killed, remove it
self.enemies_defeated += 1
self.logger("Enemy killed! Total # of enemies defeated: " + str(self.enemies_defeated))
to_die.append(enemy_ind)
self.kill_enemy(self.enemies[enemy_ind])
self.enemies[:] = [enemy for (ind, enemy) in enumerate(self.enemies) if ind not in to_die]
def run_step(self):
for enemy in self.enemies:
self.logger(str(enemy) + " hit player")
enemy.steps_survived += 1
if enemy.hit(self.player):
self.logger("Player died!")
return True
self.logger("Player has {:.2f} health left".format(self.player.get_health()))
enemy_stats = list(map(Enemy.get_stats, self.enemies))
enemy_indices = self.player.get_attack(enemy_stats, self.rounds, self.nuke_recharge)
if len(enemy_indices) == ENEMIES_HIT_PER_TURN:
self.attack_enemies(enemy_indices)
elif self.nuke_recharge <= 0:
self.logger("Player chose to NUKE!")
self.attack_enemies(list(range(len(self.enemies))))
self.nuke_recharge = NUKE_RECHARGE_TIME
else:
self.logger("Player tried to nuke, but still needs to wait {} turn(s)".format(self.nuke_recharge))
if len(self.enemies) == 0:
self.rounds += 1
self.logger("All enemies killed. Total # of rounds completed: " + str(self.rounds))
self.player.restore()
self.create_enemies()
else:
self.reproduce_all()
random.shuffle(self.enemies)
self.nuke_recharge = max(0, self.nuke_recharge - 1)
self.player.regenerate()
self.logger("Regenerating, player has {} health left".format(self.player.health))
self.logger("\n")
return False
def create_enemies(self):
average_round_stats = {}
for key in self.round_stats:
average_round_stats[key] = self.round_stats[key] / self.round_num_enemies
self.round_stats[key] = 0
self.round_num_enemies = 0
for _ in range(self.get_round_enemies()):
self.enemies.append(Enemy(**average_round_stats))
def get_round_enemies(self):
return STARTING_ENEMIES * (self.rounds + 1)
def reproduce_all(self):
babies = []
total_attack = sum(map(lambda x: x.attack, self.enemies))
for enemy in self.enemies:
if enemy.can_reproduce(len(self.enemies)):
other = enemy.choose_mate(self.enemies, total_attack)
baby = enemy.reproduce_with(other)
if enemy == other:
self.logger(str(enemy) + " reproduced to create " + str(baby))
else:
self.logger(str(enemy) + " and " + str(other) + " reproduced to create " + str(baby))
babies.append(baby)
self.enemies.extend(babies)
class ExamplePlayer(Player):
def __init__(self):
super().__init__(attack=3, defense=0, regeneration=7)
def get_attack(self, enemies, round_num, nuke_recharge):
if self.get_health() < 50 and nuke_recharge == 0:
return [0] # Nuke it!
return [0, 1, 2]
def noop(*args, **kwargs):
pass
if __name__ == "__main__":
c = Controller(logger=print, pclass=ExamplePlayer) # Change Player to ExamplePlayer to run example player
while True:
if c.run_step():
break
print("\n\n\n")
print("Survived {} rounds".format(c.rounds))
print("Minimum health {}".format(c.player.min_health))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment