Jak zrobić, aby pytania się nie powtarzały?

0

Mam grę milionerzy.
Pytania wyglądają tak:

void pytanie1()
{
   if( !wyswietlZawartosc( "pytania/1.txt" ) )
         cout << "Nie udalo sie otworzyc pliku o podanej nazwie." << endl;
         char odp=0;
         cin>>odp;
         if(odp != 'd')
			{	
				system("cls");
				sprawdzstatus();
				getch();
		 	}
}

Losowanie pytań tak:

int losuj()
{
    srand(time(NULL));
    int losowa = std::rand() % 32 + 1;
}
int wylosowano(int losowa)
{
    if (losowa == 1) {
        pytanie1();
    }
    else if (losowa == 2) {
        pytanie2();
    }
    else if (losowa == 3) {
        pytanie3();
    }
    else if (losowa == 4) {
        pytanie4();
    }
    else if (losowa == 5) {
        pytanie5();
    }
    else if (losowa == 6) {
        pytanie5();
    }
    else if (losowa == 7) {
        pytanie7();
    }
    else if (losowa == 8) {
        pytanie8();
    }
    else if (losowa == 9) {
        pytanie9();
    }
    else if (losowa == 10) {
        pytanie10();
    }
    else if (losowa == 11) {
        pytanie11();
    }
    else if (losowa == 12) {
        pytanie12();
    }
    else if (losowa == 13) {
        pytanie13();
    }
    else if (losowa == 14) {
        pytanie14();
    }
    else if (losowa == 15) {
        pytanie15();
    }
    else if (losowa == 16) {
        pytanie16();
    }
    else if (losowa == 17) {
        pytanie17();
    }
    else if (losowa == 18) {
        pytanie18();
    }
    else if (losowa == 19) {
        pytanie19();
    }
    else if (losowa == 20) {
        pytanie20();
    }
    else if (losowa == 21) {
        pytanie21();
    }
    else if (losowa == 22) {
        pytanie22();
    }
    else if (losowa == 23) {
        pytanie23();
    }
    else if (losowa == 24) {
        pytanie24();
    }
    else if (losowa == 25) {
        pytanie25();
    }
    else if (losowa == 26) {
        pytanie26();
    }
    else if (losowa == 27) {
        pytanie27();
    }
    else if (losowa == 28) {
        pytanie28();
    }
    else if (losowa == 29) {
        pytanie29();
    }
    else if (losowa == 30) {
        pytanie30();
    }
    else if (losowa == 31) {
        pytanie31();
    }
    else {
        pytanie32();
    }
}

Użycie pytania w programie tak (w main) :

///pytanie 1 za 500
			statuspytania= 500;
		    status500();
		    wylosowano(losuj());
			system("cls");
			//kontynuuj();
///pytanie 2 za 1 000
			statuspytania= 1000;
		    status1000();
		    wylosowano(losuj());
		    system("cls");

Jak zrobić aby pytania się nie powtarzały?
(za mało danych, piszcie to wkleję co potrzebne, nie wklejałem całości bo 1000 linijek+pliki txt)

Drugą sprawą jest jak w przypadku błędnej odpowiedzi powrócić do menu głównego?
Bo obecnei jak źle odpowiemy na pytanie to wyswietli sie info ze przegralismy, ale i tak mozna grac dalej.

4

o_O

  1. srand() wykonaj tylko na początku programu w main, a nie przed każdym losowaniem
  2. Czy gdyby pytań było np. 1000 to też byś to tak zrobił za pomocą copy-paste? ;]
1

Wklejaj kod w znaczniki C++. Podeślij cały kod. Ta drabinka 32 ifów jest okropna.

  1. Jest nieskończenie wiele sposobów. Brzydkie, słabo rozszerzalne ale działające rozwiązanie to np.: możesz do każdego pytania zrobić bool CzyByloX = false;. Srand losuje jakąś liczbę np. 16, po wylosowaniu sprawdza czy bool CzyBylo16 == true;. Jeśli true, to nie wywołujesz pytanie16();. Jeśli false, to callujesz pytanie16(); i ustawiasz tego boola na true. Ale lepiej zrobić jedną funkcję za to odpowiedzialną zamiast tworzyć pińćset booli.
  2. Stwórz jakiś bool GameFinished. Wykonuj losowanie (i wyświetlanie, itd.) pytań tylko jeśli GameFinished jest false. Jeśli odpowie się błędnie na pytanie, ustaw GameFinished na true.
bool GameFinished = false;
...
while ( ! GameFinished) {
// losowanie
// wyświetlanie
// itd
}

Ogólnie poczytaj więcej o funkcjach, żeby kod był łatwiej rozszerzalny (i czytalniejszy).

2

Pierwsza rzecz – zapoznaj się z wektorami, bo ta drabinka if-ów nie dość, że wygląda paskudnie, to w dodatku trzeba ją będzie wydłużać, jeśli do gry dołożysz kolejne pytania. Dzięki wektorowi, możesz załadować do pamięci wszystkie pytania, następnie losować indeks i na jego podstawie wybierać dane z tego kontenera.

Jeśli koniecznie chcesz mieć pytania w osobnych plikach, to jeszcze łatwiej będzie nimi zarządzać – tzn. mniej kodu potrzeba, aby je obsługiwać. Chodzi o to, aby wylosować liczbę i tę liczbę przekazać do funkcji pytanie w parametrze, którą następnie konwertujesz na ciąg znaków i łączysz z nazwą pliku w tej instrukcji:

if( !wyswietlZawartosc( "pytania/1.txt" ) )

W miejscu 1 wstawiasz wynik konwersji liczby z parametru. Poczytaj o tym, w jaki sposób konwertować liczby na ciągi znaków i jak łączyć je w jeden łańcuch.

Kolejna rzecz to kwota, jaką w danym momencie ma gracz na ”koncie”. Znów robisz dziwne drabinki z przypisań do zmiennej statuspytania i z funkcji status500, status1000 itd. Po co to? Zadeklaruj sobie wektor, wypełnij liczbami określającymi wygraną (0, 500, 1000 itd., aż do miliona) i w jednej zmiennej przechowuj indeks kwoty, jaką w danym momencie posiada gracz. Po poprawnej odpowiedzi inkrementuj ten indeks o 1. Za pomocą tego indeksu możesz pobrać z wektora tę kwotę, aby np. wyświetlić ją na ekranie, razem z aktualnym pytaniem.

Jeśli chodzi o niepowtarzalność pytań – znów możesz użyć wektora. Ustaw jego rozmiar na zgodny z liczbą wszystkich możliwych pytań (u Ciebie będzie to 31). Wypełnij go kolejno liczbami od 1 do 31, a następnie pomieszaj losowo zawartość – do tego celu możesz użyć random_shuffle (kliknij w link, jest tam przykład kodu robiącego dokładnie to o czym piszę). Po przemieszaniu wektora, przytnij jego długość do 10 elementów. Od tej chwili, wektor ten zawiera indeksy pytań dla całej gry – teraz wystarczy Ci jedna zmienna z numerem pytania. Aby załadować dane bieżącego pytania, pobierz jego indeks z tego wektora i przekaż go do funkcji, która użyje go do otwarcia pliku.

I pisz ten kod w całości po angielsku, stosując się do wytycznych związanych z formatowaniem kodu i nazewnictwem.

2

Jak zrobić aby pytania się nie powtarzały?

  1. zrob klase ktora odpowiada plikowi
  2. wczytuj pytania / odpowiedzi do tej klasy. Wszystko wrzuc w std::vector zeby miec liste pytan
  3. wylosuj jakies pytanie z std::vector (nie bedziesz wiedziec to napisz w komentarzu). Po czym usuwasz z std::vector

Drugą sprawą jest jak w przypadku błędnej odpowiedzi powrócić do menu głównego?
"Tryby" pracy programu
Jak stworzyć menu w konsoli

0

coś ty uczynił ten absurdalnie długi switch xD

jest kilka metod na zrobienie tego...

  1. Klasami ( zapewne odpada widząc twój kod - a to najlepsza metoda )
  2. Tablicami Funkcji ( to też odpada widząc twój kod na 100% nawet nie znasz tego określenia )
  3. na podstawie Struktury...

zapewne widząc twój kod pkt. 3 też odpada ale zamiast wypisywać jak wiele ci brakuje to opiszę ci moim zdaniem najłatwiejszą metodę do stworzenia czegoś takiego... chyba że wiesz już czym są struktury to po prostu ich użyj...

struct
{
 string Pytanie;
 string Odpowiedzi[4];
 char Odpowiedz;
 bool Dostepne;
}ListaPytan[25];

( W tym przypadku sam zakładam że będzie np. 25 róznych pytan )

dzięki takiej strukturze możesz stworzyć cały swój program ( no i w dodatku zapisywać dane i pobierać je jednym getlinem )
w każdym razie co jest to ?...

Pytanie -> Obiekt ( Zmienna ) przechowująca twoje pytanie
Odpowiedzi[4] -> Tablica typu string z 4 elementami ( domyslnie w końcu mamy A , B , C , D ^_^ )
Odpowiedz -> Obiekt ( Zmienna ) typu char przechowująca poprawną odpowiedź
Dostepne -> Obiekt ( Zmienna ) typu bool przechowywująca CZY pytanie zostało już zadane
a jeśli tak to losowane jest nowe pytanie

if(ListaPytan.Dostepne)LosujPytanie();else ZadajPytanie();

zamiast podawać na końcu nazwę obiektu możesz wykorzystać

Struct ListaPytań
{
 CTRL C / V
}

i na tej podstawie stworzyć np. kategorie

ListaPytan PytaniaHumanistyczne[25];
ListaPytan PytaniaBiologiczne[15];
ListaPytan PytaniaChemiczne[20];

warto wtedy też zrobić osobna tablica aby nie bawić się w 1000 case break...
albo skorzystać ze wskaźnika... ale wracając do poprzedniego...

widząc twój kod zakładam że uzycie wskaźników oraz bardziej zaawansowanych tablic jest nierealne dla cb :P

w każdym razie pokazałem ci jak to MNIEJ więcej zrobić ^_^...

0

Sorry, wiem że kod jest paskudny i amatorski, wiem że powinno być inaczej, robię na ile mi mój skill (a raczej jego brak) pozwala. Będę starał się to korygować i robić w bardziej "profesjonalny" sposób.

@Hodor Odnośnie twojego rozwiązania. Pozumiem że powinienem to zrobić tak:

bool GameFinished = false; //gdzieś w programie np. na początku.
while ( ! GameFinished) { //na początku maina
GameFinished = true; //w każdym pytaniu w przypadku gdy gracz udzieli błędnej odpowiedzi?

Nie działa :/

@TobiPL
Nie widziałeś absurdalnie długich switchy xD

1
  1. Nie używaj rand/srand: https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/
  2. O absurdalnym switchu inni już napisali.
  3. Wrzuć pytania do kontenera (np. std::vector), wymieszaj go za pomocą std::shuffle, a potem po prostu leć w tej kolejności. Łatwo, prosto, czytelnie.
0

Dobra wrzucam całe archiwum z "grafiką" + kod.
@kq obowiązuje tutaj jakiś skan pliku dla potwierdzenia że plik nie zawiera wirusa?
(za chwile wrzucę)

0

@watus1992r:
jeżeli twój main wygląda mniej więcej tak:

///pytanie 1 za 500
            statuspytania= 500;
            status500();
            wylosowano(losuj());
            system("cls");
            //kontynuuj();
///pytanie 2 za 1 000
            statuspytania= 1000;
            status1000();
            wylosowano(losuj());
            system("cls");
///pytanie 3 za 2 000
            statuspytania= 2000;
            status2000();
            wylosowano(losuj());
            system("cls");
///pytanie 4 za 4 000
            statuspytania= 4000;
            status4000();
            wylosowano(losuj());
            system("cls");
///pytanie 5 za 8 000
            statuspytania= 8000;
            status8000();
            wylosowano(losuj());
            system("cls");
/// ...

i wsadzisz to wszystko w While, to i tak While wykona się przynajmniej raz do samego końca. Chyba, że użyjesz break i wyjdziesz z pętli, ale jak tu mądrze skorzystać z tego brejka mając taki kod?

#include <iostream>

int main()
{
    bool GameFinished = false;
    while (!GameFinished)
    {
        std::cout << "Pierwsza jakas tam linijka\n";
        GameFinished = true;
        std::cout << "Druga jakas tam linijka. To tez sie wypisze!\n";
    }
}
0

w sumie kod z pierwszego posta jest jak jedno wielkie WTF, ale i tak dobrze, że widzisz, że coś jest źle i że zadajesz takie pytania, jak można coś uprościć (wiele osób się nawet nie zastanawia i cały czas pisze wszystko na drabinkach duplikowanych ifów).

0

Da się w tym moim kodzie zrobić to co bym chciał, czy nie bardzo? Nie mam pomysłu jak to zrobić, na tym moja wiedza odnośnie programowania się kończy :/.

0

Wszystko się da, ale nikt rozsądny tego nie zrobi. Drabinka ifów do wywalenia, inaczej tego nie widzę.

0

A odnośnie tego wywalenia do początku po nieprawidłowej odpowiedzi. Zrobiłem to tak jak napisaliście (konkretnie Hodor) i nie działa.
Przez while we while? Czy coś źle dodałem?

0
watus1992r napisał(a):

A odnośnie tego wywalenia do początku po nieprawidłowej odpowiedzi. Zrobiłem to tak jak napisaliście (konkretnie Hodor) i nie działa.
Przez while we while? Czy coś źle dodałem?

zaznaczę, że nie znam c++, ale może taki "hello world" Ci coś pomoże

#include <iostream>
#include <string>
#include <vector>
#include <random>

using namespace std;

vector < string > questions;

int getRandomNumber(int min, int max)
{
    random_device rd;
    mt19937 engine(rd());
    uniform_int_distribution<> distribution(min, max);
    return distribution(engine);
}

int main()
{
    questions.push_back("2+2?"); // dodajesz pytania do vectora
    questions.push_back("3-3?");
    questions.push_back("2*2?");
    questions.push_back("0+1?");

    while(questions.size()>0) // wykonujesz dopoki sa jakies pytania w vectorze
    {
        int random_index = getRandomNumber(0, questions.size()-1); // losujesz index pytania w vectorze
        cout << questions[random_index] << endl; // wyswietlasz pytanie pod losowym indexem
        questions.erase(questions.begin() + random_index); // usuwasz pytanie pod losowym indexem
    }
}

0

Czyli tak:

  1. tworze vector:
    vector <int> questions;
  2. Tworzę pętlę for wykonującą się tyle razy ile jest pytań do wygranej głównej.
  3. W pętli za każdym razem dodawany jest wpis do tablicy.
    (czyli teraz mamy już gotową tablicę z wylosowanymi pytaniami)
  4. Teraz znowu nie wiem co dalej. Ja bym to zrobił znowu i fami bo inaczej nie ogarniam
    if(question[0]=1)
    pytanie1()
    elseif(question[0]=2)
    pytanie2()

i znowu drabinka 320 ifów :P
Nie wiem jak to inaczej zrobić...

3

Może inaczej, bo widzę, że nie wszystko jest jasne. Każde pytanie opisuje kilka informacji:

  • treść pytania,
  • treści odpowiedzi:
    • treść odpowiedzi A,
    • treść odpowiedzi B,
    • treść odpowiedzi C,
    • treść odpowiedzi D,
  • numer prawidłowej odpowiedzi.

Potrzebujesz zdefiniować jakiś kontener, który pozwoli przechować dane na temat pytania. Taki obiekt powinien dawać dostęp do wyżej wymienionych danych, jednocześnie nie pozwalając na ich modyfikację (no bo i po co). Nazwijmy go Question.

Następnie trzeba się zająć tym, w jaki sposób pobierać dane o pytaniach do programu. Tych pytań masz niewiele, więc w sumie możesz je wszystkie załadować do pamięci. Aby zgrupować dane wszystkich pytań w jednym miejscu, przyda się wektor. Wektor ten ma przechowywać obiekty z kompletnymi danymi dotyczącymi pytań – nazwijmy go Questions. Dane pytań załadować trzeba raz – na początku działania programu.

Do przechowania numeru bieżącego pytania w grze, użyj zwykłego inta – niech nazywa się QuestionIndex. Jego używasz do pobrania obiektu z wektora Questions – obiekt ten zawiera treść pytania, odpowiedzi oraz numer prawidłowej odpowiedzi.

Do całości trzeba dorzucić jeszcze jeden wektor, który przechowywać będzie kwoty odpowiednie dla każdego pytania.


Tak to się ma ogólnie. Pierwsze co trzeba zrobić to stworzyć wektor dla wszystkich pytań i je załadować z pliku(ów) do pamięci.

Teraz czas na pętlę gry – najpierw szuflujesz wektor pytań, inicjalizujesz numer pytania i zaczyna się gra. Wyświetlasz na ekranie dane pierwszego pytania, pobierasz numer odpowiedzi, sprawdzasz czy jest prawidłowa. Jeśli jest prawidłowa to inkrementujesz numer pytania i wracasz na początek pętli. Jeśli jest nieprawidłowa to przerywasz działanie pętli i wracasz do menu. Jeśli gracz odpowiedział na ostatnie pytanie to wyświetlasz informację i też przerywasz pętlę, wracając do menu.

Nie ma mowy o drabinkach, bo wszystkie potrzebne informacje możesz w dowolnym momencie pobrać z wektorów, wykorzystując do tego numer pytania, czyli zmienną QuestionIndex.

1 użytkowników online, w tym zalogowanych: 0, gości: 1