User Tools

Site Tools


elemental_fighters

This is an old revision of the document!


Elemental Fighters

Uz zadatak je dan i izvorni kod.

Spajanjem na zadatak otvara se izbor borca. Mogući izbor su 3 borca i 3 elementa za svakog borca.

 Slika 1 - izbor borca

No, analizom koda u zadatku može se zaključiti da zapravo ne postoji kombinacija borca koja bi ni u najsretnijem slučaju uspjela pobijediti sve neprijatelje i doći do flaga — znači da je potrebno nešto drugo napraviti jer izbor pravog borca ne postoji.

Analizom koda, zanimljiva je varijabla s (scale), koja određuje koliko će se oslabiti ili ojačati neprijatelji.

 Slika 2 - scale varijabla

Ova varijabla se kasnije u kodu množi s atributima neprijatelja: što je manja, neprijatelji su slabiji; što je veća, neprijatelji su jači.

Također, zanimljiv dio koda je player default, koji definira varijablu _player_ kao `milo(“ice”)` ako je _player_ `None`.

 Slika 3 - Player default

Najključniji dio koda je funkcija kojom se inicijalizira varijabla _player_ iz izbora igrača.

 Slika 4 - inicijalizacija player varijable iz igračevog izbora

Ovdje se koristi funkcija eval, kojom se unos _fighter_ poziva kao funkcija, a _fighterType_ kao argument.

Sukladno tome, fighteri su zapravo funkcije:

 Slika 5 - fighter funkcije

Vrijednosti _fighterType_ definirane su u rječniku i parsiraju se pri pozivanju _fighter_ funkcije.

To znači da unosom _fighterType_ (“Odaberite element borca”) definiraš argument funkcije, a unosom _fighter_ (“Odaberite borca”) definiraš funkciju kojoj će se argument proslijediti i koja će se izvršiti u `eval`.

No, svaki unos prolazi kroz validate_input, filter koji određuje koji su unosi dozvoljeni.

 Slika 6 - validate funkcija

Kako bismo provjerili možemo li pozvati proizvoljnu funkciju i argument (ako validate_function ne zabrani), možemo probati:

list("aaa")

Unos izgleda ovako:

Odaberite element borca (Ice, Fire, Acid): aaaa
Odaberite borca (Zorn, Krev, Milo)list

 Slika 7 - poziv list("aaa")

Program vraća listu u kojoj su svi znakovi iz stringa koji smo poslali kao prvi argument, s dodanim zagradama oko _fighterType_ varijable (vidi sliku 4).

Slično možemo pozvati:

len("aaa")

Unos:

Odaberite element borca (Ice, Fire, Acid): aaa
Odaberite borca (Zorn, Krev, Milo)len

 Slika 8 - poziv len("aaa")

Program vraća 5, što odgovara trima znakovima `“a”` koje smo poslali i dvama znakovima zagrada.

Flag nije pohranjen u varijabli; hardkodiran je u zadnjem `print`u programa. Potrebno je osmisliti način kako pozvati odgovarajuću funkciju i argument da bi program izvršio flag.

Dobar pristup je mijenjanje varijable s (vidi sliku 2), koja predstavlja skalu jačine protivnika. Ako je postavimo na 0, protivnici su slabiji, a činjenica da se input koristi za mijenjanje varijable _s_ umjesto inicijalizacije borca nije problem jer postoji *default* borac (vidi sliku 3).

Cijeli unos igrača se izvršava unutar eval, koji evaluira *expression*. Primjeri: `“2+2”` → `4`, `len(“(aaa)”)` → `5`. Bilo koja vrijednost vraćena iz eval dodjeljuje se _player_ varijabli (vidi sliku 4).

Potrebno je mijenjati druge varijable u globalnom kontekstu (npr. _s_) unutar eval-a.

Python razlikuje *expression* i *statement*. *Statement* (npr. `a = 0`) izvršava akciju, ali ne vraća vrijednost — pa `eval(“a=0”)` nije validan kod. Funkcija exec izvršava *statement* i može mijenjati varijable u globalnom kontekstu: `exec(“a=0”)`. Pregledom validate_input (slika 6) vidi se da exec nije zabranjen.

Dakle, exec se može koristiti za mijenjanje globalne varijable s.

Primjer pokušaja:

exec("s=0")

Unos:

Odaberite element borca (Ice, Fire, Acid): s=0
Odaberite borca (Zorn, Krev, Milo)exec

Pokretanjem pojavit će se greška `invalid syntax` (slika 9) jer parser eval zahtijeva validan *expression*.

 Slika 9 - greška pri pokušaju  Slika 10 - eval parser i exec funkcija

Rješenje: koristiti Pythonov walrus operator (`:=`), koji je *expression* i vraća vrijednost dok istovremeno dodjeljuje varijabli.

Primjer:

(a := 3)

U zagradama postaje validan *expression*, koji se može evaluirati unutar eval i izvršiti s exec u globalnom scopeu.

Rješenje unosa:

Odaberite element borca (Ice, Fire, Acid): s:=0
Odaberite borca (Zorn, Krev, Milo)exec

Time se postavlja varijabla s na 0, a _player_ ostaje `None` — aktivira se *default* `player = Milo(“ice”)`.

 Slika 11 - walrus operator  Slika 12 - rješenje zadatka

Walrus operator je validan *expression*, može se izvršavati unutar eval i exec, mijenja vrijednost varijable samo ako se izvršava u globalnom scopeu.

 Slika 16 - walrus i eval / exec  Slika 17 - walrus unutar exec unutar eval

Ovaj postupak reproducira originalnu logiku inicijalizacije _player_ varijable u zadatku (slika 4).

 Slika 20 - pojednostavljeno izvršavanje payloada

Rješenje unosa:

Odaberite element borca (Ice, Fire, Acid): s:=0
Odaberite borca (Zorn, Krev, Milo)exec

Postavlja s = 0 i _player = None_, zatim se _player_ inicijalizira na *default* Milo(“ice”).

 Slika 21 - rješenje zadatka

Pošto se izvršava u global scopeu, exec može mijenjati globalnu varijablu s. Ako bi se izvršavalo unutar funkcije, lokalne varijable ne bi bile promijenjene.

 Slika 22 - eval unutar functiona  Slika 23 - eval unutar global scopea

Ovo vrijedi i za eval i za exec.

elemental_fighters.1761918940.txt.gz · Last modified: 2025/12/01 11:40 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki