Jump to content
  • 0

pomoc Náhodné otázky + dané odpovědi


ForestCZE

Dotaz

Ahoj, mám takový problém. Snažím se udělat losování otázek se správnými odpověďmi. Nějak jsem to sesmolil, ale přijde mi to krkolomné a stále mi něco říká, že by to šlo lépe.

 

new question[20][1000]; //u té tisícovky si nejsem jistý, jestli je to v pořádku, ale toho textu je celkem dost
new answer[20][2]; //tady také nevím, ale když bude ve stringu např. "a", tak by to mělo stačit
Spoiler

question[0] = "Otázka číslo 1\nA) ano\nB) ne\nC) nevim";
question[1] = "Otázka číslo 2\nA) ano\nB) ne\nC) nevim";
question[2] = "Otázka číslo 3\nA) ano\nB) ne\nC) nevim";
question[3] = "Otázka číslo 4\nA) ano\nB) ne\nC) nevim";
question[4] = "Otázka číslo 5\nA) ano\nB) ne\nC) nevim";
question[5] = "Otázka číslo 6\nA) ano\nB) ne\nC) nevim";
question[6] = "Otázka číslo 7\nA) ano\nB) ne\nC) nevim";
question[7] = "Otázka číslo 8\nA) ano\nB) ne\nC) nevim";
question[8] = "Otázka číslo 9\nA) ano\nB) ne\nC) nevim";
question[9] = "Otázka číslo 10\nA) ano\nB) ne\nC) nevim";
question[10] = "Otázka číslo 11\nA) ano\nB) ne\nC) nevim";
question[11] = "Otázka číslo 12\nA) ano\nB) ne\nC) nevim";
question[12] = "Otázka číslo 13\nA) ano\nB) ne\nC) nevim";
question[13] = "Otázka číslo 14\nA) ano\nB) ne\nC) nevim";
question[14] = "Otázka číslo 15\nA) ano\nB) ne\nC) nevim";
question[15] = "Otázka číslo 16\nA) ano\nB) ne\nC) nevim";
question[16] = "Otázka číslo 17\nA) ano\nB) ne\nC) nevim";
question[17] = "Otázka číslo 18\nA) ano\nB) ne\nC) nevim";
question[18] = "Otázka číslo 19\nA) ano\nB) ne\nC) nevim";
question[19] = "Otázka číslo 20\nA) ano\nB) ne\nC) nevim";

answer[0] = "a";
answer[1] = "a";
answer[2] = "c";
answer[3] = "b";
answer[4] = "c";
answer[5] = "b";
answer[6] = "a";
answer[7] = "c";
answer[8] = "b";
answer[9] = "b";
answer[10] = "a";
answer[11] = "a";
answer[12] = "c";
answer[13] = "a";
answer[14] = "c";
answer[15] = "b";
answer[16] = "a";
answer[17] = "a";
answer[18] = "c";
answer[19] = "c";

Pak potřebuju náhodně vybrat 5 otázek z 20 tak, aby se ve výběru žádná neopakovala:

new allot[5];

for(new i = 0; i < 5; i++)
{
	allot[i] = random(19);
	//nevím, jak sestavit podmínku, aby to opravdu hodilo znovu random pokud to na nějakém indexu 0-4 najde stejné číslo
}

Pak uložím hráči do proměnné správné odpovědi, abych je později mohl porovnat s těmi, které zadal (v jiném dialogu):

new correctanswer[MAX_PLAYERS][5][2]; //opět nevím, jestli stačí dva znaky pro "a"
correctanswer[playerid][0] = answer[allot[0]];
correctanswer[playerid][1] = answer[allot[1]];
correctanswer[playerid][2] = answer[allot[2]];
correctanswer[playerid][3] = answer[allot[3]];
correctanswer[playerid][4] = answer[allot[4]];
//toto by se také dalo přidat do toho cyklu?

Pak to vypíšu do dialogu:

new allquestions[1000]; //opět délka - to číslo mě děsí a zdá se mi, že i pawno déle compiluje
format(allquestions, sizeof(allquestions), "1. %s", question[allotq[0]);
format(allquestions, sizeof(allquestions), "%s2. %s", allquestions, question[allotq[1]]);
format(allquestions, sizeof(allquestions), "%s3. %s", allquestions, question[allotq[2]]);
format(allquestions, sizeof(allquestions), "%s4. %s", allquestions, question[allotq[3]]);
format(allquestions, sizeof(allquestions), "%s5. %s", allquestions, question[allotq[4]]);
ShowPlayerDialogEx(playerid, 0, DIALOG_STYLE_INPUT, "Otázky", allquestions, "Odeslat", "Ukončit");

A nakonec zkontroluju odpovědi, když zadám do inputtextu např. a,b,c,a,c

new questionout[][]; //tady nevím, jak to bude s velikostmi - myslím, že v prvním poli bude 5 jako pět částí stringu a u druhého nevím
questioncount = strexplode(questionout, inputtext, ","); //include strlib
if(questioncount != 5) return SCM //špatný formát

//A porovnání
if(questionout[0][0] == correctanswer[playerid][0][0]) //ta nula v druhém pole u každé podmínky je dobře? Řvalo to, že array must be indexed a snad to i funguje, ale...
{
	//Odpověď na otázku číslo 1 je správně
}

if(questionout[1][0] == correctanswer[playerid][1][0])
{
	//Odpověď na otázku číslo 2 je správně
}

if(questionout[2][0] == correctanswer[playerid][2][0])
{
	//Odpověď na otázku číslo 3 je správně
}

if(questionout[3][0] == correctanswer[playerid][3][0])
{
	//Odpověď na otázku číslo 4 je správně
}

if(questionout[4][0] == correctanswer[playerid][4][0])
{
	//Odpověď na otázku číslo 5 je správně
}

Je to snad vše :)

 

Jde mi o:

1) Je tohle efektivní řešení? Nevynalézám kolo?

2) Pomoc s věcmi, u kterých opravdu nevím (viz popisky)

 

Dal jsem si s tím opravdu práci, abych vše popsal, o co jde a mohli jsme to společně vyřešit, tak i pevně věřím, že se najde někdo ochotný, kdo si dá práci to projít a pomůže mi. Děkuji předem za pomoc všem :)

Link to comment
Share on other sites

6 odpovědí na tuto otázku

Recommended Posts

  • 0

Plánuješ s tými otázkami ďalej v GM pracovať (upravovať/meniť ich)? Ak nie, spravil by som ich pomocou funkcie a returnu - nespotrebuješ toľko pamäti.

stock GetQuestion(id)
{
	new str[]; // tu nemusíš mať číslo 1000, proste zober najdlšiu otázku a spočítaj kolko sa v nej nachádza znakov
	switch(id)
	{
		case 0: str = "Otázka1";
		case 1: str = "Otázka2";
		//atď...
		default: str = "Otázka neexistuje!";
	}
	return str;
}
stock GetAnswer(id)
{
	new str[2];
	switch(id)
	{
		case 1: str = "a";
		case 2: str = "c";
		//atď...
		default: str = "0";
	}
}

No, aby sa otázka neopakovala, musíš prekontrolovať všetky doteraz dosadené otázky ;)

new allot[5];

for(new i = 0; i < 5; i++)
{
  	new bool:corr_question; // kontrolná podmienka aby cyklus vedel že má skončiť
	while(!corr_question) // cyklus sa bude opakovať až pokial corr_question == true
    {
		allot[i] = random(19);
      	corr_question = true; // POZOR! TRUE musíš nastaviť až tu, ak ho nastavíš pri deklarácií, cyklus while sa nespustí
      	for(new a=0;a<i;a++) // spustíme cyklus od 0 po i (tj. ak si na 4 otázke tak cyklus prebehne pre čísla 0,1,2,3)
        {
          	// PS: cyklus v cykle v cykle (ano 3 cykly) nepoužívaj bez premýšlania! Toto sú nízke hodnoty, ale keby dáš for pre 50 a 3x do seba, tak máš 125 000 opakovaní, tak pozor na to
          	if(allot[a] == allot[i]) corr_question = false; // nastavíme na false pretože táto otázka už existuje
        }
    }
}
Citace

Pak uložím hráči do proměnné správné odpovědi, abych je později mohl porovnat s těmi, které zadal (v jiném dialogu):

A musíš ich ukladať? :o Ďalej s nimi nijak nepracuješ, naviac sú obsiahnuté už v jednej premennej (u mňa vo funkcií) takže zbytočné vytvárať novú

 

Takto by som upravil vypisovanie otátok.

new allquestions[]; // toto číslo si nastav na 5x dĺžku definovanú vo funkcii GetQuestion
for(new i=0;i<5;i++)
{
	format(allquestions, sizeof(allquestions), "%s%d. %s\n", allquestions,i, GetQuestion(allot[i]));
}
ShowPlayerDialogEx(playerid, 0, DIALOG_STYLE_INPUT, "Otázky", allquestions, "Odeslat", "Ukončit");

No a nakoniec k porovnaniu.

new questionout[5][2]; //tady nevím, jak to bude s velikostmi - myslím, že v prvním poli bude 5 jako pět částí stringu a u druhého nevím
questioncount = strexplode(questionout, inputtext, ","); //include strlib
if(questioncount != 5) return SCM //špatný formát
// k funkcii strexplode sa ti nevyjadrím, lebo som ju nikdy nepoužil, ale ak by robila problém tak použi sscanf2
for(new i=0;i<5;i++)
{
 	if(!strcmp(questionout[i], GetAnswer(allot[i]), true))
    {
     	// Odpoveď na otázku č.%d je správna... 
    } else // odpoveď je nesprávna
}

 

Podľa môjho názoru je to takto jednoduchšie, nevytváraš zbytočne veľké polia a taktiež nemusíš do zblbnutia opakovať rovnaké podmienky (nahradené cyklami)

Edited by Quiter
Link to comment
Share on other sites

  • 0

 

před 5 hodinami, Quiter said:

Plánuješ s tými otázkami ďalej v GM pracovať (upravovať/meniť ich)?

Určitě budu přidávat celkový počet, ale losovat jich to bude vždycky 5. Co by se zásadně změnilo, kdybych to nějak upravoval?

 

před 5 hodinami, Quiter said:

for(new a=0;a<i;a++) // spustíme cyklus od 0 po i (tj. ak si na 4 otázke tak cyklus prebehne pre čísla 0,1,2,3)

Pokud mám těch otázek 5, nemělo by to proběhnout ještě pro číslo 4?

 

před 5 hodinami, Quiter said:

A musíš ich ukladať? :o Ďalej s nimi nijak nepracuješ, naviac sú obsiahnuté už v jednej premennej (u mňa vo funkcií) takže zbytočné vytvárať novú

No asi nemusím, tady jsem zmaten :d

 

Děkuju moc, dává to smysl a vypadá to pěkně. Zkusím to pochopit a použít a ještě budu když tak reagovat později :) 

Edited by ForestCZE
Link to comment
Share on other sites

  • 0
před 9 hodinami, ForestCZE said:

Pak potřebuju náhodně vybrat 5 otázek z 20 tak, aby se ve výběru žádná neopakovala:


new allot[5];

for(new i = 0; i < 5; i++)
{
	allot[i] = random(19);
	//nevím, jak sestavit podmínku, aby to opravdu hodilo znovu random pokud to na nějakém indexu 0-4 najde stejné číslo
}

 

 

Asi cyklom pozrieť, či sa už tá otázka nevybrala.. A potom vygenerovať inú.

--

Čo sa týka celkového riešenia, ak odpoveď je vždy len jeden znak (A/B/C), tak na uloženie správnej odpovede nepotrebuješ ďalšie pole.
Môžeš správnu odpoveď uložiť na začiatok každej otázky, :

question[0] = "aOtázka číslo 1\nA) ano\nB) ne\nC) nevim"; // vsimni si prvy znak v stringu; spravna odpoved je a)

Následne pri zadaní otázky hráčovi dáš:
 

#define ShowPlayerQuestion(%0,%1) ShowPlayerQuestionEx(%0,%1[1]) // pri zobrazeni preskoc prvy znak (odpoved)
// nieco na tento styl, neviem ako to zobrazuješ hracovi
// ShowPlayerQuestion(playerid, questionString);

Odpoved potom kontroluješ cez
 

if (playersAnswer[0]) == playerQuestion[0][0]) // ak jeho odpoved (znak) == prvemu znaku v stringu otazky

 

Link to comment
Share on other sites

  • 0
před 1 hodinou, Tanga said:

Asi cyklom pozrieť, či sa už tá otázka nevybrala.. A potom vygenerovať inú.

To bych moc nedoporučoval, jednou jsem tak shazoval omylem server (nešlo přímo o otázky a odpovědi).

Lepší by bylo asi pole zamíchat (shuffle) a vybrat otázky z toho, případně jiné řešení.

 

// EDIT: Čím víc odpovědí máš vybráno, tím je větší pravděpodobnost, že se při dalším náhodném výběru trefíš do již vybrané odpovědi a znovu se začne vybírat náhodná odpověď. Tím může dojít k zacyklení a pádu.

Edited by Lukasz
Link to comment
Share on other sites

  • 0

Jo toto se mi libi, sice jsem nejak moc peclive necetl komenty, ale udelal jsem svuj zpusob reseni:

 

#include <a_samp>

#define RANDOM_OTAZEK       5

new Otazky[][] = {//neni potreba vyplnovat, compiler si doplni sam podle obsahu pole (new string[sizeof(Otazky[])]; <- vytvoris string tak, aby se ti tam vesla nejdelsi otazka)
	"Otazka 1",
	"Otazka 2",
	"Otazka 3",
	"Otazka 4",
	"Otazka 5",
	"Otazka 6",
	"Otazka 7",
	"Otazka 8",
	"Otazka 9",
	"Otazka 10"
};

new Odpovedi[sizeof(Otazky)][] = {//opet neni potreba zadavat rozmery, je to udelane tak ze odpoved muze mit i vic nez jedno pismeno. (Pro sychr "sizeof(Otazky)" aby ti compiler zarval, pokud bude jiny pocet odpovedi nez otazek)
	"a",
	"a",
	"a",
	"a",
	"a",
	"a",
	"a",
	"a",
	"a",
	"a"
};

stock VylosujOtazky(otazky[])
{
	new index,nahoda[sizeof(Otazky)] = {0,1,2,...};
	for(new i;i<RANDOM_OTAZEK;i++)
	{
		index = random(sizeof(Otazky)-i);//random na danou otazku (ale vybira jen ze zacatku pole, protoze na konec uklada jiz vylosovane - zajisti se tak unikatnost)
		otazky[i] = nahoda[index];//ulozime vylosovane cislo
		//nahoda[sizeof(Otazky)-1-i] = nahoda[index];//na misto na konci pole ulozime vylosovanou hodnotu (neni treba pouzit, protoze vysledek ukladame uz nahore)
		nahoda[index] = sizeof(Otazky)-1-i;//a na vylosovany prvek presuneme hodnotu z konce pole
	}
	return 1;
}

stock KontrolaOdpovedi(playerid,otazky[],odpovedi[][])
{
    new string[144];
	for(new i;i<RANDOM_OTAZEK;i++)
	{
		if(odpovedi[i][0] && strcmp(Odpovedi[otazky[i]],odpovedi[i],true) == 0)
		{
			format(string,sizeof(string),"Otázka %s odpovezena správně",Otazky[otazky[i]]);
			SendClientMessage(playerid,-1,string);
			print(string);
		}
		else
		{
			format(string,sizeof(string),"Otázka %s odpovezena špatně",Otazky[otazky[i]]);//správná odpověď: "Odpovedi[otazky[i]]" vaše odpověď: "odpovedi[i]" blabla...
			SendClientMessage(playerid,-1,string);
			print(string);
		}
	}
	return 1;
}

public OnFilterScriptInit()
{
	new otazky[RANDOM_OTAZEK];
    VylosujOtazky(otazky);
    for(new i;i<sizeof(otazky);i++) printf("%d) %d",i,otazky[i]);
    
    new playerid = 0;//prasarna nepouzvat !!! ale pro ten priklad...
    
    new odpovedi[][] = {//popripade "new odpovedi[MAX_PLAYERS][][];" a do funkce dole dat "odpovedi[playerid]"
		"a",
		"n",
		"a",
		"n",
		"a"
	};
    KontrolaOdpovedi(playerid,otazky,odpovedi);
    
	return 1;
}

Myslim ze myslenka je vystizena, implementovat to a dodelat tomu dialogy uz je hracka :)

Edited by ATomas
Link to comment
Share on other sites

  • 0
před 11 hodinami, ForestCZE said:

 

Určitě budu přidávat celkový počet, ale losovat jich to bude vždycky 5. Co by se zásadně změnilo, kdybych to nějak upravoval?

 

Pokud mám těch otázek 5, nemělo by to proběhnout ještě pro číslo 4?

 

No asi nemusím, tady jsem zmaten :d

 

Děkuju moc, dává to smysl a vypadá to pěkně. Zkusím to pochopit a použít a ještě budu když tak reagovat později :) 

•  No pridávať ich budeš tak či tak cez pawno a nie nejakým ingame príkazom, takže byť tebou, nechám to cez funkciu :d

• Nie, pre číslo 4 to nie je nutné, pretože číslo 4 je posledná otázka, takže nemá zmysel aby porovnávalo samo seba (tj. otázka č.4 porovná otázku 0,1,2 a 3)

• Nemusíš... Keď sa pozrieš na môj kód tak na záver používam premennu allot[] ktorú si definoval pri náhodnom výbere otázky - každopádne by som si to upravil aby táto premenná obsahovala parameter PLAYERID, alebo bude mať celý server rovnaké otázky?

• Ak by ti niečo nebolo jasné tak napíš sem alebo do PM

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...