Gyakorlati alapok
Chilipaprika zabáltatása algoritmikusan
Adott egy játék: egy tálban szaloncukrok és 1 db chilipaprika található. (Az édesség fajtája természetesen nem lényeges, csupán egy, de fontos tulajdonsága számít, hogy legyen pontosan megszámolható.)
A szaloncukorból 1, 2 vagy 3 darabot húzhatunk. A cél, hogy utolsónak a chilipaprika maradjon és az veszít, akié az utolsó darab. (A játék klasszikus változata szerint ezt a vesztesnek meg kell ennie.) Ha nincs chilipaprika, az veszít, akié az utolsó darab szaloncukor.
A játék mögött természetesen algoritmus húzódik meg, így a beavatott játékos (itt a gép) mindig nyerni fog. A tréfa kedvéért először játsszunk a géppel egy kicsit, de úgy, hogy ne pillantsunk rá a működtető Java-kódra:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int szalonCukorSzam = 17;
int szamlalo = 1;
int aktualisSzam = 0;
int aktualisSzamGep = 0;
String szam = "";
System.out.println("Ön 1, 2 vagy 3 szaloncukrot húzhat.
Az veszít, akié a chilipaprika (vagy az utolsó szaloncukor). Ön kezd!");
Scanner scanner = new Scanner(System.in);
do{
do{
System.out.println("Írja be, hogy " + szamlalo + ". körben hány szaloncukrot
húz! (1-2-3)");
szam =
scanner.nextLine();
}while(!szam.equals("1")
&& !szam.equals("2") && !szam.equals("3"));
aktualisSzam = Integer.parseInt(szam);
szalonCukorSzam -= aktualisSzam;
aktualisSzamGep = 4 - aktualisSzam;
System.out.println("A gép jön és " + aktualisSzamGep + "
db-ot húzott.");
szalonCukorSzam -= aktualisSzamGep;
szamlalo++;
}while(szalonCukorSzam > 1);
System.out.println("Ön vesztett,
mert Ön jön és a tálban " + szalonCukorSzam + " db szaloncukor van.");
}
}
Végeredmény:
Ön 1, 2 vagy 3 szaloncukrot húzhat. Az veszít, akié a
chilipaprika (vagy az utolsó szaloncukor). Ön kezd!
Írja be, hogy hány szaloncukrot húz! (1-2-3)
1
A gép jön és 3 db-ot húzott.
Írja be, hogy hány szaloncukrot húz! (1-2-3)
2
A gép jön és 2 db-ot húzott.
Írja be, hogy hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Írja be, hogy hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Ön vesztett, mert Ön jön és a tálban 1 db szaloncukor van.
A gép nyilvánvalóan nem csal és algoritmikus eszközökkel fog nyerni, ezért most nézzük meg eme rejtély megoldását!
Az első fontos részletet a játék többszöri átjátszása után már észrevehetjük: mindig 4 húzási kör + 1 végkör lesz. Ezt a felismerést megkönnyíti ama tény, hogy az alábbi kódban a körök már jelezve vannak, e nélkül kissé nehezebb, de nem lehetetlen ezen felfedezés. Nézzük meg ezt a bővített verziót is:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int szalonCukorSzam = 17;
int szamlalo = 1;
int aktualisSzam = 0;
int aktualisSzamGep = 0;
String szam = "";
System.out.println("Ön 1, 2 vagy 3 szaloncukrot húzhat.
Az veszít, akié a chilipaprika (vagy az utolsó szaloncukor). Ön kezd!");
Scanner scanner = new Scanner(System.in);
do{
do{
System.out.println("Írja be, hogy " + szamlalo + ". körben hány szaloncukrot
húz! (1-2-3)");
szam =
scanner.nextLine();
}while(!szam.equals("1")
&& !szam.equals("2") && !szam.equals("3"));
aktualisSzam = Integer.parseInt(szam);
szalonCukorSzam -= aktualisSzam;
aktualisSzamGep = 4 - aktualisSzam;
System.out.println("A gép jön és " + aktualisSzamGep + "
db-ot húzott.");
szalonCukorSzam -= aktualisSzamGep;
szamlalo++;
}while(szalonCukorSzam > 1);
System.out.println("Ön vesztett,
mert Ön jön és a tálban " + szalonCukorSzam + " db szaloncukor van.");
}
}
Végeredmény:
Ön 1, 2 vagy 3 szaloncukrot húzhat. Az veszít, akié a
chilipaprika (vagy az utolsó szaloncukor). Ön kezd!
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
e
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
4
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
1
A gép jön és 3 db-ot húzott.
Írja be, hogy 2. körben hány szaloncukrot húz! (1-2-3)
2
A gép jön és 2 db-ot húzott.
Írja be, hogy 3. körben hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Írja be, hogy 4. körben hány szaloncukrot húz! (1-2-3)
4
Írja be, hogy 4. körben hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Ön vesztett, mert Ön jön és a tálban 1 db szaloncukor van.
Amit az örökkön vesztes nem tud, hogy 16 db szaloncukorral + 1 chilipaprikával játszunk, ez összesen 17 db elem, amely páratlan szám. 17 felbontható 4 x 4 + 1 egységre, amelyet alább 1 számmal reprezentálok:
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
1
Ebből következően: mindig 4 húzási kör + 1 végkör lesz, azaz mindig lesz 1 utolsó elem (chilipaprika), ha úgy játszom: mindig annyit húzok, hogy 1 kör összeredménye 4 legyen, azaz:
aktualisSzam + aktualisSzamGep = 4
3 eset lehetséges...
-
aktualisSzam = 1;
-
aktualisSzam = 2;
-
aktualisSzam = 3;
...tehát...
1 + 3 = 4
2 + 2 = 4
3 + 1 = 4
A nyertes nem tesz mást, mint az aktualisSzam + aktualisSzamGep = 4 tartásával úgy manipulálja a szaloncukor mennyiségét, vele a körszámot, hogy az utolsó 5. kör mindig a vesztesre essen.
A kód ugyanakkor járulékos szolgáltatásként egy do-while ciklus segítségével azt is megakadályozza, hogy 1-2-3 számoktól különböző karakterek kerüljenek a rendszerbe:
do{
System.out.println("Írja be, hogy " + szamlalo + ". körben
hány szaloncukrot húz! (1-2-3)");
szam = scanner.nextLine();
}while(!szam.equals("1") && !szam.equals("2") && !szam.equals("3"));
Aki pedig esetleg kételkedik a kód hitelességében, az lefuttathatja az alábbi kódverziót, amelyben minden egyes húzáskor ki lesz írva a pillanatnyi szaloncukor-mennyiség is:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int szalonCukorSzam = 17;
int szamlalo = 1;
int aktualisSzam = 0;
int aktualisSzamGep = 0;
String szam = "";
System.out.println("Ön 1, 2 vagy 3 szaloncukrot húzhat.
Az veszít, akié a chilipaprika (vagy az utolsó szaloncukor). Ön kezd!");
Scanner scanner = new Scanner(System.in);
do{
do{
System.out.println("Írja be, hogy " + szamlalo + ". körben hány szaloncukrot
húz! (1-2-3)");
szam =
scanner.nextLine();
}while(!szam.equals("1")
&& !szam.equals("2") && !szam.equals("3"));
aktualisSzam = Integer.parseInt(szam);
szalonCukorSzam -= aktualisSzam;
aktualisSzamGep = 4 - aktualisSzam;
System.out.println("A tálban " + szalonCukorSzam + " db
szaloncukor van.");
System.out.println("A gép jön és " + aktualisSzamGep + "
db-ot húzott.");
szalonCukorSzam -= aktualisSzamGep;
System.out.println("A tálban " + szalonCukorSzam + " db
szaloncukor van.");
szamlalo++;
}while(szalonCukorSzam > 1);
System.out.println("Ön vesztett,
mert Ön jön és a tálban " + szalonCukorSzam + " db szaloncukor van.");
}
}
Végeredmény:
Ön 1, 2 vagy 3 szaloncukrot húzhat. Az veszít, akié a
chilipaprika (vagy az utolsó szaloncukor). Ön kezd!
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
e
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
4
Írja be, hogy 1. körben hány szaloncukrot húz! (1-2-3)
1
A gép jön és 3 db-ot húzott.
Írja be, hogy 2. körben hány szaloncukrot húz! (1-2-3)
2
A gép jön és 2 db-ot húzott.
Írja be, hogy 3. körben hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Írja be, hogy 4. körben hány szaloncukrot húz! (1-2-3)
4
Írja be, hogy 4. körben hány szaloncukrot húz! (1-2-3)
3
A gép jön és 1 db-ot húzott.
Ön vesztett, mert Ön jön és a tálban 1 db szaloncukor van.