Sugestii de programare pentru 4-poker

From Algopedia
Revision as of 13:19, 9 April 2015 by Cata (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Iată câteva sugestii pentru a vă testa mai ușor programele.

Folosiți un fișier de intrare

Programul vostru trebuie să citească datele de la intrarea standard, dar asta nu înseamnă că este obligatoriu să le tastați de la tastatură. Puteți crea un fișier cu pachetul de cărți, să spunem deck.in. Apoi puteți executa programul cu intrarea redirectată din fișier. În GNU/Linux, aceasta se face tastând într-un terminal comenzile:

cd /calea/spre/programul/meu
./programul_meu < deck.in

Dacă folosiți Code::Blocks, îl puteți configura să execute programul cu intrarea din fișier, nu de la tastatură. (Nu știu sigur cum; dacă cineva știe, spuneți-mi ca să actualizez pagina aici.)

Generați, în buclă, multe fișiere de intrare

Pentru a vă face o idee despre calitatea strategiei voastre, va trebui să o testați pe sute sau mii de pachete. Iată o soluție (sub GNU/Linux) care necesită modificări minore în program.

În primul rând, faceți programul vostru să-și calculeze singur scorul și să-l tipărească la stderr. Astfel, veți putea rula programul într-o buclă ca să adunați scorurile raportate.

...
fprintf(stderr, "%d\n", scor);
...

În al doilea rând, scrieți-vă un generator de date de intrare în formatul corect. N-ar trebui să fie prea greu.

În final, rulați într-o buclă generatorul și programul vostru și calculați scorul mediu. Iată o comandă bash pe o singură linie.

games=10; sum=0; for i in `seq 1 $games`; do ./generator > deck.in; output=`./programul_meu < deck.in 2>&1 >/dev/null`; echo jocul $i: scor $output; sum=$(($sum+$output)); done; echo media: $(($sum/$games))

Sau, ca să arate mai bine, puteți crea un fișier shell, să zicem driver.sh (nu uitați să-l faceți executabil cu chmod 755 driver.sh).

#!/bin/bash
games=10
sum=0

for i in `seq 1 $games`
do
    ./generator > deck.in
    output=`./player < deck.in 2>&1 >/dev/null`
    echo jocul $i: scor $output
    sum=$(($sum+$output))
done

echo media: $(($sum/$games))

Sintaxa Bash este destul de ușor de înțeles. Două lucruri sunt mai obscure:

  • Sintaxa 2>&1 >/dev/null redirectează ieșirea standard (1) către /dev/null, adică o ignoră, și redirectează ieșirea de eroare (2) către cea standard (1).
  • Operatorii `comandă` (numite apostrofuri inverse sau backticks) evaluează comanda dintre ele și returnează ieșirea ei standard. În cazul nostru, returnează mesajul tipărit la stderr, adică scorul.

Generați-vă pachetul chiar în program

Puteți face chiar programul vostru să genereze pachete aleatoare în loc să le citească. Atunci programul vostru poate să ruleze singur sute de seturi de date și să-și calculeze scorul mediu.

Dezavantajul este că programul trebuie modificat înainte să mi-l trimiteți. Plus că nu aceasta este calea GNU/Linux. :-) Sub GNU/Linux, preferăm programe modulare, care fac exact ceea ce-și propun să facă și nimic mai mult. Peste ele folosim scripturi și comunicare inter-programe pentru a calcula date la un nivel mai înalt.

Folosiți dealerul și arbitrul

Dacă vreți să învățați ceva nou, iată cum se va face jurizarea. În secțiunea Descărcări veți găsi un program-dealer și un program-arbitru.

Dealerul:

  • Generează un pachet (la concursul propriu-zis, dealerul va citi pachetul dintr-unul din cele 500 de fișiere).
  • Afișează prima carte la ieșirea standard.
  • Așteaptă un răspuns între 1 și 4 la intrarea standard și îi verifică corectitudinea.
  • Afișează a doua carte.
  • etc.
  • Dacă au apărut erori, scrie în fișierul game.dat mesajul de eroare.
  • Altfel, scrie în fișierul game.dat istoria jocului și scorul obținut.

Arbitrul:

  • Primește ca parametri un program-dealer și un program-jucător.
  • Lansează programele.
  • Redirectează ieșirea standard a dealerului la intrarea standard a jucătorului și invers.
  • Rulează ambele programe până când jucătorul se termină.
  • Dacă dealerul a creat fișierul game.dat îl copiază în locul specificat.
  • Altfel îl creează cu mesajul de eroare „timp depășit”.

După ce vă scrieți programul-jucător, puteți lansa totul cu comanda

php arbiter.php -p player -d dealer -o fisier_iesire.out

Descărcări

La http://catalin.francu.com:/tmp/4-poker am pus o arhivă cu diverse fișiere. Uitați-vă cel puțin peste player.cpp.

  • player.cpp: Un model rudimentar de jucător. Are o ordine prestabilită a cărților, indiferent ce îi vine din pachet. Evident, voi trebuie să implementați logica.
  • dealer.cpp: Un model de dealer. Această versiune amestecă un pachet și tipărește cărțile una câte una. La concursul propriu-zis dealerul va citi cărțile dintr-un fișier.
  • arbiter.php: Un model de arbitru. El rulează un dealer și un jucător, redirectând intrarea unuia la ieșirea celuilalt și invers.
  • visual-ansi.cpp: Un browser de partide. El știe doar să afișeze fișierul game.dat, folosind culori ANSI și simboluri Unicode.