Skip to content

Instantly share code, notes, and snippets.

@leehosung
Last active January 4, 2021 08:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leehosung/f784d9efc71dce12855739647dd98877 to your computer and use it in GitHub Desktop.
Save leehosung/f784d9efc71dce12855739647dd98877 to your computer and use it in GitHub Desktop.
PyCon Korea 2017 - dodo fighter
import json
import sys
import random
# 도도 νŒŒμ΄ν„°μ— μ°Έκ°€ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ—μ΄μ „νŠΈλ₯Ό λ§Œλ“€μ–΄μ„œ μ œμΆœν•΄ μ£Όμ…”μ•Ό ν•©λ‹ˆλ‹€.
# μ—μ΄μ „νŠΈλŠ” μ‚¬μš©μžκ°€ μž‘μ„±ν•˜λŠ” 인곡지λŠ₯ μ½”λ“œλ‘œμ„œ, μ£Όμ–΄μ§€λŠ” ν˜„μž¬ κ²Œμž„ μƒνƒœλ₯Ό λ°”νƒ•μœΌλ‘œ
# μ–΄λ–€ μ•‘μ…˜μ„ 취할지λ₯Ό κ²°μ •ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.
#
# μ•‘μ…˜ μ„€λͺ…
# - idle - 아무것도 ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
# - forward - μ•žμœΌλ‘œ μ›€μ§μž…λ‹ˆλ‹€. μƒλŒ€κ°€ λ°”λ‘œ μ•žμ— μžˆμ„ 경우 더 움직이지 μ•ŠμŠ΅λ‹ˆλ‹€.
# - backward - λ’€λ‘œ μ›€μ§μž…λ‹ˆλ‹€. 처음 μ‹œμž‘μ§€μ μ—μ„œ μ„ΈμΉΈ 이상 λ’€λ‘œ 갈 수 μ—†μŠ΅λ‹ˆλ‹€.
# - punch - 상단을 κ³΅κ²©ν•©λ‹ˆλ‹€.
# - kick - ν•˜λ‹¨μ„ κ³΅κ²©ν•©λ‹ˆλ‹€.
# - crouch - 상단 곡격을 ν”Όν•©λ‹ˆλ‹€.
# - jump - ν•˜λ‹¨ 곡격을 ν”Όν•©λ‹ˆλ‹€.
# - guard - 곡격을 λ°©μ–΄ν•©λ‹ˆλ‹€. μƒν•˜λ‹¨ λͺ¨λ‘ λ°©μ–΄ν•  수 μžˆμ§€λ§Œ μ•½κ°„μ˜ 데미지λ₯Ό μž…μŠ΅λ‹ˆλ‹€.
#
# μƒνƒœ μ„€λͺ…
# - distance - μƒλŒ€λ°©κ³Ό λ‚˜μ™€μ˜ 거리. 0일 κ²½μš°μ—λ§Œ 곡격이 κ°€λŠ₯ν•©λ‹ˆλ‹€.
# - time_left - 남은 μ‹œκ°„
# - health - λ‚˜μ˜ 체λ ₯
# - opponent_health - μƒλŒ€μ˜ 체λ ₯
# - opponent_action - μ§€λ‚œ ν„΄μ—μ„œ μƒλŒ€μ˜ μ•‘μ…˜
# - given_damage - 직전 μ•‘μ…˜μ—μ„œ λ‚΄κ°€ μƒλŒ€λ°©μ—κ²Œ κ°€ν•œ 데미지
# - taken_damage - 직전 μ•‘μ…˜μ—μ„œ μƒλŒ€λ°©μ΄ λ‚˜μ—κ²Œ κ°€ν•œ 데미지
# - match_records - μ§€κΈˆκΉŒμ§€μ˜ κ²½κΈ° 기둝. 리슀트 ν˜•μ‹μž…λ‹ˆλ‹€.
# 예λ₯Ό λ“€μ–΄ [None, True, False]인 경우, 첫번째 κ²½κΈ°λŠ” λ¬΄μŠΉλΆ€,
# λ‘λ²ˆμ§Έ κ²½κΈ°λŠ” 당신이, μ„Έλ²ˆμ§Έ κ²½κΈ°λŠ” μƒλŒ€λ°©μ΄ μ΄κ²Όλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.
#
# μ£Όμ˜μ‚¬ν•­
# - 같은 μ•‘μ…˜μ„ 계속 λ°˜λ³΅ν•˜μ§€ λ§ˆμ„Έμš”. 곡격λ ₯이 ν•˜λ½λ˜λŠ” νŽ˜λ„ν‹°κ°€ μžˆμŠ΅λ‹ˆλ‹€.
# - μƒλŒ€μ˜ 곡격을 νšŒν”Όν•˜κ±°λ‚˜ λ§‰λŠ”λ° μ„±κ³΅ν•˜λ©΄ λ‹€μŒ κ³΅κ²©μ—μ„œ 곡격λ ₯ λ³΄λ„ˆμŠ€κ°€ μžˆμŠ΅λ‹ˆλ‹€.
# - ν•œ ν„΄ λ‚΄μ—μ„œλŠ” 이동과 λ°©μ–΄ λ™μž‘μ΄ 곡격 λ™μž‘λ³΄λ‹€ μš°μ„ ν•©λ‹ˆλ‹€.
# 즉, P1이 곡격을 ν•˜κ³  P2κ°€ μ΄λ™ν•œλ‹€λ©΄ P2κ°€ μ΄λ™ν•˜λŠ” μ•‘μ…˜μ„ μš°μ„  ν‰κ°€ν•©λ‹ˆλ‹€.
# - μ‚¬μš©ν•  수 μžˆλŠ” λͺ¨λ“ˆμ€ random, json, sys, math둜 ν•œμ •λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
# - 슀크립트 μ‹€ν–‰ μ‹œκ°„μ΄ 3초λ₯Ό λ„˜μ–΄κ°€λ©΄ νƒˆλ½ μ²˜λ¦¬λ©λ‹ˆλ‹€.
last_action = 'idle'
attack_actions = ['punch', 'kick']
defence_actions = ['crouch', 'jump', 'guard']
available_backsteps = 3
accumulated_given_damage = 0
accumulated_taken_damage = 0
def action(what):
global last_action
if what not in ('idle', 'forward', 'backward', 'punch', 'kick',
'crouch', 'jump', 'guard'):
raise ValueError(f'Unknown action type: {what}')
last_action = what
sys.stdout.write(what + '\n')
sys.stdout.flush()
def read_status():
data = sys.stdin.readline()
while data:
yield json.loads(data)
data = sys.stdin.readline()
def attack():
"""곡격"""
action(random.choice(attack_actions))
def defence():
"""방어와 νšŒν”Ό
λ°©μ–΄μ˜ μ΅œμ„ μ€ λ§žμ§€ μ•ŠλŠ” κ²ƒμž…λ‹ˆλ‹€. λ’€λ‘œ λ„λ§κ°ˆ 수 있으면 λ„λ§κ°‘λ‹ˆλ‹€.
더 이상 λ„λ§κ°ˆ 곳이 μ—†μœΌλ©΄ 랜덀으둜 ν”Όν•˜κ±°λ‚˜ λ§‰μŠ΅λ‹ˆλ‹€.
"""
global available_backsteps
if available_backsteps > 0:
available_backsteps -= 1
action('backward')
else:
action(random.choice(defence_actions))
def success_defence(taken_damage, opponent_action):
"""방어에 성곡 ν–ˆλŠ”κ°€?
거리가 0 μΌλ•Œ, λ‹€μŒ 3가지 κ²½μš°λŠ” 방어에 μ„±κ³΅ν•œ κ²ƒμž…λ‹ˆλ‹€.
- λ°©μ–΄(guard)λ₯Ό μ„ νƒν–ˆλŠ”λ° 데미지λ₯Ό μž…μ€ 경우
- μƒλ‹¨νšŒν”Ό(crouch)λ₯Ό μ„ νƒν–ˆλŠ”λ° μƒλŒ€λ°©μ΄ 상단곡격(punch)을 ν•œ 경우
- ν•˜λ‹¨νšŒν”Ό(jump)λ₯Ό μ„ νƒν–ˆλŠ”λ° μƒλŒ€λ°©μ΄ ν•˜λ‹¨κ³΅κ²©(kick)을 ν•œ 경우
방어에 μ„±κ³΅ν•˜λ©΄ 곡격λ ₯ λ³΄λ„ˆμŠ€λ₯Ό λ°›μŠ΅λ‹ˆλ‹€. 곡격!
:param taken_damage: λ‚΄κ°€ μž…μ€ 데미지
:param opponent_action: μƒλŒ€λ°©μ΄ μ„ νƒν•œ λ™μž‘
:return:
bool: 방어에 성곡 ν–ˆμœΌλ©΄ True, 방어에 μ‹€νŒ¨ ν–ˆμœΌλ©΄ False
"""
return (taken_damage > 0 and last_action == 'guard') or \
(last_action == 'crouch' and opponent_action == 'punch') or \
(last_action == 'jump' and opponent_action == 'kick')
def fail_attack(given_damage, opponent_action):
"""곡격에 μ‹€νŒ¨ν–ˆλŠ”κ°€? 즉, μƒλŒ€λ°©μ΄ λ°©μ–΄,νšŒν”Όμ— 성곡 ν–ˆλŠ”κ°€?
거리가 0일 λ–„, λ‹€μŒ 3가지 κ²½μš°λŠ” μƒλŒ€λ°©μ΄ 방어에 μ„±κ³΅ν•œ κ²ƒμž…λ‹ˆλ‹€.
- 곡격을 μ„ νƒν–ˆλŠ”λ° μƒλŒ€νŽΈμ΄ λ°©μ–΄(guard)λ₯Ό μ„ νƒν•œ 경우
- 곡격을 μ„ νƒν–ˆλŠ”λ° μƒλŒ€νŽΈμ΄ 데미지λ₯Ό μž…μ§€ μ•Šμ€ 경우, 즉 상,ν•˜λ‹¨μ„ λ§žμΆ°μ„œ ν”Όν•œ 경우
μƒλŒ€λ°©μ΄ 곡격λ ₯ λ³΄λ„ˆμŠ€λ₯Ό λ°›μŠ΅λ‹ˆλ‹€. λ„λ§κ°€κ±°λ‚˜ λ°©μ–΄λ₯Ό ν•©μ‹œλ‹€.
:param given_damage: μƒλŒ€λ°©μ΄ λ§žμ€ 데미지
:param opponent_action: μƒλŒ€λ°©μ΄ μ„ νƒν•œ λ™μž‘
:return:
bool: 곡격에 μ‹€νŒ¨ ν–ˆμœΌλ©΄ True, 곡격에 성곡 ν–ˆμœΌλ©΄ False
"""
return last_action in attack_actions and (given_damage == 0 or opponent_action == 'guard')
def do_random_action(health, opponent_health):
"""랜덀 행동을 ν•©λ‹ˆλ‹€.
자리λ₯Ό μ΄λ™ν•˜μ§€ μ•Šκ³  곡격성에 λ”°λΌμ„œ 랜덀 행동을 ν•©λ‹ˆλ‹€. 지고 μžˆμ„ 수둝 적극적으둜 곡격을 ν•΄μ„œ 역전을 λ…Έλ €μ•Ό ν•©λ‹ˆλ‹€.
곡격성은 "μƒλŒ€λ°©μ˜ 체λ ₯/(μƒλŒ€λ°©μ˜ 체λ ₯ + λ‚˜μ˜ 체λ ₯)" 으둜 μ •μ˜ν•©λ‹ˆλ‹€. μ–‘μͺ½μ˜ 체λ ₯이 같을 λ•Œμ—λŠ” 곡격과 λ°©μ–΄λ₯Ό 선택할 ν™•λ₯ μ΄ κ°™μŠ΅λ‹ˆλ‹€.
:param health: λ‚˜μ˜ 체λ ₯
:param opponent_health: μƒλŒ€λ°©μ˜ 체λ ₯
"""
aggressivity = opponent_health * 1.0 / (opponent_health + health)
random_action = random.choices([attack, defence], weights=[aggressivity, 1 - aggressivity])[0]
random_action()
for status in read_status():
distance = status['distance']
time_left = status['time_left']
health = status['health']
opponent_health = status['opponent_health']
opponent_action = status['opponent_action']
given_damage = status['given_damage']
taken_damage = status['taken_damage']
match_records = status['match_records']
accumulated_given_damage += given_damage
accumulated_taken_damage += taken_damage
# 거리가 2칸이면 닀가가도 λ§žμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•œ 걸음 λ‹€κ°€κ°‘λ‹ˆλ‹€. λ‚˜μ€‘μ— λ„λ§κ°ˆ μ—¬μœ λ₯Ό λ§Œλ“€μ–΄ λ‘‘λ‹ˆλ‹€.
if distance >= 2:
action('forward')
available_backsteps += 1
# 거리가 1칸이면 λ‹€κ°€κ°€λ©΄ λ§žμŠ΅λ‹ˆλ‹€. μƒλŒ€λ°©μ΄ λ‹€κ°€μ˜¬μ§€ λͺ¨λ₯΄λ‹ˆ 곡격을 ν•©μ‹œλ‹€.
elif distance == 1:
# μ„œλ‘œκ°€ μ‹Έμš΄μ μ΄ 있으면 닀가가지 μ•ŠμŠ΅λ‹ˆλ‹€. ν•œλ²ˆλ„ μ‹Έμš°μ§€ μ•Šμ€ κ²½μš°μ—λŠ” κ°€λ§Œνžˆ μžˆλŠ” 더미 μ—μ΄μ „νŠΈλ₯Ό 이기기 μœ„ν•΄μ„œ 5초λ₯Ό 남기고 λ‹€κ°€κ°‘λ‹ˆλ‹€.
if accumulated_given_damage == 0 and accumulated_taken_damage == 0 and time_left < 5:
action('forward')
# μƒλŒ€λ°©μ΄ λ‹€κ°€μ˜€μ§€ μ•ŠμœΌλ©΄ ν—ˆκ³΅μ— 계속 주먹질, λ°œκΈΈμ§ˆμ„ ν•˜κ³  μžˆμ„ κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€.
# 같은 λ™μž‘μ„ μ—°μ†μœΌλ‘œ ν•˜λ©΄ νŒ¨λ„ν‹°κ°€ μžˆμŠ΅λ‹ˆλ‹€. 주먹질, λ°œκΈΈμ§ˆμ„ λ²ˆκ°ˆμ•„ κ°€λ©΄μ„œ ν•©μ‹œλ‹€.
elif last_action == 'punch':
action('kick')
elif last_action == 'kick':
action('punch')
# 아무 κ³΅κ²©μ΄λ‚˜ ν•©μ‹œλ‹€.
else:
attack()
# 거리가 0μΉΈ μž…λ‹ˆλ‹€.
else:
# 방어에 μ„±κ³΅ν–ˆλ‹€λ©΄ 곡격λ ₯ λ³΄λ„ˆμŠ€κ°€ μƒκΉλ‹ˆλ‹€. κ³΅κ²©ν•©μ‹œλ‹€.
if success_defence(taken_damage, opponent_action):
attack()
# 곡격에 μ‹€νŒ¨ν–ˆλ‹€λ©΄ μƒλŒ€λ°©μ΄ 곡격λ ₯ λ³΄λ„ˆμŠ€κ°€ μƒκΉλ‹ˆλ‹€. λ„λ§κ°€κ±°λ‚˜ λ§‰μμ‹œλ‹€.
elif fail_attack(given_damage, opponent_action):
defence()
# μ–‘μͺ½λ‹€ λ³΄λ„ˆμŠ€κ°€ μ—†λŠ” 상황이라면 λžœλ€ν–‰λ™μ„ ν•©λ‹ˆλ‹€.
else:
do_random_action(health, opponent_health)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment