Problem z losowością liczb

0

Cześć wszystkim,

Napisałem program, który generuje losową liczbę z danego przedziału a potem sam ma odgadnąć tę liczbę. Są dwa problemy:

  • program losuje zawsze 0 jako pierwszą liczbę, pomimo warunku że pierwszą liczbą jest 1. Nie wiem z czego to wynika. Zakomentowany mam nawet test losowości. Stworzyłem go, żeby sprawdzić czy zero się wylosuje, co się nigdy nie stało.

  • pomimo że zakres zmniejszyłem do (strzał, MAX) lub (MIN, strzał) program wciąż losuj liczby spoza tego zakresu.

Problem jest w funkcjach? Wiem, że mogę dodać osobne if'y ale ze strony logicznej wszystko powinno działać (tak mi się zdaje).

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

using namespace std;

// Variables
int wynik, strzal, proby = 0; 
bool winner = false;

int losuj(int minimum, int maksimum){
    return rand() % (maksimum - minimum + 1) + minimum;
}

int zgaduj(int minimum, int maksimum){
    return rand() % (maksimum - minimum + 1) + minimum;
}

int main(){

    srand( time ( NULL ) );

    /*for (int i=0; i<110; i++){        TEST LOSOWOSCI
        cout << losuj(1,100) << endl;
    }
    */
    losuj:
    wynik = losuj(1,100);
    cout << "Wylosowana zostala liczba, sprobuj ja odgadnac. Powodzenia!" << endl;

    do { 
        int stzal = zgaduj(1,100);
        cout << strzal;

        zgaduj:
        if (strzal>wynik){
            cout << " - Za wysoko" << endl;
            strzal = zgaduj(1, strzal);
            cout << strzal;
            proby++;
            goto zgaduj;

        } else if (strzal<wynik){
            cout << " - Za nisko" << endl;
            strzal = zgaduj(strzal, 100);
            cout << strzal;
            proby++;
            goto zgaduj;

        } else if (strzal == wynik) {
            cout << " - Brawo! Wylosowana liczba: " << wynik << endl << "Liczba prob: " << proby << endl;
            winner = true;
        }

    } while(winner == false);
    
    return 0;
}

0

U mnie, kompilowane g++-9, losuj działa poprawnie. Popatrz też:
https://stackoverflow.com/questions/7560114/random-number-c-in-some-range

2

Ten kod jest okropny, zaoraj go i napisz od nowa. Jeśli piszesz w C++ to nie pisz w koślawym C i nie używaj goto do sterowania przebiegiem programu.

Twój bezpośredni problem jest taki, że masz zmienne strzał i stżał: strzał jest globalna (a więc jej pierwszą wartością jest 0), a stżał nie jest, ale nie jest też w ogóle używana. Swoją drogą, nie używaj zmiennych globalnych - są fuj.

PS: zauważyłeś, że masz dwie funkcje o identycznym ciele?

Dorzucę jeszcze https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/ ale samo zastosowanie się do tego wiele tutaj nie pomoże.

0
kq napisał(a):

Ten kod jest okropny, zaoraj go i napisz od nowa. Jeśli piszesz w C++ to nie pisz w koślawym C i nie używaj goto do sterowania przebiegiem programu.

Twój bezpośredni problem jest taki, że masz zmienne strzał i stżał: strzał jest globalna (a więc jej pierwszą wartością jest 0), a stżał nie jest, ale nie jest też w ogóle używana. Swoją drogą, nie używaj zmiennych globalnych - są fuj.

PS: zauważyłeś, że masz dwie funkcje o identycznym ciele?

Dorzucę jeszcze https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/ ale samo zastosowanie się do tego wiele tutaj nie pomoże.

  • Jest okropny bo się uczę. Dla mnie najważniejsze obecnie jest zrozumienie dlaczego coś działa a coś nie działa. Z tą wiedzą mogę dopiero optymalizować kod.
  • Mam tylko jedną zmienną "strzal".
  • Czym mam w takim razie zastąpić zmienne globalne? Mam robić osobny plik ze zmiennymi prywatnymi na kod, który ma zaledwie 100 linijek? Powrót to pierwszego myślnika - najpierw zrozumienie, potem optymalizacja.
  • wiem, że mam dwie te same funkcje. Skopiowałem pierwszą funkcję bo inaczej nie wylosuje liczby 'losowej' tylko liczbę większą albo równą liczbie wylosowanej, ponieważ pobierana jest z zegara (tak mi sie wydaje) .
1

Jest okropny bo się uczę.

Z jakiego kursu/książki korzystasz? Zmienne globalne, goto - jeśli są w nim pokazywane na początku - świadczą, że jest to słaby kurs. Szczególnie goto.

Mam tylko jedną zmienną "strzal".

int wynik, strzal, proby = 0;
// ...
int stzal = zgaduj(1,100);

Czym mam w takim razie zastąpić zmienne globalne?

Zmiennymi lokalnymi w odpowiednich funkcjach. Dobrym nawykiem jest używanie zmiennej w najmniejszym możliwym zakresie (czyli w najbardziej zagłębionych klamrach)

inaczej nie wylosuje liczby 'losowej' tylko liczbę większą albo równą liczbie wylosowanej, ponieważ pobierana jest z zegara (tak mi sie wydaje)

Po to masz parametry funkcji aby decydować w jakim zakresie szukać. Jeśli funkcje są identyczne to będą się identycznie zachowywać.

0
kq napisał(a):

Jest okropny bo się uczę.

Z jakiego kursu/książki korzystasz? Zmienne globalne, goto - jeśli są w nim pokazywane na początku - świadczą, że jest to słaby kurs. Szczególnie goto.

Mam tylko jedną zmienną "strzal".

int wynik, strzal, proby = 0;
// ...
int stzal = zgaduj(1,100);

Czym mam w takim razie zastąpić zmienne globalne?

Zmiennymi lokalnymi w odpowiednich funkcjach. Dobrym nawykiem jest używanie zmiennej w najmniejszym możliwym zakresie (czyli w najbardziej zagłębionych klamrach)

inaczej nie wylosuje liczby 'losowej' tylko liczbę większą albo równą liczbie wylosowanej, ponieważ pobierana jest z zegara (tak mi sie wydaje)

Po to masz parametry funkcji aby decydować w jakim zakresie szukać. Jeśli funkcje są identyczne to będą się identycznie zachowywać.

Poprawiłem literówkę i pierwszy problem zniknął. Drugi problem wciąż istnieje. Oto spis z konsoli po uruchomieniu:

Wylosowana zostala liczba, sprobuj ja odgadnac. Powodzenia!
14 - Za nisko
92 - Za wysoko
6 - Za nisko
56 - Za nisko
77 - Za wysoko
75 - Za wysoko
60 - Za nisko
80 - Za wysoko
32 - Za nisko
54 - Za nisko
99 - Za wysoko
79 - Za wysoko
73 - Za wysoko
6 - Za nisko
53 - Za nisko
89 - Za wysoko
63 - Brawo! Wylosowana liczba: 63
Liczba prob: 16

Jak widać wartości skaczą, co jest dziwne. Any ideas?

1
            strzal = zgaduj(1, strzal);
            strzal = zgaduj(strzal, 100);

Losujesz [1,strzal) i [strzal, 100), musisz pamiętać krańce zakresu z obu stron i je sukcesywnie zmniejszać.

Zamiast goto masz pętle - nawet ich używasz...

0

Tu masz "na zachętę" poprawny kod implementujący podobną grę (gracz podaje, komputer zgaduje):

#include <iostream>
#include <random>
// z https://dsp.krzaq.cc/post/180
thread_local std::mt19937 gen{std::random_device{}()};
 
template<typename T>
T random(T min, T max) {
    using dist = std::conditional_t<
        std::is_integral<T>::value,
        std::uniform_int_distribution<T>,
        std::uniform_real_distribution<T>
    >;
    return dist{min, max}(gen);
}

int main()
{
    static constexpr auto min_value = 1;
    static constexpr auto max_value = 1000;
    int secret;
    std::cout << "Wprowadz sekretna liczbe\n";
    std::cin >> secret;
    secret = std::clamp(min_value, secret, max_value);
    std::cout << "Sekretna liczba: " << secret << '\n';

    int min = min_value;
    int max = max_value;
    while(true) {
        int guess = random(min, max);
        std::cout << guess << " - ";
        if(guess < secret) {
            std::cout << "       ZA MALO\n";
            min = guess + 1;
        } else if(guess > secret) {
            std::cout << "ZA DUZO\n";
            max = guess - 1;
        } else {
            std::cout << "BRAWO!\n";
            break;
        }
    }
}

https://wandbox.org/permlink/caNvWWYd05qkARyX

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