Skoči na vsebino

P1 2021/22 - 12 Bitka - resitev Starc Aljaz v2

Warning

Ta resitev deluje, a je napacna, saj ne uporablja koncepta objektnega programiranja (kar je celoten point naloge)

from typing import List, Tuple
import risar
import random
import itertools
import time
from PyQt5.QtWidgets import QMessageBox


def rnd_num (start: int|float, end: int|float, disallowed: List[Tuple[int|float, int|float]]):
    while True:
        num = random.uniform(start, end)
        # check if generated number is in any disallowed range
        for rng in disallowed:
            # if it is, just break the loop and generete a new number
            if (rng[0] < num < rng[1]):
                break
        else:
            # number is not in any disallowed ranges!
            # we return it :)
            return num



def rnd_ladja (x = None, y = None, r = None, barva = None, sirina = 1):
    if not x:
        x, _ = risar.nakljucne_koordinate()
    if not y:
        _, y = risar.nakljucne_koordinate()
    if not r:
        r = random.randint(2, 20)
    if not barva:
        barva = risar.nakljucna_barva()

    return risar.krog(x=x, y=y, r=r, barva=barva, sirina=sirina)


def do_they_collide (x1, y1, r1, x2, y2, r2):
    distSq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); 
    radSumSq = (r1 + r2) * (r1 + r2); 
    return distSq <= radSumSq

def fade_krog (krog, alpha):
    brush = krog.pen().color().lighter()
    brush.setAlpha(alpha)
    krog.setBrush(brush)

def nova_explozija (x, y, r, barva, lifetime_ms = 4000, sirina = 1):
    expl = risar.krog(x=x, y=y, r=r, barva=barva, sirina=sirina)
    el = {
        "l": expl,
        "type": "explosion",
        "x": x,
        "y": y,
        "r": r,
        "exploded_at": time.time(),
        "lifetime_ms": lifetime_ms
    }
    return el



def run_simulation (ladij=20, za_uniciti=10, pixel_per_cycle=1, cycle_delay=.0025, ladja_radij=10, miska_radij=30, explozija_radij=30, explozija_trajanje_ms=4000):

    risar.pobrisi()
    QMessageBox.information(None, "Zacetek igre", "Skupaj ladij: %i - uniciti vsaj %i" % (ladij, za_uniciti))


    # Lista "objekti" vsebuje entitete kot so ladje ter explozije
    ladje = []
    explozije = []

    # Kreiraj ladje ter jih dodaj v listo entitet
    for _ in range(ladij):
        barva = risar.nakljucna_barva()
        ladje.append({
            "l": rnd_ladja(r=ladja_radij, barva=barva),
            "barva": barva,
            "r": ladja_radij,
            "move_x": rnd_num(-1, 1, [(-.6, .6)]),
            "move_y": rnd_num(-1, 1, [(-.6, .6)]),
            "type": "ship"
        })

    # Kreiraj misko, edina entiteta, ki ni dodana v listo 'objekti'
    miska_barva = risar.nakljucna_barva()
    miska_krog = risar.krog(*risar.miska(), r=miska_radij, barva=miska_barva, sirina=1)




    # Zazenemo "main event loop?"
    while True:

        # Ce miska se ni bila kliknjena (ob kliku se krog odstrani)
        if miska_krog is not None:
            # premaknemo krog na trenutno pozicijo miske
            x, y = risar.miska()
            miska_krog.setPos(x, y)

            # in ce je slucajno ravno kliknjena
            if risar.klik():
                # dodamo explozijo v listo 'objekti'
                explozije.append(nova_explozija(x=x, y=y, r=explozija_radij, barva=miska_barva, lifetime_ms=explozija_trajanje_ms))
                # ter odstranimo miskin krog
                risar.odstrani(miska_krog)
                miska_krog = None

        # ce je miska klinjena
        # ter ni vec nobenih eksplozij
        elif explozije == [] or ladje == []:
            # je poiskus spodletel
            if len(ladje) > za_uniciti:
                QMessageBox.information(None, "Igra spodletela!", "Skupaj ladij: %i - za uniciti: %i - uniciti %i" % (ladij,  za_uniciti, ladij - len(ladje)))
                return False
            else:
                QMessageBox.information(None, "Zmaga!", "Skupaj ladij: %i - za uniciti: %i - unicenih %i" % (ladij, za_uniciti, ladij - len(ladje)))
                return True



        for objekt, obj_i in zip(ladje, itertools.count()):

            x = objekt["l"].x()
            y = objekt["l"].y()
            r = objekt["r"]

            o_left = x - r <= 0
            o_right = x + r >= risar.maxx
            o_top = y - r <= 0
            o_bottom = y + r >= risar.maxy


            # levi del kroga je izven okna, desni se ni
            if (o_left and not o_right): objekt["move_x"] = abs(objekt["move_x"])
            # desni del kroga je izven okna, levi se ni 
            if (not o_left and o_right): objekt["move_x"] = 0 - abs(objekt["move_x"])

            # spodnji del kroga je izven okna, zgornji se ni 
            if (not o_bottom and o_top): objekt["move_y"] = abs(objekt["move_x"])
            # spodnji del kroga je izven okna, zgornji se ni
            if (o_bottom and not o_top): objekt["move_y"] = 0 - abs(objekt["move_y"])

            # premaknemo ladjo
            objekt["l"].setPos(
                objekt["l"].x() + objekt["move_x"] * pixel_per_cycle,
                objekt["l"].y() + objekt["move_y"] * pixel_per_cycle
            )

            # preveri ce se je ladja zadela v explozijo
            for e in explozije:
                if e["type"] == "explosion" and do_they_collide(x, y, objekt["r"], e["x"], e["y"], e["r"]):
                    explozije.append(nova_explozija(x, y, explozija_radij, barva=objekt["barva"], lifetime_ms=explozija_trajanje_ms))
                    risar.odstrani(objekt["l"])
                    del ladje[obj_i]
                    break

        # odstranimo / fade-amo explozije
        for objekt, obj_i in zip(explozije, itertools.count()):
            time_alive_ms = (time.time() - objekt["exploded_at"]) * 1000
            # Ali obstaja vec casa kot lahko?
            if time_alive_ms < objekt["lifetime_ms"]:
                time_out_of_total = time_alive_ms / objekt["lifetime_ms"]
                alpha = 250 - 250 * time_out_of_total
                fade_krog(objekt["l"], int(alpha))
            else:
                # odstrani in nadaljuj zanko po ostalih objektih
                risar.odstrani(objekt["l"])
                del explozije[obj_i]

        risar.cakaj(cycle_delay)


stopnje = [
    (30, 10),
    (30, 12),
    (28, 12),
    (28, 14),
    (26, 14),
    (26, 16),
    (24, 16),
    (24, 18),
    (22, 18),
    (22, 20)
]

for ladij, za_uniciti in stopnje:
    run_simulation(ladij=ladij, za_uniciti=za_uniciti)

Zadnja posodobitev: May 7, 2022