NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Pomoc s piškvorky (algoritmus pro zjištění vítěze)

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
David Kroupa
Člen
Avatar
David Kroupa:14.1.2017 13:05

Ahoj, vytvořil jsem následující kód pro hru piškvorek (v konzoli), poradil by mi někdo, jak vytvořit kód, který by zjistil vítěze? :) Popřípadě jestli vidíte nějakou blbost v kódu, budu rád za upozornění.

public class SemestralniPracePiskvorky {

    public static Scanner sc = new Scanner(System.in);


    public static void main(String[] args) {
    System.out.println("Vítejte ve hře Piškvorky !");

        Piskvorky hra = new Piskvorky();                                        // Vytvoří novou instanci (hra) piškvorek
        do {
            System.out.printf("Nyní je na řadě hráč : " +hrajicihoZnacka+ "\n\n");
            hra.nacteniVstupu();                                                // metoda pro kontrolu vstupu
            System.out.printf("\nTáhnete na: [%d,%d]\n",sloupec,radek);
            hra.polozZnacku(radek-1, sloupec-1);                                // -1 protože indexy pole začinaji na 0 a hrač zadává do vizualizace ( začíná 1-kou )
            hra.vypisPole();
            hra.zmenHrace();

        }while(true);

    }

}
package semestralnipracepiskvorky;

import java.util.Scanner;
public class Piskvorky {

    public static Scanner sc = new Scanner(System.in);
    public char[][] herniPole;                                                  // založí pole charů "herníPole" dostupné v celé této třídě
    public static char hrajicihoZnacka = 'X';                                   // založí char "hrajicihoZnacka" dostupný v celé této třídě
    boolean jePlne;
    static int vyhra = 0;
    public static int sloupec;
    static int radek;

    public Piskvorky() {
        herniPole = new char[10][10];                            //  Vytvoří nové pole (Matice 10x10)
        cara();
        vytvorPole();
    }
    public static void nacteniVstupu() {              // Metoda kontroly vstupu
        System.out.println("Zadejte souřadnice vašeho tahu na poli [10x10]");
            System.out.print("Zadej sloupec [1-10]: ");                         // Čtení sloupce
                while(!sc.hasNextInt()){                                            // Kontrola vstupu (pokud není int, uživatele to dál nepustí dokud nezadá správný vstup
                System.out.print("Neplatné zadání!!! - Vstup musí být číselný, prosím opakujte, zadejte sloupec [1-10] ");
                sc.next();
                }
                sloupec = sc.nextInt();
        while (sloupec<1 || sloupec>10) {
            System.out.println("Neplatné zadání!!! - Prosím opakujte, zadejte sloupec [1-10]");
            sloupec = sc.nextInt();
        }
        System.out.print("Zadej řádek [1-10]: ");                               // Čtení řádku
            while(!sc.hasNextInt()){                                            // Kontrola vstupu (pokud není int, uživatele to dál nepustí dokud nezadá správný vstup
                System.out.print("Neplatné zadání!!! - Vstup musí být číselný, prosím opakujte, zadejte sloupec [1-10] ");
                sc.next();
                }
                radek = sc.nextInt();
        while (radek<1 || radek>10) {
            System.out.println("Neplatné zadání!!! - Prosím opakujte, zadejte řádek [1-10]");
            radek = sc.nextInt();
        }

    }

    public void vytvorPole() {
        for (int radek = 0; radek<herniPole.length; radek++) {                  //  Vytvoří řádky
            for (int sloupec =0; sloupec<herniPole.length; sloupec++) {         //  Vytvoří sloupce
                herniPole[radek][sloupec] = '-';                                //  Zaplní každé políčko pomlčkou (charem '-') (bereme jej jako prázdné)
            }
        }
    }
    public void cara()
    {
        for (int i = 0; i <herniPole.length; i++) {
            System.out.print("----");
        }
        System.out.println("-");
    }

    public void vypisPole() {
        cara();        //Vypíše vrchní okraj řádku

        for (int i =0; i<herniPole.length; i++) {
            System.out.print("| ");                                             //  Vypíše okraje řádků zleva
            for (int j = 0; j<herniPole.length; j++) {
                System.out.print(herniPole[i][j] + " | ");                      //  Vypíše okraje sloupců zprava
            }
            System.out.println();                                               //  Odřádkování
            cara();                                                             //  Vypíše spodní okraj řádku
        }
        System.out.println("");                                                 //  Odřádkování (jen vizuální úprava)
    }

    public boolean plnePole() {
        boolean jePlne = true;                                                  //  Deklarace booleanu jePlne (rozhoduje zda již nelze pokračovat ve hře (všechna políčka jsou zaplněna piškvorkami)
        for (int i =0; i<herniPole.length; i++) {
            for(int j=0; j<herniPole.length; j++) {
                if (herniPole[i][j] == '-' ) {                                  //  Pokud se objeví char '-' tedy pole bez piškvorky vypíše se false a je tedy možno pokračovat ve hře
                    jePlne = false;
                }
            }
        }
        return jePlne;
    }

    public void zmenHrace() {                                                   // Mění hráčovu značku
        if (hrajicihoZnacka == 'X') {
            hrajicihoZnacka = 'O';
        }else {
            hrajicihoZnacka = 'X';
        }
    }

    public boolean polozZnacku(int radek, int sloupec) {                        //  Umístí začku na zadané souřadnice v poli
        if ((radek>=0)&& (radek<herniPole.length)){                             //  Kontroluje jestli je správně zadaný radek
            if ((sloupec >=0) && sloupec<herniPole.length) {                    //  Kontroluje jestli je správně zadaný sloupec
                if (herniPole[radek][sloupec] == '-') {
                    herniPole[radek][sloupec] = hrajicihoZnacka;
                }
                else if (herniPole[radek][sloupec] == hrajicihoZnacka) {
                    System.out.printf(" - Neplatný tah!!!, Prosím opakujte akci na volné políčko.\n----------------------------------------\n",sloupec+1,radek+1);  //+1 opět upravuje vizualizaci pro uživatele (Uživatel vidí čísla co zadal - ve skutečnosti jsou indexy o 1 menší)
                    System.out.println("Zadej sloupec [1-10]: ");
                    sloupec = sc.nextInt();
                    System.out.println("Zadej řádek [1-10]: ");
                    radek = sc.nextInt();
                    herniPole[radek][sloupec] = hrajicihoZnacka;
                }
                else if (herniPole[radek][sloupec] != '-' || herniPole[radek][sloupec]!= hrajicihoZnacka) {
                    System.out.printf(" - Neplatný tah!!!, Prosím opakujte akci na volné políčko.\n----------------------------------------\n",sloupec+1,radek+1);  //+1 opět upravuje vizualizaci pro uživatele (Uživatel vidí čísla co zadal - ve skutečnosti jsou indexy o 1 menší)
                    System.out.println("Zadej sloupec [1-10]: ");
                    sloupec = sc.nextInt();
                    System.out.println("Zadej řádek [1-10]: ");
                    radek = sc.nextInt();
                    herniPole[radek-1][sloupec-1] = hrajicihoZnacka;
                }
            }
        }
        return true;
    }

}
 
Odpovědět
14.1.2017 13:05
Avatar
pocitac770
Tvůrce
Avatar
Odpovídá na David Kroupa
pocitac770:14.1.2017 15:40

Je to docela primitivní, dokonce, pokud jde o univerzální kód. Mám tu dokonce dvě možnosti, jedna pochopitelnější, kterou můžeš použít na pochopení celého systému, a jedna "kompaktnější"

Po každém tahu si zavoláš metodu, která projede celou tabulku podle následujícího systému (bereme souřadnice [x][y], viz obrázek:
Budeš mít 2 proměnné, jedna, která bude ozančovat, který hráč má "sérii", tzn. u koho počítáš řadu jeho znaků, a druhá, která bude označovat, kolik jich už v ředě měl.

  1. vodorovné čáry (oranžová)

Jednoduché, vezmeš si každý prvek pole, který má index [0][?], a kontrolouješ, pokud je tam nějaká značka, pokud ano, tak se koukneš, jestli je to ten samý hráč, co je označen v sérii, pokud ano, nebo žádný ozančen není, pak ho označíš a přičteš v každém případě 1, pokud ne, tak vynuluješ obě. Dál přičteš index [0][+1] a jdeš dál, takto, dokud nenarazíš na index pole, co je mimo hranice (jakýkoliv z dvou). Pokud kdykoliv dojdeš k tvému výhernímu počtu, tak vyhlásíš výherce, ukončíš cyklus i hru.

  1. svislé (zelená)

stejné jako 1, ale jdeš od [?][0] a přičítáš [+1][0]

  1. šikmo dolu (modrá)

zde je to už komplikovanější, protože se žádné strany nedotýkají všechny vyznačené čáry. Proto musíš projet obě modré strany. U levé ([0][?]) přičítáš [+1][+1] a u pravé ([MAX][?]) přičítáš [-1][-1]

  1. šikmo nahoru (červená)

jako 3, ale bereš horní a spodní, u horní ([?][0]) přičítáš [-1][+1], u spodní ([?][MAX]) přičítíš [+1][-1]

Pak jsou tu 2 možnosti, jak to urychlyt, zkrátit. Jednak se nabízí to, že jeden tah ovvlivní pouze to, kde je, tzn. si můžeš zkontrolovat pouze ty čáry, na kterých se tah nachází, stejným systémem jako výše. Dále, máš nějakou délku vítězné série, tzn. stačí zkontrolovat pouze tu část tabulky, která je vzdálená od těch souřadnic tahu (délka - 1)

Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
14.1.2017 15:40
Avatar
David Kroupa
Člen
Avatar
Odpovídá na pocitac770
David Kroupa:14.1.2017 19:09

Nebyl by nějaký stručný kód pro inspiraci? :) Vím jak to myslíš, ale programuju teprv chvíli a docela se s tím peru.

1. vodorovné čáry (oranžová)

Editováno 14.1.2017 19:10
 
Nahoru Odpovědět
14.1.2017 19:09
Avatar
pocitac770
Tvůrce
Avatar
Odpovídá na David Kroupa
pocitac770:15.1.2017 18:20

Rovnou jsem tam přidal zlepšení, že nemusíš kontrolovat druhé, pouze toho, který táhl, jak říkám, jde to mnoha způsoby vylepšit, stačí trochu popřemýšlet. Máš to jako příklad toho 1), zbytek si musíš dodělat

public boolean zkontrolovat(){
        int serie = 0;
        for(int i  = 0; i < herniPole.length(); i++){
                for(int j = 0; j < herniPole[i].length(); j++){
                        if(herniPole[i][j] == hrajicihoZnacka){
                                serie ++;
                                if(serie == vyherniPocet){
                                        return true;
                                }
                        }
                        else{
                                serie = 0;
                        }
                }
                serie = 0;
        }
        return false;
}

A pár poznámek, jedna jsem špatně v bodě 1 a 2 napsal to přičítání, je to naopak, dále tenhle kód jsem psal jenom tak z hlavy bez IDE, můžou tam být chyby, a k tvému kódu, v některých místech používáš dynamické hodnoty (přes délku pole), a jindy zase máš hodnoty napsané natvrdo (vypisování do konzole, některé podmínky...) musíš se tedy rozhodnout, jestli to chceš mít krátké, nebo upravitelné (jako že upravíš jednu hodnotu a máš kompletně změněnou velikost tabulky s tím, že všechno pořád funguje jak má). Pak máš nešikovně použité zjišťování délky pole, nerozlišuješ řádky a sloupce.... Co kdyby jsi měl pole o velikosti 10x20? To by jsi například pořád bral hodnotu 20, a dostával by jsi ArrayIndexOutOf­BoundsExcepti­on a nevěděl by jsi, kde je problém. To, jak si bezpečně zjistit ty délky u dvourozměrného pole (i když tohle není skutečné dvourozměrné pole, ale pouze pole polí, u dvourozměrného by to vypadalo ještě trochu jinak) máš v mém kódu.

 
Nahoru Odpovědět
15.1.2017 18:20
Avatar
David Kroupa
Člen
Avatar
David Kroupa:15.1.2017 18:30

Díky moc :)
Jak říkáš toho problému s délkou pole jsem si vědom. Ještě to upravím.
Já po trošce přemýšlení stvořil tohle, není to uplně ideální, ale funguje to.
Určitě to ještě upravím podle tebe.

public void vyhra() {   //Hledá v poli vítěznou řadu                        // Kontroluje řádky, pokud nalezne 5 stejných políček za sebou, vyhlásí vítěze
        for(int i=0; i<10;i++) {                                  // Projede řadek
            for(int j=0; j<6;j++){                                              // Postoupí o sloupec dolů
                if (herniPole[i][j] == hrajicihoZnacka && herniPole[i][j+1] == hrajicihoZnacka && herniPole[i][j+2] ==hrajicihoZnacka
                        && herniPole[i][j+3] ==hrajicihoZnacka && herniPole[i][j+4] ==hrajicihoZnacka) {
                    System.out.printf("Vítězem se stává: [%c]\n",hrajicihoZnacka);      //  Vyhlásí vítěze, ukončí program
                    System.exit(0);
                }
            }
        }

        for(int i=0; i<6; i++) {                                                // Kontroluje sloupce, pokud nalezne 5 stejných piškvorek pod sebou, vyhlásí vítěze
            for(int j=0; j<10; j++) {                             // Postoupí o sloupec dolů
                if(herniPole[i][j] == hrajicihoZnacka && herniPole[i+1][j] == hrajicihoZnacka && herniPole[i+2][j] == hrajicihoZnacka
                        && herniPole[i+3][j] == hrajicihoZnacka && herniPole[i+4][j] == hrajicihoZnacka) {
                    System.out.printf("Vítězem se stává: [%c]\n", hrajicihoZnacka); //  Vyhlášení vítěže
                    System.exit(0);                                                 // Ukončení programu
                }
            }
        }

        for(int i=0; i<6; i++) {                                                //Kontroluje diagonály ve směru šikmo vpravo dolů
            for(int j=0; j<6; j++) {
                if(herniPole[i][j] == hrajicihoZnacka && herniPole[i+1][j+1] == hrajicihoZnacka && herniPole[i+2][j+2] == hrajicihoZnacka
                        && herniPole[i+3][j+3] == hrajicihoZnacka && herniPole[i+4][j+4] == hrajicihoZnacka) {
                    System.out.printf("Vítězem se stává: [%c]\n", hrajicihoZnacka); //  Vyhlášení vítěže
                    System.exit(0);                                                 // Ukončení programu
                }
            }
        }

        for(int i=9; i>4; i--) {                                                //Kontroluje diagonály ve směru šikmo vlevo dolů
            for(int j=0; j<6; j++) {
                if(herniPole[i][j] == hrajicihoZnacka && herniPole[i-1][j+1] == hrajicihoZnacka && herniPole[i-2][j+2] == hrajicihoZnacka
                        && herniPole[i-3][j+3] == hrajicihoZnacka && herniPole[i-4][j+4] == hrajicihoZnacka) {
                    System.out.printf("Vítězem se stává: [%c]\n", hrajicihoZnacka); //  Vyhlášení vítěže
                    System.exit(0);                                                 // Ukončení programu
                }
            }
        }

    }
 
Nahoru Odpovědět
15.1.2017 18:30
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 5 zpráv z 5.