Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions terminal_snake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import curses, time, random

def main(stdscr):
curses.curs_set(0)
stdscr.nodelay(True)

# 画面サイズは起動時に固定として扱う(iPadの微妙なリサイズ対策)
min_h, min_w = 20, 40
max_y, max_x = stdscr.getmaxyx()
if max_y < min_h or max_x < min_w:
stdscr.clear()
stdscr.addstr(0, 0, f"Make terminal larger (>= {min_h}x{min_w}).")
stdscr.refresh()
stdscr.getch()
return

# 枠(最初に一度だけ)
stdscr.clear()
stdscr.border()

# プレイ可能範囲(枠の内側)
top, left = 1, 1
bottom, right = max_y - 2, max_x - 2

# 初期配置
center = (max_y // 2, max_x // 2)
snake = [center]
direction = (0, 1) # 右
food = (random.randint(top, bottom), random.randint(left, right))
while food == center:
food = (random.randint(top, bottom), random.randint(left, right))
score = 0
speed = 0.07 # 小さいほど速い

while True:
# 入力(矢印 / WASD / q)
key = stdscr.getch()
if key in (curses.KEY_UP, ord('w'), ord('W')) and direction != (1, 0):
direction = (-1, 0)
elif key in (curses.KEY_DOWN, ord('s'), ord('S')) and direction != (-1, 0):
direction = (1, 0)
elif key in (curses.KEY_LEFT, ord('a'), ord('A')) and direction != (0, 1):
direction = (0, -1)
elif key in (curses.KEY_RIGHT, ord('d'), ord('D')) and direction != (0, -1):
direction = (0, 1)
elif key in (ord('q'), ord('Q')):
break

# 次の頭
head_y, head_x = snake[0]
ny, nx = head_y + direction[0], head_x + direction[1]

# 壁 or 自己衝突
if ny < top or ny > bottom or nx < left or nx > right or (ny, nx) in snake:
msg = f"GAME OVER (score={score}) Press any key..."
stdscr.addstr(max_y//2, max(1, (max_x-len(msg))//2), msg)
stdscr.nodelay(False)
stdscr.getch()
break

# 前進
snake.insert(0, (ny, nx))
if (ny, nx) == food:
score += 1
# 新しいエサ(スネーク上は避ける)
while True:
food = (random.randint(top, bottom), random.randint(left, right))
if food not in snake:
break
# 少しずつ速く
if speed > 0.03:
speed -= 0.002
else:
snake.pop() # しっぽを短く(個別消しはしない)

# 再描画(盤面をクリアしない。枠は残す)
# スコア行だけ上書き(はみ出し防止)
score_text = f"SNAKE score={score} (q=quit)"
score_text = score_text[:max(0, right - 1)]
stdscr.addstr(0, 2, " " * (max_x - 4))
stdscr.addstr(0, 2, score_text)

# 食べ物
stdscr.addch(food[0], food[1], '*')

# スネーク全身を描画
for i, (y, x) in enumerate(snake):
stdscr.addch(y, x, 'O' if i == 0 else 'o')

stdscr.refresh()
time.sleep(speed)

if __name__ == "__main__":
curses.wrapper(main)
# TODO: add high score featur