Curs BGT - Desfasurare

Diverse limbaje, programare, scripting, coduri, unelte specifice etc.
Cornel
Locotenent
Mesaje: 376
Membru din: 02 Iun 2008, 23:17
Localitate: Targu Frumos

diagonala

Mesaj de Cornel »

Desi cele mai multe jocuri de genul acesta merg pe ideea miscarii rectilinii, as sugera sa facem posibila miscarea si pe diagonala; pentru aceasta extindem array-ul simplu cardinale, inserand nord-vest, nord-est, sud-vest si sud-est, asa incat vom avea opt directii. Functia void deplasare() va incrementa pe diagonala fireste ambele coordonate, sau le va decrementa x++, x--, y++ si y--. Ca propunere as zice ca, intrucat impactul cu peretele se face la un unghi de 135 grade, acolo sa fie un fel de frecare plus o deviere: daca se merge spre nord-est, de exemplu, odata ajuns la peretele din nord, y va fi egal cu latime minus unu apare frecarea apoi devierea spre est deci x va continua sa creasca pana cand se ajunge eventual la lovirea frontala a peretelui din est unde e clar ca fiind impact frontal se va opri. La fel, daca directia e tot spre nord-est si lovirea se face de peretele din est, x=lungime-1 frecus si deviere spre nord pana la maximul lui y. In felul acesta se imita situatia din viata reala practic.
Cornel
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

Da, buna idea si usor de implementat.
Practic trebuie sa extindem array-ul cardinale la 9 valori, avand in vedere si 0 care este un string gol.
Ar trebui sa modificam functia modificare_directie() astfel incat incrementarea si decrementarea valorii variabilei directie sa fie intre 1 si 8.
Mergem apoi in functia deplasare unde mai punem 4 if-uri, dupa ce le modificam putin si pe celelalte, practic punctele cardinale directe ar fi la 1, 3, 5, 7, iar cele noi vor fi la 2, 4, 6, 8. Exprimat in string-uri, 1 va fi nord, 2 va fi nord-est, iar 8 va fi nord-vest.

Vezi putin si functia pauza(), acolo ai pus sa se ajunga cu volumul fundalului la 0 in while, practic la fiecare 5 ms se tot seteaza volumul la 0.
Asadar, randul:
fundal.volume=0;
trebuie sa fie deasupra lui while(true), iar dupa inchiderea blocului de cod al while-ului, ar fi bine sa se revina la valoarea -25 a proprietatii volume:
fundal.volume=-25.
Tot ce am sccris mai sus merge atata vreme cat volumul fundalului nu este reglabil.

Poate azi ne ocupam mai mult de adaugarea functiilor propuse, plus deplasarea in 8 directii, clar ca ar fi ceva mult mai bun si mai avansat.
Ne-ar trebui un sunet pentru frecarea de perete, daca e neaparat acest lucru, altfel se poate auzi si lovire normala de perete.

Spun ca maine ar fi bine sa ne ocupam mai mult de cizelare si pentru ca nu prea am timp sa gandesc modul de presarare obiecte si de interactiune cu ele, zilele acestea fiind tabara ICC la Cluj.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Aplicatii practice, partea 3

Mesaj de Manu »

Marti, 24 iulie 2012, ne-am intalnit pentru a paisprezecea oara, intr-o a treia intalnire de aplicatii practice.

Am continuat cu realizarea joculetului nostru si am reusit sa facem deplasarea pe teren mult mai complexa.
De acum, la apasarea sagetilor stanga / dreapta, personajul din joc se intoarce doar cu cate 45 de grade in directia corespunzatoare.
Cu sageata in sus personajul se deplaseaza in directia de la un moment dat, aceasta putand fi chiar diagonala, puncte cardinale intermediare gen nord-est, sud-vest etc.
Cand personajul se loveste de perete deplasandu-se pe diagonala, acesta este deviat in directie corespunzatoare, devierea fiind semnalata sonor printr-un nou sunet inclus si anuntata de JAWS. Daca merge spre nord-est si se loveste de peretele nordic, personajul va fi deviat catre est; daca merge catre sud-est si se loveste de peretele estic, personajul va fi deviat spre sud.

Am adaugat si un fundal care porneste la lansare cu fade-in.

La apasarea tastei p, jocul se pune pe pauza, in acest caz fundalul urcand la maxim cu un fade-in, iar in timpul pauze tot cu tasta p se stabileste continuarea jocului, fundalul coborand la volumul anterior printr-un fade-out.

Apasand tasta i se pot auzi informatii, deocamdata am pus sa anunte marimea salii / terenului.

Mai jos este un ZIP care contine tot ce trebuie pentru ca joculetul in faza lui actuala sa poata fi incercat de oricine, in folderul rezultat in urma extragerii fiind si o varianta compilata (.EXE).

Continuam munca si pe forum, sa vedem ce idei mai vin. Ar fi bine sa gasim un nume pentru joc, avand in vedere ca va fi cu bombe, mine etc.

Un .ZIP care contine intr-un folder tot proiectul in cea de-a treia faza a lui, fisiere de sunet, fisierul .BGT si un .EXE este la link-ul urmator:
Download Fisier ZIP cu intreg proiectul in faza 3, functional cu JAWS

Deschidere doar sursa intr-un fisier .TXT la link-ul urmator:
Sursa fisier TXT cu intreg codul in faza 3

Imprimarea intalnirii de marti, 24 iulie 2012, Aplicatii practice - Partea 3, este la link-ul urmator:
Download Fisier MP3 14._BGT_-_Aplicatii_practice_-_Partea3.mp3 (78,2 MB)
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

A patra intalnire pentru aplicatii practice in BGT

Mesaj de Manu »

Marti, 7 august 2012, ne-am intalnit pentru a cincisprezecea oara, intr-o a patra intalnire de aplicatii practice.

Am continuat cu dezvoltarea jocului.
In faza curenta se poate juca pana la capat, avand feedback pentru castig prin dezamorsarea a 10 mine sau pentru pierdere prin consumarea celor 3 vieti.

Descrierea jocului in faza sa actuala:
Personajul este plimbat pe teren cu sageata sus, iar cu stanga / dreapta ii este schimbata directia.
In orice moment poate nimeri pe o mina, fapt semnalat printr-un sunet putin diferit de cel al pasului normal.
In momentul pasirii pe o mina, aceasta este activata, urmand ca timp de 5 secunde sa se auda o alarma pe pozitie.
Daca se apasa tasta spatiu in decursul celor 5 secunde pe pozitia minei activate, aceasta va fi dezamorsata.
Considerand ca se apasa repede sageata in sus, este foarte probabil ca personajul nostru sa fi trecut de mina, deci trebuie o intoarcere de 180 de grade pentru a reajunge pe pozitia cu mina.
Daca mina nu este dezamorsata la timp cu tasta spatiu, se va auzi o explozie si una dintre cele 3 vieti initiale va fi pierduta.
Se castiga in momentul in care toate cele 10 mine presarate aleatoriu au fost dezamorsate.
Se pierde cand cele 3 vieti au fost consumate.
L anunta numarul de vieti ramase, iar M numarul de mine inca existente pe suprafata.

Asadar am presarat printr-o functie 10 mine aleatoriu astfel incat desi random sa nu existe posibilitatea existentei a doua mine pe acelasi punct.
Voi pune mai jos spre exemplificare functia presarare mine, poate fi un algoritm util:

Cod: Selectaţi tot

/* Variabilele k si l sunt pentru x, respectiv y.
Pe o pozitie oarecare, int 0 inseamna gol, int 1 inseamna mina.
Variabila locala i este pentru a fi siguri ca while-ul merge pana la numarul de mine de presarat. */
void presarare_mine()
{
int i=0;
while(i<nr_mine)
{
int k=random(0, lungime-1);
int l=random(0, latime-1);
if(sala[k][l]==0)
{
sala[k][l]=1;
i++;
}
}
}
Toate sunetele se aud pe pozitia corespunzatoare.
La un moment dat, doar o mina poate fi activata.

Am adaugat eu dupa intalnire o functie verificare_screen_reader() care se va uita din secunda in secunda daca ruleaza vreun screen reader, iar daca da, sa detecteze care este acesta.
Functia spune() va stii de acum sa vorbeasca prin screen reader-ul detectat activ, iar daca nu este vreunul activ, va vorbi prin SApi 5.
Tot dupa intalnire, am impartit tot codul pe fisiere .BGT, astfel incat functiile pentru vorbire sa fie intr-un fisier, cele pentru crearea suprafetei si golirea ei in altul etc, in total sunt acum 6 fisiere >BGT pentru a ne fi mai usor, ajunsese ca .BGT-ul principal sa fie prea lung.

Asadar, va trebui ca toti cei care incearca codul sau care vor continua lucrul pe el sa descarce proiectul in faza lui actuala.

Un .ZIP care contine intr-un folder tot proiectul in cea de-a patra faza a lui, fisiere de sunet, fisierele sursa .BGT si un .EXE este la link-ul urmator:
Download Fisier ZIP cu intreg proiectul in faza 4, functional cu JAWS, Window_Eyes, System Access sau NVDA

Deoarece codul a fost impartit in mai multe fisiere, nu mai pun un link catre sursa intr-un fisier text cum am facut in randurile anterioare..

Continuam sa discutam si pe aici cam ce va fi adaugat in viitor, spunea Cornel sa punem o usa si o cheie pe undeva.
Va trebui in viitor sa fie si limita de timp pentru dezamorsare, diferite grade de dificultate in functie de nivelul la care se ajunge prin parasirea salii pe usa care va fi creata etc.
Vor trebui si sunete mai bune pentru explozie, ceva sunet pentru dezamorsare etc, poate se ocupa Alexandru putin de aceasta problema dupa ce incearca joculetul in faza lui actuala.
Este suficient sa fie inlocuite fisierele din folderul "sunete", cu numele lor actual.

Vom continua cu dezvoltarea jocului, dar nu mai punem fisiere MP3 cu imprimarea intalnirilor, din acest moment lucrul este mai haotic, nu cred sa se poata invata mai mult din imprimari decat studiind codul propriu-zis.
Ultima oară modificat 21 Aug 2012, 16:56 de către Manu, modificat 1 dată în total.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

A cincisprezecea intalnire - aplicatii practice BGT

Mesaj de Manu »

Marti, 14 august 2012 ne-am intalnit din nou si am continuat cu lucrul la joculetul nostru.

In aceasta a cincia intalnire de aplicatii practice, am apucat sa punem aleatoriu prin sala o cheie semnalata sonor la pasirea pe ea. Cheia nu poate fi pe vreuna din margini, in orice situatie va fi cel putin la un pas de oricare perete.

Am montat si o usa care se plaseaza aleatoriu pe unul dintre pereti. Pun mai jos codul pentru plasarea usii, pentru aceasta am ales cel mai simplu algoritm, stabilind intai random pe care perete sa fie usa,a poi tot random unde anume sa fie langa acel perete.

Cod: Selectaţi tot

void plasare_usa()
{
int i=0;
while(i<1)
{
// Declaram k si l, ca variabile omoloage pentru x si y:
int k=0, l=0;

// Usa trebuie sa fie pe una din laturi:
// Determinam intai de toate pe care perete sa fie plasata usa:
int pe_ce_perete=random(1, 4);

// Daca e 1 - nord:
if(pe_ce_perete==1)
{
k=random(0, lungime-1);
l=latime-1;
}

// Daca e 2 - est:
else if(pe_ce_perete==2)
{
k=lungime-1;
l=random(0, latime-1);
}

// Daca e 3 - sud:
else if(pe_ce_perete==3)
{
k=random(0, lungime-1);
l=0;
}

// Daca e 4 - vest:
else if(pe_ce_perete==4)
{
k=0;
l=random(0, latime-1);
}

// Verificam daca e pozitie goala:
if(sala[k][l]==0)
{
sala[k][l]=3; // 3 va insemna usa.
i++;
}
}
}
Asadar functiile plasare_cheie() si plasare_usa() au grija sa plaseze obiectele pe o pozitie goala, cu valoare 0.
Cele doua functii mentionate se gasesc in fisierul 03_suprafata.bgt.

Un .ZIP care contine intr-un folder tot proiectul in cea de-a cincia faza a lui, fisiere de sunet, fisierele sursa .BGT si un .EXE este la link-ul urmator:
Download Fisier ZIP cu intreg proiectul in faza 5, functional cu JAWS, Window_Eyes, System Access, NVDA sau SAPI5

Vom continua cu dezvoltarea jocului.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Proiectul in faza 6

Mesaj de Manu »

Marţi, 28 august 2012, ne-am mai întâlnit încă o dată pentru continuarea jocului nostru, numit în prezent Explorare suprafaţă minată.

Încă nu există un fişier de Ajutor, dar scriu aici un mic tutorial, urmând ca în viitor să îl includem în pachet.

Jocul are 3 nivele de dificultate.
În fiecare nivel "personajul" este aruncat pe o suprafaţă de dimensiuni random, cu o lungime vest - est de vreo 40 paşi, nord - sud de vreo 20 paşi.
Cu săgeată în sus personajul este deplasat în direcţia lui de mers câte un pas la fiecare apăsare.
Direcţia de mers se schimbă cu săgeţile stânga / dreapta.
Există în total 8 direcţii de mers: nord, nord-est, est, sud-est şi aşa mai departe.
La începutul rundei, personajul se află în colţul de sud-vest, pe poziţia 1x1 iar direcţia de mers este nord.

Pe suprafaţă sunt plasate aleatoriu la începutul unui nivel 10 mine care se activează la păşirea pe ele.
Din momentul activării unei mine există un timp limită de dezamorsare.
Undeva există şi o cheie care poate fi luată.
Pe una dintre margini există şi o uşă care poate fi deschisă dacă anterior a fost găsită şi luată cheia.

Dacă sunt dezamorsate cele 10 mine şi încă nu a fost găsită cheia, aceasta este luată automat. Dacă este găsită cheia şi încă nu au fost dezamorsate cele 10 mine, uşa poate fi deschisă şi nivelul este trecut cu succes.

Toate acţiunile (dezamorsare mină, luare cheie, încercare uşă) se efectuează apăsând tasta spaţiu.

Se consideră nivel terminat în momentul deschiderii uşii cu cheia găsită. Aşadar, dacă norocul face să fie găsită cheia înainte de dezamorsarea celor 10 mine, nivelul poate dura mult mai puţin.
Jocul se termină cu victorie în momentul trecerii cu succes de toate cele 3 nivele.

Se consideră înfrângere în momentul pierderii tuturor vieţilor sau în momentul expirării timpului limită disponibil pentru terminarea unui nivel.
O viaţă este pierdută dacă o mină nu este dezamorsată la timp şi explodează.

Lista tastelor disponibile:
- Săgeată în sus - deplasare în direcţia de mers.
- Săgeţi stânga / dreapta - schimbare direcţie de mers.
- Spaţiu - acţiuni pe poziţie.
- D - anunţă direcţia curentă.
- C - anunţă coordonatele poziţiei curente şi ce se află acolo.
- I - spune nivelul curent şi mărimea sălii.
- L - spune numărul de vieţi rămase.
- T spune timpul rămas pentru terminarea rundei.
- P - pune jocul pe pauză.

Diferenţe de nivel:
- Nivelul 1: 5 secunde disponibile pentru dezamorsare, 10 minute disponibile pentru terminare.
- Nivelul 2: 3 secunde disponibile pentru dezamorsare, 7 minute şi jumătate disponibile pentru terminare.
- Nivelul 3: o secundă disponibilă pentru dezamorsare, 5 minute disponibile pentru terminare.


Înainte de a pune link-ul către arhiva cu proiectul, dacă tot e vorba de învăţat ceva, pun mai jos şi un mic algoritm pe care l-am utilizat.

În momentul în care cele 10 mine au fost dezamorsate şi cheia nu a fost găsită, aceasta devine disponibilă ca şi cum am fi luat-o în mână cu tasta spaţiu.
Din acest moment ea nu trebuie să se mai găsească la poziţia ei random, ci trebuie căutată şi ştearsă de acolo.
În array-ul nostru bidimensional de tip int care reprezintă suprafaţa, cheia are valoarea 2, iar o poziţie goală are valoarea 0.
Aşadar, trebuie să găsim unde există valoarea 2 în array şi să punem acolo valoarea 0.

Mai jos este algoritmul de căutare într-un array bidimensional numit sala[][], algoritm aflat în proiect în fişierul 03_suprafata.bgt, în funcţia void eliminare_cheie():

Cod: Selectaţi tot

// k merge pe axa x (vest - est), iar l merge pe axa y (sud / nord):)
for(int k=0; k<lungime; k++)
{
for(int l=0; l<latime; l++)
{
// La fiecare punct se verifică dacă e cheie:
if(sala[k][l]==2)
{
-- Cheia este eliminată prin atribuirea valorii 0 la punctul găsit:
sala[k][l]=0;
break;
}
}
}
Proiectul în faza 6:
Download Fişier ZIP cu întreg proiectul în faza 6

Lansând fişierul .EXE din folderul rezultat la dezarhivare, oricine se poate juca.
Nu am verificat încă dacă valorile sunt bine alese, de exemplu pentru a dezamorsa o mină într-o secundă la nivelul 3 este foarte greu şi probabil ar trebui să fie mărit timpul limită la două secunde. Soluţia ar mai fi să se meargă cu atenţie, astfel încât să nu fie necesară întoarcerea cu 180 de grade, ci imediat după păşirea pe mină să se apese şi spaţiul pentru dezamorsare.

Se va mai lucra şi la design-ul audio.
Vom adăuga şi un cutremur care să arunce personajul de pe poziţia pe care se află, astfel încât uneori să fie bruiată căutarea sistematică de tip linie cu linie.

Aşteptăm sugestii dacă sunt, dacă nu... mergem înainte până va ajunge un pachet de instalare.
Poate are cineva o idee pentru numele final al joculeţului.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Ghita Potra
General de corp de armata
Mesaje: 6070
Membru din: 15 Oct 2007, 12:29
Localitate: Cluj-Napoca

Mesaj de Ghita Potra »

Cum ar fi "Marea Evadare", sau ceva asemănător?
Rezolvaţi online sute de şarade
Puteţi încerca şi Pontes Şarade, o aplicaţie pentru Android cu toate şaradele de pe acest forum
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

Da, un nume in acest gen ar fi bun.
Asa cum ai spus si tu, jocul va trebui sa inceapa cu o poveste: de ce s-a ajuns pe acea suprafata minata?
Ne intalnim inca o data pentru o definitivare a jocului si apoi vedem cine ar putea sa spuna povestea de inceput, apoi il lansam printr-un installer.
Asteptam si de la Alexandru o definitivare a designului audio.
Ne trebuie un cutremur, un sunet de cadere.
De asemenea, unele din sunetele existente ar trebui sa fie schimbate, cel de trecere a unei runde, de pierdere a jocului etc.
In orice caz, nu vom encripta sunetele, nu le impachetam intr-un singur fisier, ci le lasam simple .OGG-uri, astfel incat oricine sa poata face daca are chef un design propriu inlocuind sunetele actuale cu altele.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Vortex
Sublocotenent
Mesaje: 298
Membru din: 19 Noi 2009, 17:12
Contact:

Mesaj de Vortex »

N-am urmarit cu atentie topic-ul, dar mi se pare ca eliminarea cheii se face in mod ineficient. Sugerez salvarea pozitiei cheii atunci cand este plasata. Astfel stergerea ei se poate face dintr-un singur pas, fara cautare. Din cate inteleg, valorile variabilelor globale sunt pastrate, deci se poate face asta.
De acord ca cautarea cheii nu ia prea mult timp, dar cred ca este important sa incercam sa programam cat mai eificient, in special cand plusul de eficienta nu e dificil de implementat.
Vortex Website
Maximum de confort, cu minimum de efort.
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

E totusi greu de spus daca ar fi mai convenabila salvarea cheii la plasare.
Probabil ca alegeam solutia aceasta la un moment dat, dar mergem cu dezvoltarea treptat si atunci includem lucruri pe masura ce ne vin in cap, mai mult pentru a exersa scrierea de cod cu cei care nu au mai programat in trecut.

Asadar, am scris codul pentru gasirea chei in primul rand pentru a vedea un algoritm de cautare intr-un array cu doua dimensiuni.
In viitor jocul va trebui sa poata fi salvat, astfel ar fi fost necesar sa introducem in registri inca o valoare sau sa punem intr-un fisier o valoare sub forma de string care apoi ar fi trebui sa fie interpretata la momentul eliminarii. Aceasta interpretare presupune mai multe actiuni:
- citirea valorii de tip string.
- interpretarea stringului si convertirea in doua valori uint pentru x si y.
Desigur ca daca ar fi jocul salvat, ar trebui si reincarcat si reconstruit spatiul, moment in care s-ar putea memora coordonatele cheii in doua variabile globale la plasarea ei pe fosta pozitie, deci se poate elimina posibilul dezavantaj.

Am putea considera insa ca mentinerea a doua variabile globale de tip uint ar fi iar fara sens cand putem rezolva pe loc problema fara sa ne mai batem capul unde a fost plasata, mai ales ca eliminarea chei intervine mai rar decat neeliminarea cheii, exista sanse de 10 la 1 sa fie gasita cheia inainte de gasirea tuturor celor 10 mine.

In orice caz, de retinut sugestia lui Vortex pentru cei care se vor ocupa de problema, ca o varianta mai simpla din punct de vedere al codului ar fi memorarea pozitiei cheii in momentul plasarii, la fel cum se intampla la activarea unei mine. Acolo a fost necesara memorarea pozitiei minei activate, asta pentru ca este posibil ca personajul sa treaca cu cativa pasi de mina, iar explozia trebuie sa se auda pe pozitia corespunzatoare minei, de asemenea daca personajul se intoarce si incearca sa dezamorseze mina, se verifica daca pozitia lui corespunde cu pozitia minei deja activate.
De asemenea, varianta cu salvarea pozitiei la plasare este, cel putin teoretic mai rapida la eliminare, spun teoretic in sensul ca totul se intampla atat de repede cand se lucreaza cu int-uri, incat proprietatea elapsed a unui timer din BGT ar ramane la 0, asta pentru ca unitatea minima de timp pe care o avem aici este milisecunda.

I-am spus lui Philip acum o vreme ca mi-ar placea sa am si microsecunda exact pentru astfel de teste, dar mai vedem daca o implementeaza candva. :)

Verificarea timpului de rulare pentru diverse lucruri este una dintre placerile mele. :D

Chiar azi m-am jucat putin cu inlocuirea diacriticelor dintr-un text, acelasi cod in C++ si in BGT.
Am mers pe formula verificare pentru fiecare caracter din string-ul cu textul intreg, daca nu cumva este unul dintre caracterele diacritice, iar daca da, sa il inlocuiasca cu corespondentul nediacritic.
AM facut testul pe volumul 2 din Apocalipsul lui Stephen King, un text de aproximativ 1300000 caractere. Am verificat cele 5 diacritice minuscule si majuscule, deci un alt for cu maxim 10 cicluri la fiecare dintre cele 1300000 caractere.
Am tratat string-urile ca pe niste array-uri de caractere.

Rezultatul a fost ca in C++ compilat, tot acest proces dureaza in jur de 100 milisecunde pe calculatorul meu, iar in BGT dureaza in jur de 5 secunde, deci pentru lucrul cu stringuri, BGT este de 50 de ori mai lent decat C++. Pare enorm, dar la calculatoarele din ziua de azi 50 de ori mai lent nu inseamna mult, decat in anumite situatii. Citeam undeva ca Java Script ar fi mai lent de vreo 2000 de ori decat C++, probabil ca era o informatie trantita pur si simplu de cineva, fara a fi sigur ce si cum exact.

Codul meu pentru gasire si inlocuire este:

Cod: Selectaţi tot

// Sirurile de caractere, cate 10 pentru diacritic si nediacritic:
string what="ăîâşţĂÎÂŞŢ";
string with="aiastAIAST";

// Trecere prin tot textul:
for(int x=0; x<text.length(); x++)
{
// Trecere prin sirul de caractere posibile pentru inlocuire:
for(int i=0; i<what.length(); i++)
{
if(text[x]==what[i])
{
text[x]=with[i];
break;
}
}
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
IonPop
Colonel
Mesaje: 2166
Membru din: 02 Oct 2010, 17:55

Mesaj de IonPop »

Intr-adevar, nu se poate generaliza ca un limbaj este de x ori mai rapid sau mai lent decat altul, fiindca pentru anumite operatii diferenta de viteza intre limbaje este foarte mare, iar pentru altele este foarte mica.

Insa atunci cand conteaza viteza de executie, trebuie alesi cei mai potriviti algoritmi pentru ca programul sa ruleze cat mai rapid posibil.
Daca se doreste pur si simplu sa se faca o comparatie intre doua limbaje de programare, se poate folosi intentionat un algoritm care implica multe calcule si care este lent, cum ar fi o functie care genereaza o secventa Fibonacci fara a se folosi implicit sau explicit o optimizare, fiindca atunci comparatia nu ar mai fi relevanta.

De curiozitate am creat un program in Perl care inlocuieste diacriticele din acel fisier, dar folosind un cod mult mai mic si mai elegant:

use File::Slurp;

my $text = read_file('a.txt');

$text =~ tr/ăşţâîĂŞŢÂÎ/astaiASTAI/;

write_file('b.txt', $text);


Acest program citeste fisierul sursa, face inlocuirea ca in programul tau si apoi creaza un fisier in care salveaza rezultatul.
Echivalentul intregului tau program este doar linia care incepe cu $content =~ tr/...

Programul a rulat doar 15 milisecunde pe computerul meu, dar asta fiindca am folosit modulul File::Slurp ca sa citesc si sa scriu continutul fisierelor, insa daca as fi folosit functia interna open(), ar fi durat si mai putin.

Si asta evident, nu fiindca Perl ar fi mai rapid decat C++, ci din cauza ca foloseste un cod mai potrivit pentru astfel de inlocuiri.
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

Cu siguranta exista si in C++ functii pentru string replace mult mai convenabile, alea ar lua probabil cateva milisecunde doar.

Utilizand functia nativa din BGT string_replace(), la mine procesul dureaza doar 190 de milisecunde, deci o diferenta mare fata de cele 5000 de milisecunde necesare la inlocuirea printr-un algoritm mult mai low level din punctul de vedere al codului.
Nu stiu ce s-o fi intampland acolo intern la functiile acestea native, dar diferenta de procesare e mare.

Am auzit ca Perl in general ar fi poate cel mai bun limbaj la lucrul cu stringuri, chiar regular expresions din Perl e un model pentru alte limbaje.
Oricum, codul tau de inlocuire imi pare tare ciudat, pare la prima vedere ca si cum Perl ar avea o sintaxa cu totul aparte. :)

In Perl un string nu se poate comporta ca un Array? As fi curios urmand primul meu cod cat timp ar lua inlocuirea.
Eu am preluat textul din clipboard, mi-a fost lene sa mai salvez romanul in fisier TXT si sa instantiez obiectele pentru citire si scriere.
Am observat de la tine ca in Perl si citirea si scrierea textului dintr-un fisier e foarte high level ca cod, asta dupa ce m-am obisnuit in C++ sa imi bat capul cu ifstream si ofstream.

Pentru cei care urmaresc acest topic si pentru BGT, Codul meu in acest limbaj cu string_replace() este:

Cod: Selectaţi tot

string what="ăîâşţĂÎÂŞŢ";
string with="aiastAIAST";
for(int x=0; x<what.length(); x++)
text=string_replace(text, what[x], with[x], true);
Ultima oară modificat 10 Sep 2012, 00:08 de către Manu, modificat 1 dată în total.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

Daca tot ai amintit de sirul lui Fibonacci, mi-am amintit de un cod pe care l-am scris cu ceva vreme in urma ca sa verific o informatie mentionata de Dan Brown in Codul lui Da Vinci.
Era vorba de Golden Ratio, in romana apare in general tradus ca Numarul de aur, aproximativ 1,618, chestia aia ce apare in multe masuratori, daca imparti lungimea distantei de la sold la talpa la lungimea distantei dintre genunchi si talpa,, numarul de femele dintr-un stup la numarul de masculi etc.

Ei bine, acest raport poate fi gasit si in sirul lui Fibonacci, daca un numar din sir este impartit la anteriorul, rezultatul tinde sa fie tot 1,618.
Am facut o medie pentru rezultatele impartirii primelor 1475 perechi din sir si intr-adevar, rotunjit la 3 zecimale media este 1,618, cu 4 zecimale media este 1,6178. Am mers doar pana la 1475 pentru ca acolo era cel mai mare numar din sir pe care il permitea un double din BGT.

Am pus la codul acela un cronometru si tot calculul dureaza in jur de doar o milisecunda, deci nu prea pot face verificari.

Pe site la Blastbay este codul, la primul heading din pagina care se deschide:
Fibonacci code and doubles

Probabil ca pentru teste ar trebui ceva calcule si mai complexe, ceva care sa se invarta mai mult, astfel incat valorile sa nu iasa din limitele de stocare ale variabilelor.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
IonPop
Colonel
Mesaje: 2166
Membru din: 02 Oct 2010, 17:55

Mesaj de IonPop »

Da, cu siguranta ca Perl este cel mai bun limbaj pentru lucrul cu stringuri, si nu doar datorita celui mai puternic motor de regular expressions care este imbunatatit incontinuu, ci si datorita altor functii si module care se pot instala cu o singura comanda.

Banuiesc ca linia care ti-a parut ciudata este:
$text =~ tr/ăşţâîĂŞŢÂÎ/astaiASTAI/;

Este intr-adevar o functie mai atipica, cum sunt in general functiile care au de a face cu regular expressions, desi tr nu este folosita tocmai pentru regular expressions. De fapt in Perl exista doar 3 astfel de functii, una se numeste "tr", alta "s" si alta "m" si toate se folosesc impreuna cu operatorul "=~" sau "!~". In rest, restul functiilor nu folosesc acest operator care pare si el cam ciudat, si au denumiri normale si se apeleaza ca toate functiile cu nume_functie() sau chiar fara paranteze, ca de exemplu print "ok".

Exista cateva functii in Perl pentru care delimitatorii de grupare a parametrilor lor nu trebuie sa fie neaparat paranteze si acesta este si cazul acestor 3 functii.

In cazul functiei tr care inseamna translate, se inlocuiesc caracterele de la primul / pana la al doilea, cu caracterele dintre al doilea / si al treilea, iar dupa al treilea / se pot optional adauga unele caractere care modifica modul de lucru al functiei.
Se pot adauga si elemente folosite in regular expressions, de exemplu sa spui sa inlocuiasca literele de la a la z, folosind a-z ca in regular expressions, dar tr nu permite toate facilitatile regular expressions.
Doar ca in loc de / se poate folosi un alt caracter de despartire, cum ar fi de exemplu caracterul |. Acest lucru este util daca printre caracterele care trebuie sa fie inlocuite se afla si caracterul /, fiindca nu mai trebuie sa se adauge un \ inaintea lui.
Sau se pot folosi paranteze, sau acolade, sau caractere < si >, ca de exemplu:
tr<abc><xyz>;
tr{abc}{xyz};

Sau se pot folosi doua tipuri diferite de caractere de grupare:
tr{abc}<xyz};
tr(abc){xyz};

Si nici nu trebuie sa fie pe acelasi rand:
tr{abc}
(xyz);

Perl este foarte liberal. Poti scrie in multe feluri, si vor functiona.

Functia s seamana cu tr si se foloseste pentru inlocuire folosind regular expressions. Este o singura functie pentru inlocuire, care poate accepta si ea modificatori, si ea poate separa expresia care trebuie inlocuita de ceea ce trebuie inlocuit cu paranteze, acolade, <>, |...

Iar functia m este folosita pentru "match" adica pentru a cauta ceva cu regular expressions, si se poate chiar omite, adica in loc sa se scrie m// sa se foloseasca doar //, ca de exemplu:

if ( $variabila =~ /cucu/ ) {
print "variabila contine textul 'cucu'";
}

Este ca si cum s-ar fi scris if ( $variabila =~ m/cucu/ ) {...}

Functia m se foloseste neaparat doar cand se aleg ca delimitatori alte caractere decat /.

Nu, in Perl cu un string nu se poate lucra ca si cu un array. Pentru a lucra cu un array, trebuie creat un array, splitand stringul cu split();

my @array = split( //, $string );

sau fara paranteze:
my @array = split //, $string;

Daca se foloseste //, deci fara nimic intre ele, nu se spliteaza in functie de un sir de caractere sau de o expresie regulata dintre //, ci fiecare caracter va deveni elementul array-ului.

Am facut un test si cu codul scris de tine, iar ca viteza este cam ca in BGT. De obicei ii ia 5 secunde, iar uneori 5.08 sau pe acolo.

Codul este:

use File::Slurp;

my $text = read_file('a.txt');
my $what = "ăîâşţĂÎÂŞŢ";
my $with = "aiastAIAST";

my @text = split //, $text;
my @what = split //, $what;
my @with = split //, $with;

for my $x ( 0 .. $#text ) {
for my $i ( 0 .. $#what ) {
if( $text[$x] eq $what[$i] ) {
$text[$x] = $with[$i];
next;
}
}
}

write_file('b.txt', join('', @text ));

Citirea si scrierea fisierelor este atat de high level doar fiindca am folosit modulul File::Slurp.

Daca ar fi trebuit sa folosesc functia open() ar fi cerut mai mult cod, de exemplu:

open my $f, '<', 'file.txt';
local $/;
my $content = <$f>;
close $f;

Ma rog, se poate si fara close() fiindca fisierul se inchide automat cand iese din context sau cand se inchide programul.

Daca un limbaj foloseste o optimizare just in time in mod implicit, cum este cazul Java de exemplu, daca o functie este apelata de mai multe ori tot cu aceiasi parametrii, el salveaza rezultatul in memorie, iar a doua oara functia nu mai este apelata ci se preia rezultatul salvat. Astfel se consuma mai multa memorie, dar calculul se face mai rapid. De aceea am spus ca ar trebui sa nu se foloseasca optimizari implicite sau explicite pentru ca calculul secventelor Fibonacci sa poata fi utilizat pentru comparatii.
In Perl se poate folosi modulul Memoize si el face acelasi lucru, asa ca orice calcul Fibonacci dureaza extrem de putin.
Avatar utilizator
Manu
General de divizie
Mesaje: 4120
Membru din: 02 Feb 2007, 01:15
Localitate: Cluj-Napoca
Contact:

Mesaj de Manu »

Interesante toate amanuntele despre Perl.
Am retinut modul de declarare a unei variabile, probabil locale, cu myh in fata si utilizarea semnului $ ca si in PHP sau AutoIt. E diferit modul de declarare al unui array, cu @ in fata.
Inteleg ca next este echivalentul instructiunii break din C++. iar eq inseamna ==. In autoit next era utilizat pentru inchiderea for-ului, nu pentru spargerea lui.
Ma tot intreb, cum se hotarasc creatorii de limbaje ce nume si semne sa foloseasca pentru diversele instructiuni, probabil ca unii au fost obisnuiti cu alte limbaje inainte si au preluat cam ce li s-a parut mai clar sau cea cu ce s-au obisnuit mai tare.
Nu stiu unde am citit despre o alta proprietate interesanta in Perl, posibilitatea de a atribui unei variabile globale o valoare locala, care sa tina doar intr-un bloc de cod, dupa care sa revina la valoarea din faza globala dinainte. Stiu ca la jocul de table mi-ar fi trebuit o astfel de facilitate pentru a scrie mai pe scurt ceva, dar pentru a rezolva problema am declarat alte variabile locale.
Errare humanum est, sed perseverare diabolicum...
In forum linguae Latinae venite! (via est: www.limbalatina.ro)
Scrie răspuns