Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Last active December 7, 2019 07:55
Show Gist options
  • Save shiracamus/d7a5b39aa4408b2ecbf06807f6befb8f to your computer and use it in GitHub Desktop.
Save shiracamus/d7a5b39aa4408b2ecbf06807f6befb8f to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
import curses
import locale
from random import randint
INSTRUCTION = """\
Maneaters Ver 1.3
Mission : マンイーターを消して生き残れ!
O -- Maneater, 段階的に追い詰める敵
# -- Rock, 触るとマンイーターや自分が死ぬ
@ -- Player, コントロールしてマンイーターを岩に当て、
生き残れ!"
Key control: Tenkey:
7 8 9 7 8 9
↖ ↑ ↗ ↖ ↑ ↗
u← i→o 4← 5→ 6
↙ ↓ ↘ ↙ ↓ ↘
j k l 1 2 3
'i' と '5' は、マンイーターのみが動き、自分は動かない
Good Luck
キーを押してスタート。
"""
def main():
Game.init()
Game.start()
Game.end()
class Game:
def init():
global screen, field
locale.setlocale(locale.LC_ALL, '') # UTF-8 を使うためにLC_ALLをセット
screen = curses.initscr()
curses.noecho()
curses.curs_set(0)
field = Field(width=40, height=23)
def start():
playing = True
while playing:
Game.instruction()
player = Game.setup()
Game.play(player)
Game.over()
playing = Game.ask_replay()
def instruction():
screen.clear()
screen.addstr(INSTRUCTION)
screen.getch() # 一文字キー入力待ち
def setup():
field.clear()
player = Player(x=field.width//2, y=field.height//2) # 最初に中央配置
Rock.deploy(num=120)
Maneater.deploy(num=12)
return player
def play(player):
while player.is_alive() and Maneater.any_alive():
screen.refresh()
player.move()
if player.is_alive():
Maneater.chase(player)
def over():
if not Maneater.any_alive():
screen.addstr(0, 0, "You Win! ", curses.A_BLINK)
else:
screen.addstr(0, 0, "You Lose ", curses.A_BLINK)
screen.refresh()
def ask_replay():
screen.addstr(1, 0, "Try Again? [y/n]")
while True:
answer = screen.getkey()
if answer in 'yn':
return answer == 'y'
def end():
curses.endwin()
class Field:
SPACE = " "
def __init__(self, width, height):
self.width = width
self.height = height
def clear(self):
screen.clear()
self.characters = [[self.SPACE] * self.width
for _ in range(self.height)]
def is_space(self, x, y):
return self.characters[y][x] == self.SPACE
def inside(self, x, y):
return 0 <= x < self.width and 0 <= y < self.height
def put(self, x, y, character):
self.characters[y][x] = character
screen.addstr(y, x * 2, str(character)) # 全角文字を使うのでx座標を2倍
def remove(self, x, y):
self.put(x, y, self.SPACE)
def find_space(self):
while True:
x, y = randint(0, self.width - 1), randint(0, self.height - 1)
if self.is_space(x, y):
return x, y
class Character:
def __init__(self, x, y):
self._alive = True
self.x = x
self.y = y
field.put(x, y, self)
def dead(self):
self._alive = False
def is_alive(self):
return self._alive
def move(self, x, y):
if not self.is_alive():
return
field.remove(self.x, self.y)
self.x = x
self.y = y
if self.conflict():
self.dead()
return
field.put(self.x, self.y, self)
def conflict(self):
return False
class Rock(Character):
def __str__(self):
return "#"
@staticmethod
def deploy(num):
Rock.rocks = [Rock(*field.find_space()) for _ in range(num)]
@staticmethod
def hit(target):
return any(rock.x == target.x and rock.y == target.y
for rock in Rock.rocks)
class Maneater(Character):
def __str__(self):
return "O"
@staticmethod
def deploy(num):
Maneater.maneaters = [Maneater(*field.find_space()) for _ in range(num)]
@staticmethod
def hit(target):
return any(maneater.x == target.x and maneater.y == target.y
for maneater in Maneater.maneaters
if maneater.is_alive() and maneater != target)
@staticmethod
def any_alive():
return any(maneater.is_alive() for maneater in Maneater.maneaters)
@staticmethod
def chase(player):
for maneater in Maneater.maneaters:
maneater.move(player)
def move(self, player):
if not self.is_alive():
return
# プレイヤーを追いかけるように差分を求める
dx = max(-1, min(1, player.x - self.x))
dy = max(-1, min(1, player.y - self.y))
super().move(self.x + dx, self.y + dy)
if self.is_alive():
player.hit(self)
def conflict(self):
return Maneater.hit(self) or Rock.hit(self)
class Player(Character):
MOVE = { # key: (x, y)
'7': (-1, -1), '8': (+0, -1), '9': (+1, -1),
'4': (-1, +0), '5': (+0, +0), '6': (+1, +0),
'1': (-1, +1), '2': (+0, +1), '3': (+1, +1),
'u': (-1, +0), 'i': (+0, +0), 'o': (+1, +0),
'j': (-1, +1), 'k': (+0, +1), 'l': (+1, +1),
}
def __str__(self):
return ("X", "@")[self.is_alive()]
def hit(self, maneater):
if self.x == maneater.x and self.y == maneater.y:
self.dead()
def move(self):
key = screen.getkey()
dx, dy = self.MOVE.get(key, (0, 0))
x, y = self.x + dx, self.y + dy
if field.inside(x, y):
super().move(x, y)
def conflict(self):
return not field.is_space(self.x, self.y)
def dead(self):
super().dead()
field.put(self.x, self.y, self)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment