Tema 3 – Liga Boților (C++)

🤖 Liga Boților - Arena Studenților ⚔️

Construiește un motor de simulare pentru o arenă tactică în care echipele de boți concurează pentru energie, teritoriu și puncte de stil. Formatul este 100% comandă-per-linie, astfel încât output-ul tău poate fi redat ca input pentru un alt student – perfect pentru dueluri!

📅 Publicare: 7.12.2025 \ ⏰ Deadline: 21.12.2025, ora 23:59 \ 🎯 Punctaj Total: 10p (9p teste + 1p README + până la 5p bonus clasament) \ 🧪 Teste: 20 scenarii automate (folder `teste/`) \ 🏆 Clasament Live: rezultate.eu \ 📝 Accept Assignment: Classroom Link

Autor: Trifu Marius-Constantin

Informații Generale

Tehnologii:

  • ✅ Limbaj: C++ (este voie cu STL)
  • ✅ Testare: 20 teste dinamice
  • ✅ Deploy: GitHub Actions
  • ✅ Clasament: rezultate.eu

Cerințe:

  • ✅ Structuri/Clase proprii pentru boți, hartă, comenzi
  • ✅ Separate `.h` / `.cpp`
  • ✅ Compilare prin `make`

1. Descriere

Jocul este un battle royale simplu pe hartă 2D. Ești un jucător într-o arenă rectangulară și te poți deplasa sau planta bombe. Simularea rulează pe runde (ticks), iar intrarea este o succesiune de comenzi trimise de arbitru (`REF`). După fiecare comandă procesată trebuie să emiți propria ta decizie (`PLAYER …`).

🎯 Obiectiv: Maximizează TOTAL_SCORE = damage dat adversarilor + supraviețuire - penalizări.

Mecanica Jocului

Ticks și Acțiuni:

  • Un tick = o rundă în care fiecare jucător face exact o acțiune
  • Acțiuni posibile: `MOVE` (deplasare o casetă), `PLANT_BOMB` (plantează bombă), `PLANT_WALL` (plantează perete), `WAIT` (stai pe loc)
  • După fiecare `REF …` primești, trebuie să răspunzi cu exact o acțiune `PLAYER …`

Hartă:

  • Arenă rectangulară de dimensiuni `LATIME × INALTIME` (coordonate 0-index)
  • Fiecare celulă poate conține: un jucător, o bombă, un perete, sau nimic

Mișcare:

  • Te poți deplasa cu o casetă pe rând în direcții: `N` (sus), `S` (jos), `E` (dreapta), `W` (stânga)
  • NU poți merge pe diagonală
  • Nu poți merge într-o celulă ocupată de alt jucător, bombă sau perete

Bombe:

  • Poți planta o bombă în celula curentă cu acțiunea `PLANT_BOMB`
  • Bomba explodează după `BOMB_TIMER` ticks de la plantare (ex: `BOMB_TIMER = 3` → explodează după 3 ticks)
  • La explozie, toate celulele din raza de explozie (`BOMB_RADIUS = 2`) primesc damage
  • Raza de explozie = 2 casete: Bomba afectează celulele la distanță 1 și 2 în toate direcțiile (N, S, E, W)
    • Exemplu: Bomba la (5,5) afectează: (5,4), (5,3), (5,6), (5,7), (4,5), (3,5), (6,5), (7,5) - total 8 celule
  • Damage-ul este `BOMB_DAMAGE` pentru fiecare celulă afectată
  • Un jucător poate avea maximum `MAX_BOMBS` bombe active simultan

Pereți:

  • Poți planta un perete în celula curentă cu acțiunea `PLANT_WALL`
  • Peretele blochează mișcările (nu poți merge prin el)
  • Peretele blochează explozii (dacă e între tine și bomba, primești mai puțin damage sau deloc, în funcție de poziție)
  • Peretele are rezistență: Trebuie să fie lovit de 2 bombe pentru a fi distrus
    • Prima bombă care lovește peretele îl slăbește (primește damage)
    • A doua bombă care lovește peretele îl distruge complet
  • Un jucător poate avea maximum `MAX_WALLS` pereți activi simultan
  • Peretele este permanent până când este distrus de 2 explozii

Vizibilitate:

  • Adversarul vede toate bombele plantate (pentru strategie)
  • Vezi pozițiile adversarilor când se deplasează (comenzi `REF MOVE`)

Scor:

  • Primești puncte pentru damage dat adversarilor
  • Primești bonus pentru supraviețuire (dacă rămâi în viață)
  • Penalizări pentru comenzi invalide sau ieșire din arenă

Fluxul unei simulari

1. Citești configurarea arenei (dimensiuni, parametri bombe, număr runde).
2. Primești comenzi de la arbitru una câte una (spawn adversar, mișcări, explozii etc.).
3. După fiecare linie citită **trebuie** să răspunzi cu exact 1 linie care descrie acțiunea ta pentru acel tick.
4. La final raportezi tabela scorurilor și cine câștigă.

2. Formate Fișiere

📝 Respectă exact formatele! Fișierele de test vor fi în `teste/input/test01.in … test20.in`. Output-urile așteptate sunt în `teste/output/`.

2.1 Fișier de intrare (arena.txt)

arena.txt
ARENA LATIME INALTIME ROUNDS
BOMB_TIMER BOMB_RADIUS BOMB_DAMAGE MAX_BOMBS MAX_WALLS
PLAYER_HP INITIAL_X INITIAL_Y
STREAM
TICK <t>
SPAWN <team> <x> <y>
MOVE <team> <x> <y>
BOMB <team> <x> <y> <timer>
EXPLODE <x> <y>
WALL <team> <x> <y>
WALL_HIT <x> <y>
WALL_BROKEN <x> <y>
HIT <x> <y> <dmg>
...
END

Explicații:

  • `ARENA` – dimensiunile grilei (0-index), număr maxim de runde.
  • `BOMB_TIMER` – numărul de ticks până bomba explodează (ex: 3 = explodează după 3 ticks de la plantare).
  • `BOMB_RADIUS` – raza de explozie (fixată la 2 casete în toate direcțiile N, S, E, W).
  • `BOMB_DAMAGE` – damage-ul aplicat fiecărei celule afectate.
  • `MAX_BOMBS` – numărul maxim de bombe active simultan pe jucător.
  • `MAX_WALLS` – numărul maxim de pereți activi simultan pe jucător.
  • `PLAYER_HP` – punctele de viață inițiale ale jucătorului.
  • `INITIAL_X INITIAL_Y` – poziția inițială a jucătorului tău (echipa Alpha).
  • `STREAM` – începe secvența de comenzi live. Liniile vin în timp real / sequential; nu există număr declarat, trebuie să citești până la `END`.

Notă: `BOMB_RADIUS` este întotdeauna 2 în această temă (bomba afectează celulele la distanță 1 și 2 în direcțiile N, S, E, W).

Direcții disponibile: `N` (sus), `S` (jos), `E` (dreapta), `W` (stânga). NU sunt permise diagonalele.

Exemplu:

ARENA 10 8 50
3 1 20 3
100 0 0
STREAM
REF TICK 1
REF SPAWN Beta 9 7
REF MOVE Beta 9 6
REF TICK 2
REF MOVE Beta 9 5
...
END

2.2 Format comenzi de intrare

Comandă Semnificație
TICK t Semnalează începerea tick-ului `t`.
SPAWN team x y Arbitru introduce un jucător pentru `team` (Alpha/Beta) la coordonatele (x, y).
MOVE team x y Jucătorul rival (`team`) s-a deplasat la coordonatele (x, y).
BOMB team x y timer Jucătorul `team` a plantat o bombă la (x, y) care explodează în `timer` ticks.
EXPLODE x y O bombă a explodat la coordonatele (x, y).
WALL team x y Jucătorul `team` a plantat un perete la coordonatele (x, y).
WALL_HIT x y Un perete la (x, y) a fost lovit de o bombă (prima lovitură, peretele rămâne activ).
WALL_BROKEN x y Un perete a fost distrus complet (a doua bombă) la coordonatele (x, y).
HIT x y dmg Ai primit `dmg` damage la coordonatele (x, y) (de la explozie).

Observații:

  • Vezi toate mișcările adversarilor (`MOVE Beta …`).
  • Vezi toate bombele plantate (`BOMB Beta …`).
  • Vezi toți pereții plantați (`WALL Beta …`).
  • Primești notificări când bombele explodează (`EXPLODE …`).
  • Primești notificări când pereții sunt loviți (`WALL_HIT …`) sau distruși (`WALL_BROKEN …`).
  • Primești damage când ești în raza de explozie (`HIT …`).

Elemente noi (extensibilitate):

  • Poți primi comenzi noi pentru elemente viitoare (ex: `TRAP team x y`, `POWERUP x y type`).
  • Pentru comenzi necunoscute, răspunde cu `WAIT`.

2.3 Output obligatoriu (arena.out)

arena.out
MOVE E
BOMB
WALL
WAIT
...
SCOREBOARD
DAMAGE_DEALT: value
SURVIVAL_BONUS: value
PENALTIES: value
TOTAL_SCORE: value
WINNER: Alpha/Beta/Draw

Reguli:

  • Exact 1 linie după fiecare comandă de intrare procesată.
  • Acțiuni disponibile: `MOVE <direction>`, `BOMB`, `WALL`, `WAIT`.
  • `MOVE <direction>` – te deplasezi cu o casetă în direcția `direction` (`N`, `S`, `E`, `W`).
  • `BOMB` – plantezi o bombă în celula curentă (dacă ai loc în `MAX_BOMBS`).
  • `WALL` – plantezi un perete în celula curentă (dacă ai loc în `MAX_WALLS`).
  • `WAIT` – stai pe loc (folosit când nu poți face altceva sau când comanda e necunoscută).
  • Output-ul trebuie să fie determinist (aceeași intrare → exact același output). Astfel putem lua fișierul rezultat și îl putem folosi ca input pentru un nou run (ex: `cat studentA.out | ./arena`).
  • Ultima parte `SCOREBOARD …` apare doar după `END`.

Notă: Nu mai trebuie să incluzi tick-ul în output (se știe din context).

Exemplu output:

MOVE E
BOMB
MOVE N
WAIT
SCOREBOARD
DAMAGE_DEALT: 60
SURVIVAL_BONUS: 50
PENALTIES: 0
TOTAL_SCORE: 110
WINNER: Alpha

2.4 Refolosirea output-ului ca input

Pentru dueluri:

  • Rulezi Student A → obții `arena.out`.
  • Transformi output-ul în comenzi de intrare (script disponibil în `teste/scripturi/oficializeaza_transcriere.py`).
  • Rulezi Student B cu acea transcriere: `cat arena.out.refeed | ./arena`.
  • Programul tău trebuie să ignore liniile de acțiune întâlnite în input (sunt tratate ca mișcări deja consumate) și să genereze răspunsuri noi.

2.5 Elemente noi (extensibilitate)

Formatul permite adăugarea de elemente noi în viitor:

  • Capcane: `TRAP team x y` - capcană plantată care dă damage când e activată
  • Power-ups: `POWERUP x y type` - obiecte speciale care dau bonusuri (ex: `SPEED`, `SHIELD`, `EXTRA_BOMB`)
  • Teleport: `TELEPORT team x1 y1 x2 y2` - jucătorul se teleportează
  • Alte elemente: Orice comandă nouă poate fi adăugată

Regulă: Pentru comenzi necunoscute, răspunde cu `WAIT`. Programul tău trebuie să fie robust la comenzi noi.

3. Reguli de Validare

🗺️ Mișcare

  • Poți merge doar în direcții: `N` (sus), `S` (jos), `E` (dreapta), `W` (stânga).
  • NU poți merge pe diagonală.
  • Nu poți merge într-o celulă ocupată de alt jucător, bombă sau perete.
  • Nu poți ieși din arenă: coordonatele trebuie să fie în `[0, LATIME) × [0, INALTIME)`.
  • Dacă comanda `MOVE` este invalidă → se tratează ca `WAIT` (penalizare).

💣 Bombe

  • Poți planta o bombă doar dacă ai mai puțin de `MAX_BOMBS` bombe active.
  • Nu poți planta o bombă într-o celulă care deja conține o bombă sau perete.
  • Bomba explodează după `BOMB_TIMER` ticks de la plantare (ex: timer=3 → explodează după 3 ticks).
  • La explozie, toate celulele din raza de explozie = 2 casete primesc `BOMB_DAMAGE` damage.
  • Raza de explozie = 2 casete în direcțiile N, S, E, W:
    • Bomba la (x, y) afectează: (x, y-1), (x, y-2), (x, y+1), (x, y+2), (x-1, y), (x-2, y), (x+1, y), (x+2, y)
    • Total: 8 celule (4 direcții × 2 casete fiecare)
  • Un jucător poate fi afectat de mai multe bombe simultan (damage se adună).
  • Pereții blochează explozii: Dacă un perete e între tine și bomba, primești mai puțin damage sau deloc (în funcție de poziție).
  • Pereții pot fi slăbiți/distruși: Dacă o bombă explodează în raza sa, peretele primește damage. După 2 bombe, peretele este distrus.

🧱 Pereți

  • Poți planta un perete doar dacă ai mai puțin de `MAX_WALLS` pereți activi.
  • Nu poți planta un perete într-o celulă care deja conține o bombă, perete sau jucător.
  • Peretele blochează mișcările (nu poți merge prin el).
  • Peretele blochează parțial explozii (dacă e între tine și bomba, primești mai puțin damage sau deloc).
  • Peretele are rezistență: Trebuie să fie lovit de 2 bombe pentru a fi distrus:
    • Prima bombă care lovește peretele (în raza sa) îl slăbește (peretele primește damage, dar rămâne activ)
    • A doua bombă care lovește peretele îl distruge complet (peretele dispare, primești `REF WALL_DESTROYED`)
  • Peretele este permanent până când este distrus de 2 explozii.
  • Strategie: Poți încolți adversarul cu pereți, dar el poate distruge pereții cu 2 bombe.

❤️ Viață și Damage

  • Jucătorul începe cu `PLAYER_HP` puncte de viață.
  • Când primești damage (`REF DAMAGE …`), scazi din HP.
  • Dacă HP ≤ 0 → jucătorul moare și nu mai poate face acțiuni.
  • Damage-ul se aplică imediat când bomba explodează.

⏱️ Sincronizare

  • Pentru fiecare `TICK t` trebuie să setezi contextul curent.
  • Comenzile cu alt tick decât cel curent sunt erori → tratează-le ca `WAIT`.
  • Două comenzi pot apărea cu același tick; le procesezi în ordine.

🪙 Scoring logic

  • `DAMAGE_DEALT` – damage total aplicat adversarilor (când bombele tale explodează și îi lovesc).
  • `SURVIVAL_BONUS` – bonus pentru supraviețuire (dacă rămâi în viață la final).
  • `PENALTIES` – se adună pentru:
    • Comenzi invalide (MOVE în celulă ocupată, PLANT_BOMB când ai MAX_BOMBS, etc.)
    • Ieșire din arenă
    • Lipsă răspuns (nu ai emis `PLAYER …` după un `REF …`)

4. Implementare

  • `main.cpp` doar creează obiectul principal (`ArenaController controller; controller.run(argc, argv);`).
  • Folosește clase pentru: `Arena` (hartă), `Player` (poziție, HP, bombe active, pereți activi), `Bomb` (poziție, timer), `Wall` (poziție), `Scoreboard`.
  • Tratează intrarea ca flux: citești linie → parsezi → execuți → produci output imediat.
  • Este permisă bufferizarea, dar output-ul trebuie să păstreze ordinea exactă a comenzilor de intrare.
  • Comenzile necunoscute → `WAIT`.
  • Gestionare bombe: Menține o listă de bombe active cu timer-uri. La fiecare tick, decrementezi timer-ul. Când timer = 0, bomba explodează cu raza 2 (celule la distanță 1 și 2 în direcțiile N, S, E, W).
  • Gestionare pereți: Menține o listă de pereți activi cu un contor de damage. Când o bombă explodează în raza sa, peretele primește damage. După 2 bombe, peretele este distrus.
  • Blocare explozii: Când o bombă explodează, verifică dacă pereții blochează damage-ul către anumite celule (dacă un perete e între bomba și jucător, damage-ul este redus sau blocat).
  • Vizibilitate: Toate bombele și pereții plantați sunt vizibili (vezi `REF BOMB_PLANTED …`, `REF WALL_PLANTED …`), deci poți planifica strategia.
  • Poți folosi STL (vector, map, etc.) pentru a gestiona bombele, pereții și jucătorii.

5. Punctaj

5.1 Teste automate (9p)

  • 20 teste × 0.45p.
  • Fiecare test are limită minimă în `teste/limite_minime.txt`.
  • Unele teste includ dueluri simulate (output → input). Programul trebuie să rămână consistent.

5.2 README (1p)

  • Nume + grupă.
  • Cum e structurată arena (clase/fișiere).
  • Cum asiguri determinismul output-ului.

5.3 Bonus Clasament (până la 5p)

  • Clasament calculat după `TOTAL_SCORE` cumulat pe toate testele.
  • Top 1 → +5p, 2-3 → +4p, 4-5 → +3p, 6-10 → +2p, 11-20 → +1p.

6. Dueluri între studenți

1. Rulați `make record TEST=test07` pentru a salva transcriptul oficial (`out/test07.log`). 2. Trimiteți fișierul altui student. 3. Acesta îl poate reda cu `cat out/test07.log | ./arena`. 4. Pentru turnee, există scriptul `scripts/run_duel.sh studentA studentB testID` care combină output-urile și declară câștigătorul după reguli.

Programul vostru trebuie să fie robust la:

  • Comenzi duplicat (ex: același `SPAWN` repetat).
  • Ticks lipsă (trebuie să faceți `WAIT` până revine).
  • Output folosit ca input (linii de acțiune în stream).

7. Comunicare în Timp Real între Programe

Pentru dueluri live sau testare interactivă, ai mai multe opțiuni:

7.1 Named Pipes (FIFO) - Timp Real

Creezi un pipe și conectezi programele:

# Creează pipe-ul
mkfifo /tmp/arena_pipe
 
# Rulează Student A (scrie în pipe)
./arena_studentA < input.txt > /tmp/arena_pipe &
 
# Rulează Student B (citește din pipe)
./arena_studentB < /tmp/arena_pipe > output.txt
 
# Curăță după
rm /tmp/arena_pipe

Avantaje: Comunicare instantanee, fără fișiere intermediare. Dezavantaje: Trebuie să gestionezi procesele manual.

7.2 Pipe Normal + tee (Salvare + Redirecționare)

Scrie în fișier ȘI trimite mai departe simultan:

# Student A scrie la stdout, tee salvează în fișier ȘI trimite la Student B
./arena_studentA < input.txt | tee arena_studentA.out | ./arena_studentB > arena_studentB.out

Avantaje: Simplu, salvează ambele output-uri. Dezavantaje: Nu e “timp real” strict (bufferizare posibilă).

7.3 Process Substitution (Bash)

Bash creează automat pipe-uri temporare:

# Student A scrie într-un "fișier virtual" care e de fapt input pentru Student B
./arena_studentB < <(./arena_studentA < input.txt) > output.txt
 
# SAU invers: Student B primește output-ul lui A ca input
./arena_studentB <(./arena_studentA < input.txt) > output.txt

Avantaje: Sintaxă curată, bash gestionează pipe-urile. Dezavantaje: Funcționează doar în bash, nu în sh.

7.4 Exemplu Makefile pentru Dueluri

# Duel între două executabile
duel: arena_studentA arena_studentB
	@echo "🚀 Pornesc duelul..."
	@mkfifo /tmp/duel_pipe 2>/dev/null || true
	@timeout 30 ./arena_studentA < teste/input/test01.in | \
		tee out/studentA.log | \
		./arena_studentB > out/studentB.log || true
	@rm -f /tmp/duel_pipe
	@echo "✅ Duel terminat. Verifică out/studentA.log și out/studentB.log"
 
# Duel cu named pipe explicit
duel-fifo: arena_studentA arena_studentB
	@mkfifo /tmp/arena_fifo
	@./arena_studentA < teste/input/test01.in > /tmp/arena_fifo & \
	./arena_studentB < /tmp/arena_fifo > out/duel_result.out; \
	rm -f /tmp/arena_fifo

Format pentru dueluri: Output-ul lui Student A trebuie transformat în comenzi de intrare înainte de a fi dat lui Student B. Vezi secțiunea 6 pentru scriptul de transcriere.

8. Încărcare și Testare

Comenzi Make:

make              # compilează și rulează toate testele din teste/input
make build        # doar compilare
make run          # rulează arena.txt -> arena.out
make test05       # rulează doar testul 5
make record TEST=test12  # rulează testul și păstrează transcriptul pentru duel

GitHub Actions rulează `make` + trimite rezultatele la `rezultate.eu`. Output-ul scriptului `trimite_rezultate.py` va include `TOTAL_SCORE`, nickname etc.

9. Exemplu Simplificat

Scenariu: Arenă 6×6, bombe cu timer 3, raza 2, damage 20, max 2 bombe, max 3 pereți. Tu (Alpha) ești la (0,0), adversarul (Beta) la (5,5).

Input
ARENA 6 6 10
3 2 20 2 3
100 0 0
STREAM
TICK 1
SPAWN Beta 5 5
MOVE Beta 5 4
TICK 2
MOVE Beta 5 3
BOMB Beta 5 3 3
TICK 3
MOVE Beta 5 2
WALL Beta 4 2
TICK 4
MOVE Beta 4 1
TICK 5
EXPLODE 5 3
HIT 5 3 20
HIT 5 2 20
HIT 5 4 20
HIT 5 1 20
HIT 4 3 20
HIT 3 3 20
WALL_HIT 4 2
TICK 6
EXPLODE 2 0
HIT 2 0 20
HIT 1 0 20
HIT 0 0 20
HIT 3 0 20
WALL_BROKEN 4 2
END
Output
MOVE E
MOVE E
BOMB
WALL
MOVE N
WAIT
SCOREBOARD
DAMAGE_DEALT: 20
SURVIVAL_BONUS: 50
PENALTIES: 0
TOTAL_SCORE: 70
WINNER: Alpha

Explicație:

  • Tick 1: Te deplasezi spre dreapta (E) pentru a te apropia de adversar.
  • Tick 2: Continui spre dreapta.
  • Tick 3: Plantezi o bombă la (2,0) care va exploda în 3 ticks (raza 2 = afectează celulele la distanță 1 și 2).
  • Tick 4: Plantezi un perete la (1,0) pentru a te proteja de explozia adversarului.
  • Tick 5: Bomba adversarului explodează la (5,3) cu raza 2, peretele tău la (4,2) primește prima lovitură (`REF WALL_DAMAGED`).
  • Tick 6: Bomba ta explodează la (2,0) cu raza 2, peretele adversarului la (4,2) primește a doua lovitură și este distrus (`REF WALL_DESTROYED`).
  • La final: Ai supraviețuit, ai dat damage adversarului, și ai distrus peretele adversarului cu 2 bombe.

10. Tips & Checklist

  • ✅ Stochează istoric comenzi pentru a putea reface dueluri.
  • ✅ Normalizează toate coordonatele/ids.
  • ✅ Scrie teste proprii folosind `scripts/generate_random_stream.py`.
  • ✅ Asigură-te că output-ul tău nu are spații în plus.
  • ⛔ Nu amesteca logică de I/O cu logica de simulare – folosește un controller clar.

Checklist:

  1. [ ] `make build` fără warnings
  2. [ ] Toate testele oficiale trecute local
  3. [ ] README complet
  4. [ ] Transcript deterministic
  5. [ ] Trimite la timp pe GitHub

Succes și abia așteptăm duelurile! 🥊

poo-is-ab/tema/2025/03_test.txt · Last modified: 2025/11/26 18:35 by marius.trifu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0