viewimage.php?id=3ea9d132&no=24b0d769e1d32ca73de784fa1bd62531bc86dc33fe20e88dc284ef41ed3f03fba55d03d7ad23d14384a61411563312773e86fd5c34f1120df2a8dad9b6b61592e6





# Distribution Invaders + Chi-square

# pip install pygame numpy scipy


import pygame

import random

import numpy as np

from scipy.stats import norm, t, uniform, laplace, chi2


pygame.init()


# ====================================

# 화면

# ====================================

WIDTH, HEIGHT = 1200, 800

screen = pygame.display.set_mode((WIDTH, HEIGHT))

pygame.display.set_caption("Distribution Invaders")

clock = pygame.time.Clock()

font = pygame.font.SysFont("arial", 24)


WHITE  = (255,255,255)

BLACK  = (0,0,0)

RED    = (220,50,50)

GREEN  = (50,220,50)

BLUE   = (50,50,220)

YELLOW = (255,220,0)

ORANGE = (255,120,0)


# ====================================

# 플레이어

# ====================================

player = pygame.Rect(WIDTH//2-30, HEIGHT-70, 60, 35)

bullets = []


# ====================================

# 분포 생성 함수

# (새 적 생성 시만 랜덤)

# ====================================

def make_normal():

    m = random.randint(-2, 2)

    s = random.choice([0.5, 1, 1.5])

    return {

        "name": f"Normal({m},{s})",

        "f": lambda x: norm.pdf(x, m, s),

        "color": BLUE

    }


def make_t():

    df = random.choice([1,2,3,5,10])

    return {

        "name": f"t(df={df})",

        "f": lambda x: t.pdf(x, df),

        "color": RED

    }


def make_uniform():

    a = -random.choice([1,2])

    b = random.choice([2,3])

    return {

        "name": f"Uniform({a},{b})",

        "f": lambda x: uniform.pdf(x, a, b-a),

        "color": GREEN

    }


def make_laplace():

    b = random.choice([0.5,0.7,1.0])

    return {

        "name": f"Laplace({b})",

        "f": lambda x: laplace.pdf(x, 0, b),

        "color": YELLOW

    }


def make_chi2():

    df = random.choice([1,2,3,5,10])

    return {

        "name": f"ChiSq(df={df})",

        "f": lambda x: chi2.pdf(x+3, df),

        "color": ORANGE

    }


DISTROS = [

    make_normal,

    make_t,

    make_uniform,

    make_laplace,

    make_chi2

]


# ====================================

# Enemy

# ====================================

class Enemy:


    def __init__(self, x, y, name, f, color):


        self.x = x

        self.y = y

        self.name = name

        self.f = f

        self.color = color


        self.speed = 1 + random.random()


        # 크기 2배

        self.width = 240

        self.height = 160


        # 부분 파괴 mask

        self.damage = np.ones(60, dtype=bool)


    def rect(self):

        return pygame.Rect(

            self.x,

            self.y,

            self.width,

            self.height

        )


    # 모양은 유지

    def move(self):

        self.y += self.speed


    # 좌우 10개 제거

    def hit(self, bullet_x):


        idx = int(

            (bullet_x - self.x)

            / self.width

            * 60

        )


        for k in range(idx-10, idx+11):

            if 0 <= k < 60:

                self.damage[k] = False


        return np.sum(self.damage) < 5


    def draw(self):


        xs = np.linspace(-3, 3, 60)

        ys = self.f(xs)


        if ys.max() > 0:

            ys = ys / ys.max() * 80


        pts = []


        for i, yv in enumerate(ys):


            if not self.damage[i]:

                if len(pts) > 1:

                    pygame.draw.lines(

                        screen,

                        self.color,

                        False,

                        pts,

                        4

                    )

                pts = []

                continue


            px = self.x + i*(self.width/59)

            py = self.y + self.height - yv

            pts.append((px, py))


        if len(pts) > 1:

            pygame.draw.lines(

                screen,

                self.color,

                False,

                pts,

                4

            )


        txt = font.render(

            self.name,

            True,

            WHITE

        )

        screen.blit(

            txt,

            (self.x, self.y-30)

        )


# ====================================

# 게임 변수

# ====================================

enemies = []

score = 0

lives = 3

spawn_timer = 0

auto_fire_timer = 0

running = True


# ====================================

# 메인 루프

# ====================================

while running:


    clock.tick(60)

    screen.fill(BLACK)


    # ------------------

    # 이벤트

    # ------------------

    for event in pygame.event.get():


        if event.type == pygame.QUIT:

            running = False


        if event.type == pygame.MOUSEBUTTONDOWN:

            bullets.append(

                pygame.Rect(

                    player.centerx-3,

                    player.y,

                    6,

                    20

                )

            )


        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_SPACE:

                bullets.append(

                    pygame.Rect(

                        player.centerx-3,

                        player.y,

                        6,

                        20

                    )

                )


    # ------------------

    # 마우스 드래그 이동

    # ------------------

    mx, my = pygame.mouse.get_pos()


    if pygame.mouse.get_pressed()[0]:

        player.centerx = mx


    player.x = max(

        0,

        min(WIDTH-player.width,

            player.x)

    )


    # ------------------

    # 자동 연사

    # ------------------

    auto_fire_timer += 1


    if pygame.mouse.get_pressed()[0] and auto_fire_timer > 8:

        bullets.append(

            pygame.Rect(

                player.centerx-3,

                player.y,

                6,

                20

            )

        )

        auto_fire_timer = 0


    # ------------------

    # 적 생성

    # ------------------

    spawn_timer += 1


    if spawn_timer > 70:


        spawn_timer = 0


        maker = random.choice(DISTROS)

        d = maker()


        enemies.append(

            Enemy(

                random.randint(

                    50,

                    WIDTH-300

                ),

                30,

                d["name"],

                d["f"],

                d["color"]

            )

        )


    # ------------------

    # 총알 이동

    # ------------------

    for b in bullets[:]:


        b.y -= 12


        if b.y < 0:

            bullets.remove(b)

        else:

            pygame.draw.rect(

                screen,

                WHITE,

                b

            )


    # ------------------

    # 충돌

    # ------------------

    for e in enemies[:]:


        e.move()

        e.draw()


        if e.y > HEIGHT:

            enemies.remove(e)

            lives -= 1

            continue


        for b in bullets[:]:


            if e.rect().colliderect(b):


                if b in bullets:

                    bullets.remove(b)


                destroyed = e.hit(

                    b.centerx

                )


                if destroyed:

                    enemies.remove(e)

                    score += 1


                break


    # ------------------

    # 플레이어

    # ------------------

    pygame.draw.rect(

        screen,

        WHITE,

        player

    )


    # ------------------

    # HUD

    # ------------------

    hud = font.render(

        f"Score: {score}   Lives: {lives}",

        True,

        WHITE

    )

    screen.blit(hud, (20,20))


    tip = font.render(

        "Drag mouse / Hold click",

        True,

        WHITE

    )

    screen.blit(tip, (850,20))


    # ------------------

    # Game Over

    # ------------------

    if lives <= 0:


        txt = font.render(

            "GAME OVER",

            True,

            RED

        )


        screen.blit(

            txt,

            (WIDTH//2-80,

             HEIGHT//2)

        )


        pygame.display.flip()

        pygame.time.wait(3000)

        running = False


    pygame.display.flip()


pygame.quit()