# Práce s náhodnými čísly

### Úvod

V této kapitole si ukážeme, jak generovat náhodná čísla pomocí třídy `Random`.

### Problematika náhodných čísel v IT

Jedna z věcí, kterou počítač neumí udělat, je právě náhodné číslo. Algoritmy na generování takovýchto čísel dokážou vytvořit dlouhou sekvenci čísel, které pouze vypadají náhodně. Náhodná čísla se v programech generují podle tzv. `seedu`. Když nastavíme seed na jednu hodnotu, dostaneme vždy stejnou náhodnou sekvenci.

### Třída Random a její metody

Abychom mohli začít generovat čísla, musíme nejdříve vytvořit novou instanci třídy `Random`.

<div class="el-tabs__header is-top" id="bkmrk-vytvo%C5%99en%C3%AD-instance"><div class="el-tabs__nav-wrap is-top"><div class="el-tabs__nav-scroll"><div class="el-tabs__nav is-top" role="tablist"><div aria-controls="pane-0" aria-selected="true" class="el-tabs__item is-top is-active" id="bkmrk-vytvo%C5%99en%C3%AD-instance-1" role="tab" tabindex="0">Vytvoření instance</div></div></div></div></div>```c#
// Vytvoření generátoru náhodného čísla s "náhodným" seedem
Random r = new Random();

// Vytvoření generátoru n. č. se specifickým seedem
Random r2 = new Random(123);
```

<div class="el-tabs__content" id="bkmrk-"><div aria-labelledby="tab-0" class="el-tab-pane" id="bkmrk--1" role="tabpanel"></div></div><p class="callout danger">Když neurčíme seed při vytvoření generátoru, nastaví se seed podle času. Tzn. že když v jedné sekundě vytvoříme více instancí třídy `Random`, budou mít všechny tyto instance stejný seed. V praxi to znamená, že bychom se měli vyhnout vytváření instancí třídy `Random` například uvnitř cyklů, jinak nám hrozí situace, že námi vygenerovaná čísla budou všechny shodná.</p>

Nyní máme vytvořený náš generátor a můžeme začít generovat čísla. Třída `Random` nám k tomu poskytuje dvě hlavní metody:

<div class="el-tabs__header is-top" id="bkmrk-hlavn%C3%AD-metody"><div class="el-tabs__nav-wrap is-top"><div class="el-tabs__nav-scroll"><div class="el-tabs__nav is-top" role="tablist"><div aria-controls="pane-0" aria-selected="true" class="el-tabs__item is-top is-active" id="bkmrk-hlavn%C3%AD-metody-1" role="tab" tabindex="0">Hlavní metody</div></div></div></div></div>```c#
Random r = new Random();

int i = r.Next();
double d = r.NextDouble();
```

<div class="el-tabs__content" id="bkmrk--2"><div aria-labelledby="tab-0" class="el-tab-pane" id="bkmrk--3" role="tabpanel"></div></div>**\# Metoda Next()**

Nyní začneme metodou `Next()`. Tu použijeme, pokud budeme chtít vygenerovat náhodné celé číslo (`int`). Když metodu napíšeme bez parametrů, tak integer, který dostaneme, bude náhodné číslo větší nebo rovno nule. Tato metoda má ale více možností, jak ji použít. Pokud do závorky u metody `Next()` dáme jeden parametr typu `int`, nastavíme tím vrchní hodnotu (maximum), ke které se generátor může přiblížit. Když přidáme ještě jeden další parametr, dostaneme tím možnost nastavit celý rozsah. Tzn. minimum i maximum:

<div class="el-tabs__header is-top" id="bkmrk-n%C3%A1hodn%C3%A9-%C4%8D%C3%ADslo"><div class="el-tabs__nav-wrap is-top"><div class="el-tabs__nav-scroll"><div class="el-tabs__nav is-top" role="tablist"><div aria-controls="pane-0" aria-selected="true" class="el-tabs__item is-top is-active" id="bkmrk-n%C3%A1hodn%C3%A9-%C4%8D%C3%ADslo-1" role="tab" tabindex="0">Náhodné číslo</div></div></div></div></div>```c#
Random r = new Random();

// Hodnoty pro "ohraničení" náhodného čísla
int min = 5;
int max = 25;

// Číslo větší nebo rovno nule [dostaneme číslo v rozsahu 0 - ...]
r.Next();

// Číslo větší nebo rovno nule a menší než parametr max [dostaneme číslo v rozsahu 0 - 24]
r.Next(max);

// Číslo větší nebo rovno parametru min a menší než parametr max [dostaneme číslo v rozsahu 5 - 24]
r.Next(min, max);
```

<div class="el-tabs__content" id="bkmrk--4"><div aria-labelledby="tab-0" class="el-tab-pane" id="bkmrk--5" role="tabpanel"></div></div><p class="callout warning">Minimum je inkluzivní (hodnota spadá do generované sekvence) zatímco maximum není.</p>

**\# Metoda NextDouble()**

Tato metoda narozdíl od ostatních dvou nevyžaduje žádný parametr, neboť má přesně daný rozsah. Pomocí ní můžeme získat čísla datového typu `double`, která jsou v intervalu od 0 do 1:

<div class="el-tabs__header is-top" id="bkmrk-desetinn%C3%A9-n%C3%A1hodn%C3%A9-%C4%8D%C3%AD"><div class="el-tabs__nav-wrap is-top"><div class="el-tabs__nav-scroll"><div class="el-tabs__nav is-top" role="tablist"><div aria-controls="pane-0" aria-selected="true" class="el-tabs__item is-top is-active" id="bkmrk-desetinn%C3%A9-n%C3%A1hodn%C3%A9-%C4%8D%C3%AD-1" role="tab" tabindex="0">Desetinné náhodné číslo</div></div></div></div></div>```c#
Random r = new Random();

// Vypíše náhodný double
Console.WriteLine(r.NextDouble());
```

<div class="el-tabs__content" id="bkmrk--6"><div aria-labelledby="tab-0" class="el-tab-pane" id="bkmrk--7" role="tabpanel"></div></div>### Realizace náhodného čísla bez opakování

Když generujeme náhodná čísla, našemu generátoru nevadí udělat klidně více stejných čísel za sebou. Někdy se to náhodou stane. Ale v nějakých případech chceme takovému chování zabránit. Například ve sportce, když se losují čísla, nikdy nemůže dostat více stejných čísel za sebou. Teď si ukážeme, jak takového výsledku docílit. Budeme si muset vytvořit list, do kterého postupně budeme přidávat hodnoty, které jsme už použili. Pomocí metody `Contains()` pak budeme kontrolovat, zda se číslo, které jsme vygenerovali, neshoduje s nějakým v našem listu. Proces budeme opakovat, dokud nenajdeme číslo, které jsme ještě nepoužili:

<div class="el-tabs__header is-top" id="bkmrk-n%C3%A1hodn%C3%A9-%C4%8D%C3%ADslo-bez-op"><div class="el-tabs__nav-wrap is-top"><div class="el-tabs__nav-scroll"><div class="el-tabs__nav is-top" role="tablist"><div aria-controls="pane-0" aria-selected="true" class="el-tabs__item is-top is-active" id="bkmrk-n%C3%A1hodn%C3%A9-%C4%8D%C3%ADslo-bez-op-1" role="tab" tabindex="0">Náhodné číslo bez opakování</div></div></div></div></div>```c#
// List hodnot, které jsme již použili
List<int> pouziteHodnoty = new List<int>();

// Pokusíme se vypsat 100 čísel, které se neopakují
for (int i = 0; i < 100; i++)
{
    // Hodnota, se kterou právě pracujem
    int generovanaHodnota;

    do
    {
        // Necháme vytvořit náhodné číslo
        generovanaHodnota = r.Next();

    } while (pouziteHodnoty.Contains(generovanaHodnota)); // Pokud ho náš List již obsahuje, zkusíme vytvořit další

    // Až se nám podaří najít hodnotu, kterou jsme ještě nepoužili, tak ji přidáme do listu
    pouziteHodnoty.Add(generovanaHodnota);

    // Vypíšeme unikátní číslo
    Console.WriteLine(generovanaHodnota);
}
```

<div class="el-tabs__content" id="bkmrk--8"><div aria-labelledby="tab-0" class="el-tab-pane" id="bkmrk--9" role="tabpanel"></div></div><p class="callout info">Pokud bychom chtěli náhodná čísla bez opakování v nějakém intervalu (např. od 0 do 10), museli bychom si pohlídat i situaci, kdy nám žádná náhodná čísla už nezbývají. Pokud by tato situace nastala, mohli bychom například vyhodit náš vlastní `Exception`.</p>

### Shrnutí

V této kapitole jsme se naučili pracovat s třídou `Random` a ukázali jsme si, jak vyřešit časté problémy při jejím používání.