Jak snadno zpracovat

vstup a výstup?

Jak se načítá vstup?

Všechny úlohy v Kasiopeji fungují tak, že vstup dostaneš ve formě textového souboru. Abys dokázal(a) úlohu vyřešit, musíš nejprve vstup načíst do svého programu a přesně s tím ti poradí tahle stránka.

Existují dvě základní možnosti, jak se vstupem pracovat. První možností je načíst vstup přímo ze souboru, tou začneme. Druhou možností je přesměrování takzvaného standardního vstupu, což je v podstatě jen odborný název pro vstup, který programu píše uživatel. Přesměrování se chová tak, že programu předává znaky ze souboru, jako by je tam psal uživatel. Hodí se to především v případě, kdy spouštíš své programy z příkazové řádky.

Protože úlohy Kasiopey mají ve svém zadání velmi často čísla, ukážeme si kromě načítání vstupu také to, jak vstup na čísla převést. To musíme udělat, protože obě výše zmíněné metody načtou vstup jako text a programovací jazyky pracují s textem jinak než s čísly. Jestli se chceš dozvědět více o práci s textem, podívej se na náš text o řetězcích.

Nejprve si krátce popíšeme obě metody načítání vstupu a pak ti ukážeme, jak se to dělá v několika populárních programovacích jazycích.

Načítání vstupu ze souboru

Jednou z možností, jak dostat zadání úlohy do svého programu, je otevřít si soubor se zadáním přímo ve svém programu a přečíst zadání z něj.

Ve všech ukázkách kódu budeme předpokládat, že soubor se zadáním se jmenuje zadani.txt a je uložený ve stejné složce, ze které spouštíš program. Dej si pozor, že pokud na psaní programů používáš nějaké IDE, může být složka, ve které se program spouští, jiná, než když ho spustíš přímo.

Standardní vstup

Když svému programu přesměruješ standardní vstup, stačí pak pro jeho načtení uvnitř programu používat stejné funkce, jako bys používal(a) pro načítání vstupu od uživatele (z klávesnice).

Nejsnadněji se přesměrování vstupu dělá z příkazové řádky, nicméně i většina vývojových prostředí to umí. Třeba v PyCharmu, IntelliJ IDEA a dalších prostředích od JetBrains se dá přesměrování nastavit v menu Edit Configurations... (rychlý trik, jak se do něj dostat je zmáčknout dvakrát klávesu shift a začít psát "Edit Configurations..."). V sekci Execution je možnost Redirect input from, ve které se nastaví vstupní soubor.

Přesměrování vstupu na příkazové řádce

Když používáš příkazovou řádku, musíš najít, kde máš uložený spustitelný soubor svého programu. Pokud překládáš pomocí řádkových programů (jako gcc, g++, apod.), určitě víš, kde output file je (u g++ si můžeš pomocí -o filename specifikovat, jak se bude jmenovat). U vývojových prostředí se spustitelný program často ukládá do podsložky /bin/Debug.

Příkaz, kterým přesměrujeme vstup, vypadá jednoduše. Pokud jsi v příkazové řádce v adresáři, ve kterém je spustitelný program i vstup, napiš toto:

program.exe < zadani.txt          (Windows)
./program < zadani.txt            (Linux)
python program.py < zadani.txt    (Python)
java Program < zadani.txt         (Java)

Tento příkaz předá soubor zadani.txt programu program na standardní vstup.

Přesměrování výstupu:

Úplně stejně jako vstup se dá přesměrovat i výstup programu. Akorát menšítko přehodíme za většítko:

program.exe > reseni.txt         (Windows)
./program > reseni.txt           (Linux)
python program.py > reseni.txt   (Python)
java Program > reseni.txt        (Java)

Tím se vyrobí soubor reseni.txt, který můžeš odevzdat do soutěže!

Ve vývojových prostředích od JetBrains se dá přesměrování výstupu nastavit v menu Edit Configurations... na záložce Logs, kde je položka Save console output to, ve které se nastaví výstupní soubor.

Obě přesměrování lze kombinovat:
./program < zadani.txt > reseni.txt

Ukázky kódu

Python
Čtení ze souboru
with open("zadani.txt") as vstup:           # otevřeme soubor
    prvni_radek = vstup.readline().rstrip() # pomocí readline přečteme jeden řádek
                                            # rstrip slouží pro odstranění bílých znaků na konci řádku
    # tady můžeme se souborem dál pracovat, třeba načíst další řádky  
Čtení ze standardního vstupu
radek = input()  # přečte jeden řádek ze vstupu
Převod na čísla

Obě metody výše čtou vstup jako text. Pro převod na číslo, musíme ještě navíc použít funkci int().

slovo_pet = "5"
cislo_pet = int(slovo_pet)

V úlohách se nám také často stává, že máme na jednom řádku více čísel oddělených mezerou. Pokud například chceme načíst dvě čísla, můžeme použít následjující kód (ten do proměnné N načte první číslo na řádku a do proměnné M druhé číslo na řádku):

N, M = [int(i) for i in input().split()]

Pokud je čísel více, většinou je chceme načíst do seznamu. To uděláme velmi podobně:

seznam = [int(i) for i in input().split()]

Výše uvedené možnosti fungují pouze v Pythonu 3. Pokud používáš Python 2, můžeš si pomoct například for cyklem (proměnná seznam_text bude obsahovat čísla jako textové řetězce a proměnná seznam je bude obsahovat skutečně jako čísla):

seznam_text = input().split()
seznam = []
for cislo in seznam_text:
    seznam.append(int(cislo))
Zápis do souboru
with open("reseni.txt", "w") as vystup:         # otevřeme soubor pro zápis
    print("prvni radek reseni", file=vystup)  # můžeme použít funkci print pro zapsání jednoho řádku
    vystup.write("druhy radek reseni\n")        # a nebo metodu write (musíme přidat \n pro odřádkování)
JavaScript

Pro řešení úloh v Javascriptu jsme pro tebe přípravili šablonu. Stačí kliknout na odkaz pravý tlačítkem a zvolit "Uložit cíl jako". Poté uprav funkci main tak, aby řešila zadanou úlohu (samozřejmně můžeš vytvářet i jiné funkce). Soubor pak otevři libovolným webovým prohlížečem podporujícim JavaScript. Následně tlačítkem „Browse“ (případně „Procházet“) vyber soubor se zadáním úlohy. Po kliknutí na tlačítko „Spusti“ ti stránka nabídne soubor ke stažení. Tento soubor stáhni a odevzdej jako řešení.

Šablona

Převod na čísla
// načti číslo z řetězce
let slovoPet = "5"
let cisloPet = Number(slovoPet)

// načti několik čísel z řetězce
let retezec = "1 2 3 4"
let cisla = []
for (cislo of line.split(" ")) {        // split(" ") rozdělí řetězec na pole řetězců podle mezer
    cisla.append(Number(cislo));
}
C#
Čtení ze souboru

Na začátek našeho programu musíme doplnit using System.IO;. Uvnitř Main funkce (nebo někde jinde v programu) pak můžeme použít toto:

using (StreamReader vstup = new StreamReader("zadani.txt")) // otevřeme soubor pro čtení
{
    string prvniRadek = vstup.ReadLine();                   // přečteme jeden řádek
}
Čtení ze standardního vstupu
string radek = Console.ReadLine(); // přečte jeden řádek ze vstupu 
Převod na čísla
string slovoPet = "5";
int cisloPet = int.Parse(slovoPet);
Přečtení seznamu čísel na jednom řádku:
string radek = Console.ReadLine();          // přečte řádek (tohle můžeme nahradit čtením ze souboru)
string[] cislaRetezce = input.Split(' ');   // rozdělí řádek podle mezer
int[] cisla = new int[cislaRetezce.Length]; // připraví si pole pro uložení čísel
// projdeme všechny řetězce a převedeme je na čísla
for (int i = 0; i < cislaRetezce.Length; ++i) {
    cisla[i] = int.Parse(cislaRetezce[i]);
}
Zápis do souboru

Podobně jako pro čtení musíme mít na začátku našeho programu using System.IO;.

using (StreamWriter vystup = new StreamWriter("reseni.txt"))
{
    vystup.WriteLine("první řádek výstupu"); // automaticky odřádkuje
    vystup.Write("druhý řádek výstupu\n");   // tady máme konec řádku ručně pomocí \n
}
C++
Čtení ze souboru

Na začátek programu doplníme #include <fstream>. V C++ můžeme rovnou číst vstup jako čísla, nemusíme je zvlášť převádět.

std::ifstream vstup("zadani.txt");  // otevřeme soubor
int cislo;                          // připravíme si proměnnou pro uložení výsledku, u toho si rovnou určíme
                                    // její typ (v tomto případě číslo, ale může to být i string nebo něco jiného)
vstup >> cislo;                     // načteme číslo ze vstupu do proměnné
Čtení ze standardního vstupu

Na začátek programu doplníme #include <iostream>. Pak už to funguje stejně jako čtení ze souboru.

int cislo;
std::cin >> cislo;

Když chceme přečíst seznam čísel na jednom řádku a víme, kolik jich je (což v úlohách Kasiopey většinou víme), stačí opakovat čtení:

int pocetCisel;
std::cin >> pocetCisel;
int cisla[pocetCisel]; // připravíme si pole správné délky
for (int i = 0; i < pocetCisel; i++)
    std::cin >> cisla[i];
Zápis do souboru

Zase potřebujeme #include <fstream>.

std::ofstream vystup("reseni.txt");            // otevřeme soubor
vystup << "první řádek výstupu";               // zapíšeme do něj
vystup << std::endl;                           // zapíšeme konec řádku
vystup << "druhý řádek výstupu" << std::endl;  // můžeme to udělat i najednou
Java

Kromě níže ukázaných možností se také často používá Scanner, který je praktický (podobně jako v ukázce v C++ umí načíst rovnou číslo), ale při větším množství dat může poznamenat rychlost.

Čtení ze souboru
BufferedReader vstup = new BufferedReader(new FileReader(new File("zadani.txt"))); // otevřeme soubor
String radek = vstup.readLine(); // přečteme jeden řádek

vstup.close(); // zavře soubor, když už ho nepotřebujeme
Čtení ze standardního vstupu
String radek = System.in.readLine();
Převod na čísla
String slovoPet = "5";
int cisloPet = Integer.parseInt(slovoPet);
Přečtení seznamu čísel na jednom řádku:
// tady čteme ze standardního vstupu
BufferedReader vstup = new BufferedReader(new InputStreamReader(System.in)); 
// přečte řádek
String radek = vstup.readLine();                                             
// rozdělí řádek podle mezer
String[] cislaRetezce = lines.trim().split("\\s+");                          
// připraví si pole pro uložení čísel
int[] cisla = new int[cislaRetezce.length];                                  
// projdeme všechny řetězce a převedeme je na čísla
for (int i = 0; i < cislaRetezce.length; i++) {
    cisla[i] = Integer.parseInt(cislaRetezce[i]);
}
Zápis do souboru
BufferedWriter vystup = new BufferedWriter(new FileWriter(new File("reseni.txt"))); // otevřeme soubor
vystup.write("první řádek výstupu");
vystup.newLine(); // konec řádku
vystup.write("druhý řádek výstupu");
vystup.flush(); // vynutí vyprázdnění bufferu (uložení na disk)
vystup.close(); // zavře soubor

Máš na to!

I ty můžeš vyhrát! Nebo to aspoň zkusit :)