import pygame
import math
import random

pygame.init()
W, H = 900, 600
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("탱크 게임")
clock = pygame.time.Clock()
font = pygame.font.SysFont("malgungothic", 20)
big_font = pygame.font.SysFont("malgungothic", 40, bold=True)

SKY = (140, 185, 225)
GROUND_COLOR = (80, 120, 70)
TANK_W, TANK_H = 46, 20
BARREL_LEN = 42
POWER_SCALE = 0.22                             # 힘(0~100)을 실제 속도로
SHELL_R = 5
GRAVITY = 0.2                                  # 매 프레임 아래로 더해지는 속도
BOOM_MAX = 40                                  # 폭발이 커지는 최대 크기

ground = []

def make_ground():
    # sin을 두 개 겹쳐서 완만한 언덕 지형을 만든다
    global ground
    ground = []
    for x in range(W):
        y = H - 150 - 38 * math.sin(x / 120) - 18 * math.sin(x / 43)
        ground.append(y)

make_ground()

def dig(cx, cy, r):
    # (cx, cy)를 중심으로 반지름 r만큼 땅을 파낸다
    for x in range(max(0, int(cx - r)), min(W, int(cx + r))):
        dx = x - cx
        inside = r * r - dx * dx
        if inside > 0:                             # 원 안쪽에 있는 x만
            bottom = cy + math.sqrt(inside)        # 구덩이의 아래 가장자리
            if bottom > ground[x]:                 # 지금 땅보다 아래면
                ground[x] = min(float(H), bottom)  # 그만큼 파낸다

def ground_y(x):
    xi = max(0, min(W - 1, int(x)))
    return ground[xi]

tanks = [
    {"x": 120.0, "angle": 45.0, "power": 55.0, "hp": 100,
     "color": (55, 105, 200), "name": "내 탱크"},
    {"x": W - 120.0, "angle": 135.0, "power": 55.0, "hp": 100,
     "color": (200, 80, 70), "name": "적 탱크"},
]
shell = None                                   # 날아가는 포탄 (없으면 None)
boom = None                                    # 폭발 효과 {"x","y","r"}
turn = 0                                       # 0 = 내 탱크, 1 = 적 탱크
state = "aim"                                  # "aim" / "fly" / "boom" / "over"
enemy_miss = None                              # 적이 지난번 얼마나 빗나갔는지
wind = 0.0                                     # 바람 세기 (양수면 오른쪽)

def tank_rect(t):
    y = ground_y(t["x"])
    return pygame.Rect(int(t["x"] - TANK_W / 2), int(y - TANK_H), TANK_W, TANK_H)

def barrel_end(t):
    rad = math.radians(t["angle"])
    bx = t["x"] + math.cos(rad) * BARREL_LEN
    by = (ground_y(t["x"]) - TANK_H) - math.sin(rad) * BARREL_LEN
    return bx, by

def explode(x, y):
    # 포탄을 없애고 그 자리에 폭발을 만든다
    global shell, boom, state, enemy_miss
    dig(x, y, 34)                              # 터진 자리를 파낸다
    shell = None
    boom = {"x": x, "y": y, "r": 6.0}
    # 폭발 지점에서 가까운 탱크에 피해를 준다
    for t in tanks:
        cx, cy = t["x"], ground_y(t["x"]) - TANK_H / 2
        d = math.hypot(cx - x, cy - y)
        if d < 70:
            t["hp"] -= int(50 * (1 - d / 70)) + 8   # 가까울수록 큰 피해
            t["hp"] = max(0, t["hp"])
    if turn == 1:                              # 적이 쏜 포탄이었다면
        enemy_miss = x - tanks[0]["x"]         # 내 탱크와 얼마나 떨어졌나 기억
    state = "boom"                             # 폭발 단계로

def next_turn():
    # 폭발이 끝나면 차례를 넘긴다
    global turn, state, wind
    # 누군가 쓰러졌으면 게임 끝
    if tanks[0]["hp"] <= 0 or tanks[1]["hp"] <= 0:
        state = "over"
        return
    turn = 1 - turn                            # 0↔1 뒤집기
    wind = random.uniform(-0.05, 0.05)         # 차례마다 바람이 바뀐다
    state = "aim"
    if turn == 1:
        enemy_turn()

def enemy_turn():
    # 지난번 빗나간 거리를 보고 힘을 조절한다
    t = tanks[1]
    t["angle"] = random.uniform(120, 150)
    if enemy_miss is None:
        t["power"] = random.uniform(45, 70)    # 첫 발은 감으로 쏜다
    else:
        # 빗나간 만큼 힘을 조정한다 (20~95 사이로 제한)
        t["power"] = max(20.0, min(95.0, t["power"] + enemy_miss * 0.06))
    fire(t)

def fire(t):
    # 각도와 힘으로 포탄의 처음 속도를 만든다
    global shell, state
    rad = math.radians(t["angle"])
    speed = t["power"] * POWER_SCALE
    bx, by = barrel_end(t)                     # 포신 끝에서 출발
    shell = {
        "x": bx,
        "y": by,
        "vx": math.cos(rad) * speed,           # 가로 속도
        "vy": -math.sin(rad) * speed,          # 세로 속도 (위가 음수)
    }
    state = "fly"                              # 쏘면 비행 단계로

def reset_game():
    # 게임 전체를 처음 상태로 되돌린다
    global tanks, shell, boom, wind, turn, state, enemy_miss
    make_ground()                              # 지형도 새로 만든다
    tanks = [
        {"x": 120.0, "angle": 45.0, "power": 55.0, "hp": 100,
         "color": (55, 105, 200), "name": "내 탱크"},
        {"x": W - 120.0, "angle": 135.0, "power": 55.0, "hp": 100,
         "color": (200, 80, 70), "name": "적 탱크"},
    ]
    shell = None
    boom = None
    wind = random.uniform(-0.05, 0.05)
    turn = 0
    state = "aim"
    enemy_miss = None

reset_game()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            if state == "aim" and turn == 0:   # 내 차례, 조준 중일 때만 발사
                fire(tanks[0])
            elif state == "over":
                reset_game()                   # 끝난 상태면 다시 시작

    # 내 차례에 조준 중일 때만 각도·힘을 바꿀 수 있다
    me = tanks[0]
    if state == "aim" and turn == 0:
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            me["angle"] = min(180.0, me["angle"] + 0.8)
        if keys[pygame.K_RIGHT]:
            me["angle"] = max(0.0, me["angle"] - 0.8)
        if keys[pygame.K_UP]:
            me["power"] = min(100.0, me["power"] + 0.6)
        if keys[pygame.K_DOWN]:
            me["power"] = max(5.0, me["power"] - 0.6)

    # 포탄을 속도만큼 움직인다 (벽돌깨기의 공과 똑같다)
    if state == "fly" and shell:
        shell["vx"] += wind                    # 바람이 가로로 밀어준다
        shell["vy"] += GRAVITY                 # 이 한 줄이 포물선을 만든다
        shell["x"] += shell["vx"]
        shell["y"] += shell["vy"]

        # 탱크에 직접 맞았는지 먼저 확인한다
        hit_tank = None
        for t in tanks:
            if tank_rect(t).collidepoint(shell["x"], shell["y"]):
                hit_tank = t

        if hit_tank:
            explode(shell["x"], shell["y"])
        elif shell["y"] >= ground_y(shell["x"]):    # 땅에 닿았으면 폭발
            explode(shell["x"], ground_y(shell["x"]))
        elif shell["x"] < -300 or shell["x"] > W + 300 or shell["y"] > H + 600:
            shell = None                       # 화면 밖으로 나가면 사라짐

    # 폭발이 점점 커지다가 사라진다
    if state == "boom" and boom:
        boom["r"] += 2.5
        if boom["r"] >= BOOM_MAX:
            boom = None
            next_turn()                        # 폭발이 끝나야 다음 차례

    screen.fill(SKY)
    points = [(0, H)] + [(x, ground[x]) for x in range(W)] + [(W, H)]
    pygame.draw.polygon(screen, GROUND_COLOR, points)

    for t in tanks:
        r = tank_rect(t)
        pygame.draw.rect(screen, t["color"], r, border_radius=6)
        bx, by = barrel_end(t)
        pygame.draw.line(screen, t["color"], (t["x"], r.top), (bx, by), 5)

        # 체력바: 회색 바탕 위에 체력만큼 채운다
        bar = pygame.Rect(r.centerx - 25, r.top - 16, 50, 7)
        pygame.draw.rect(screen, (220, 220, 220), bar, border_radius=3)
        hp_w = int(50 * t["hp"] / 100)
        pygame.draw.rect(screen, (90, 190, 100) if t["hp"] > 30 else (210, 80, 70),
                         pygame.Rect(bar.x, bar.y, hp_w, bar.h), border_radius=3)

    if shell:
        pygame.draw.circle(screen, (40, 40, 50), (int(shell["x"]), int(shell["y"])), SHELL_R)

    if boom:
        pygame.draw.circle(screen, (255, 190, 60), (int(boom["x"]), int(boom["y"])), int(boom["r"]))
        pygame.draw.circle(screen, (255, 120, 50), (int(boom["x"]), int(boom["y"])), int(boom["r"] * 0.6))

    screen.blit(font.render(f"각도 {me['angle']:.0f}°", True, (25, 30, 40)), (16, 14))
    screen.blit(font.render(f"힘 {me['power']:.0f}", True, (25, 30, 40)), (16, 40))
    wind_txt = f"바람 {'→' if wind > 0 else '←'} {abs(wind) * 100:.0f}"
    screen.blit(font.render(wind_txt, True, (25, 30, 40)), (16, 94))
    gauge = pygame.Rect(16, 68, 200, 14)
    pygame.draw.rect(screen, (230, 230, 230), gauge, border_radius=7)
    filled = pygame.Rect(16, 68, int(200 * me["power"] / 100), 14)
    pygame.draw.rect(screen, (240, 150, 60), filled, border_radius=7)

    turn_txt = "내 차례 (←→ 각도, ↑↓ 힘, 스페이스 발사)" if turn == 0 else "적 차례..."
    screen.blit(font.render(turn_txt, True, (25, 30, 40)), (16, H - 34))

    if state == "over":
        win = "승리!" if tanks[1]["hp"] <= 0 else "패배..."
        msg = big_font.render(win, True, (25, 30, 40))
        sub = font.render("스페이스를 누르면 다시 시작", True, (25, 30, 40))
        screen.blit(msg, msg.get_rect(center=(W // 2, H // 2 - 20)))
        screen.blit(sub, sub.get_rect(center=(W // 2, H // 2 + 30)))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()