Problem med en while-loop i java

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008

Problem med en while-loop i java

Har suttit och kliat mig i huvudet ett tag och har kommit fram till att jag är alldelles för trött för att lösa uppgiften själv.
Så jag tänkte höra med er om ni kanske kan ge mig någon insyn i vad som går fel.

Scanner keyboard = new Scanner(System.in); GameBoard myGame = new GameBoard(); myGame.drawBoard(); int counter = 1; boolean keepPlaying = true; String choice = null; while (keepPlaying) { while(myGame.gameActive() && counter < 10 && keepPlaying) { if (counter % 2 == 0 ) myGame.askPlayer('O'); else myGame.askPlayer('X'); counter++; System.out.println("\n"); myGame.drawBoard(); myGame.checkForWinner(); if(counter == 10) { System.out.println("It's a draw!"); } } System.out.println("Want to play again? Yes or no"); choice = keyboard.nextLine(); if (choice.equals("No") || choice.equals("no")) { keepPlaying = false; } else if (choice.equals("Yes") || choice.equals("yes")) { //kod här } } System.out.println("Thanks for playing!");

problemet jag här är att när jag kommer till den sista if-else så gör den inte riktigt som jag vill.
Skriver jag in No så avslutas spelet precis som väntat, men skriver jag Yes så fortsätter den printa "Want to play again?".
Får samma resultat oavsett om choice.equals("yes") är med eller inte, och skriver jag in break; eller return; inom måsvingarna så avbryts det även vid yes (vilket är väntat). Resultatet jag är ute efter är att loopen börjar om från steg 1.
Vad är det jag har missat?

Tack på förhand

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns

Trädvy Permalänk
Medlem
Plats
Skottland, Schweiz, Sverige
Registrerad
Dec 2010

@MaxieTheHatter Har du glömt att återställa counter ser det ut som?
*Edit*
För att förtydliga, sätt counter till 1 igen i 'else if' biten, annars så är counter större än 10 när den kollar whileloopen igen

|ASUS Maximus IV | Intel 2600K | H80 | ASUS STRIX DCU III GTX980TI| | OCZ ZX 1250W 80+ Gold | 1TB WD Caviar Black | Crucial M4 128GB | |SSD Samsung Basic 500GB SSD | HAF X | Samsung BD-reader | 16GB Corsair Vengence 1600MHz |

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008
Skrivet av danielmw2:

@MaxieTheHatter Har du glömt att återställa counter ser det ut som?
*Edit*
För att förtydliga, sätt counter till 1 igen i 'else if' biten, annars så är counter större än 10 när den kollar whileloopen igen

Tack för svar!
Tänkte på det jag också, men det gjorde ingenting så jag tog ut det igen.

För tillfället ser det ut såhär:

if (choice.equals("No") || choice.equals("no")) { keepPlaying = false; } else if (choice.equals("Yes") || choice.equals("yes")) { myGame.gameActive(); counter = 1; continue; }

Men den tar sig fortfarande inte ut ur if-else satsen vid yes

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns

Trädvy Permalänk
Medlem
Plats
Trollhättan
Registrerad
Sep 2014

Byt plats på myGame.gameActive() och counter = 1; ta bort continue. Och convertera choice till lowerCase

Skickades från m.sweclockers.com

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008
Skrivet av zmet:

Byt plats på myGame.gameActive() och counter = 1; ta bort continue. Och convertera choice till lowerCase

Skickades från m.sweclockers.com

Antar att jag konverterar till lowerCase för att slippa följande?

if (choice.equals("No") || choice.equals("no"))

och istället använda

if (choice.equals("no"))

Att byta plats på myGame.gameActive() och counter = 1; gjorde dessvärre ingen skillnad, sitter fortfarande fast i loopen

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Sep 2008
Skrivet av MaxieTheHatter:

Antar att jag konverterar till lowerCase för att slippa följande?

if (choice.equals("No") || choice.equals("no"))

och istället använda

if (choice.equals("no"))

Att byta plats på myGame.gameActive() och counter = 1; gjorde dessvärre ingen skillnad, sitter fortfarande fast i loopen

Antingen tar du emot användarens svar, lagrar i en variabel och explicit konverterar till lowercase eller så kan du använda equalsIgnoreCase och säga till att du inte bryr dig om svaret är no, No, nO eller NO utan tolka samtliga som samma.

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008

Ändrade nu till följande

System.out.println("Want to play again? Yes or no"); String choice = keyboard.nextLine(); if (choice.equalsIgnoreCase("no")) { keepPlaying = false; } else if (choice.equalsIgnoreCase("yes")) { counter = 1; myGame.gameActive(); }

fungerar inte som tänkt, men det ser mycket snyggare ut! Och jag kan även skriva in NO istället för bara No eller no

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns

Trädvy Permalänk
Medlem
Plats
Skottland, Schweiz, Sverige
Registrerad
Dec 2010
Skrivet av MaxieTheHatter:

Ändrade nu till följande

System.out.println("Want to play again? Yes or no"); String choice = keyboard.nextLine(); if (choice.equalsIgnoreCase("no")) { keepPlaying = false; } else if (choice.equalsIgnoreCase("yes")) { counter = 1; myGame.gameActive(); }

fungerar inte som tänkt, men det ser mycket snyggare ut! Och jag kan även skriva in NO istället för bara No eller no

Prova att ta bort "myGame.gameActive();", så borde den gå tillbaka till starten av loopen igen (i else if biten).

|ASUS Maximus IV | Intel 2600K | H80 | ASUS STRIX DCU III GTX980TI| | OCZ ZX 1250W 80+ Gold | 1TB WD Caviar Black | Crucial M4 128GB | |SSD Samsung Basic 500GB SSD | HAF X | Samsung BD-reader | 16GB Corsair Vengence 1600MHz |

Trädvy Permalänk
Entusiast
Testpilot
Plats
Chalmers
Registrerad
Aug 2011

Ah, imperativ programmering i sitt esse.

Ett globalt tillstånd (en. global state) (counter, keepPlaying och choice) som man modifierar och accessar här och var i koden är typiskt för denna paradigm, och tenderar att göra koden svårläst och mycket svår att felsöka när den växer.

Kod kan vara mer eller mindre imperativ, även i imperativa språk som Java. Den som vill skriva kod som är lättare att förstå, felsöka och få att fungera i alla lägen kan arbeta för att undvika modifierbara tillstånd och istället sikta på referentiell transparens i så stor utsträckning som möjligt. En nyckelmetod för att uppnå sådan är att bryta ut kod till äkta funktioner (en. pure function), som alltid returnerar samma resultat för samma argument, och aldrig modifierar eller bryr sig om något tillstånd utanför funktionen.

Ett enkelt exempel på en äkta funktion i Java:

public static int sum(final int[] numbers) { int result = 0; for (int i = 0; i < numbers.length; i++) { result += numbers[i]; } return result; }

Den metoden är (i all väsentlighet) en äkta funktion, ty den returnerar alltid samma resultat för samma argument, den modifierar inget globalt tillstånd (dvs den har inga sidoeffekter) och dess resultat påverkas inte av något globalt tillstånd.

Koden inuti metoden är imperativ, men metoden som helhet är referentiellt transparent, dvs när man använder den behöver man inte oroa sig för att den ska modifiera något eller att den kommer returnera fel resultat. Har man väl testat att funktionen fungerar som man vill kommer den alltid göra det, oavsett värdet på counter eller andra tillstånd som är svåra att hålla koll på.

Motsatsen till imperativ programmering (att säga åt datorn att göra vissa saker i en viss ordning) kallas deklarativ programmering och kan sammanfattas som att beskriva för datorn vad varje uttryck har för värde.

Skrivet med hjälp av Better SweClockers

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Sep 2008
Skrivet av MaxieTheHatter:

Ändrade nu till följande

System.out.println("Want to play again? Yes or no"); String choice = keyboard.nextLine(); if (choice.equalsIgnoreCase("no")) { keepPlaying = false; } else if (choice.equalsIgnoreCase("yes")) { counter = 1; myGame.gameActive(); }

fungerar inte som tänkt, men det ser mycket snyggare ut! Och jag kan även skriva in NO istället för bara No eller no

Ett tips, varför är else if satsen väsentlig. Vad tillför den till din kod?

Se det såhär, du har två vägar att gå. Antingen vill spelaren avsluta eller spela igen. Du behöver bara hantera en av dessa vägar, eftersom den andra kommer leda dig tillbaka till början i vilket fall som helst. Else if satsen är överflödig och istället sätt in all väsentlig kod för att påbörja ett nytt spel i början av while (keepPlaying)

Exempelvis:

while (keepPlaying) { myGame = new GameBoard(); myGame.drawBoard(); int counter = 1; boolean keepPlaying = true; String choice = null; while(myGame.gameActive() && counter < 10 && keepPlaying) { if (counter % 2 == 0 ) myGame.askPlayer('O'); else myGame.askPlayer('X'); counter++; System.out.println("\n"); myGame.drawBoard(); myGame.checkForWinner(); if(counter == 10) { System.out.println("It's a draw!"); } } System.out.println("Want to play again? Yes or no"); choice = keyboard.nextLine(); if (choice.equals("No") || choice.equals("no")) { keepPlaying = false; } }

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008
Skrivet av Razki:

Ett tips, varför är else if satsen väsentlig. Vad tillför den till din kod?

Se det såhär, du har två vägar att gå. Antingen vill spelaren avsluta eller spela igen. Du behöver bara hantera en av dessa vägar, eftersom den andra kommer leda dig tillbaka till början i vilket fall som helst. Else if satsen är överflödig och istället sätt in all väsentlig kod för att påbörja ett nytt spel i början av while (keepPlaying)

Exempelvis:

while (keepPlaying) { myGame = new GameBoard(); myGame.drawBoard(); int counter = 1; boolean keepPlaying = true; String choice = null; while(myGame.gameActive() && counter < 10 && keepPlaying) { if (counter % 2 == 0 ) myGame.askPlayer('O'); else myGame.askPlayer('X'); counter++; System.out.println("\n"); myGame.drawBoard(); myGame.checkForWinner(); if(counter == 10) { System.out.println("It's a draw!"); } } System.out.println("Want to play again? Yes or no"); choice = keyboard.nextLine(); if (choice.equals("No") || choice.equals("no")) { keepPlaying = false; } }

Mycket bra exempel, den fungerade nästan!
När jag satte keepPlaying utanför while-loopen så fick jag det att fungera som önskat.
Tack för hjälpen och intressant lösning allihopa!
Koden som fungerar:

public static void main(String[] args) { Scanner keyboard = new Scanner(System.in); boolean keepPlaying = true; while (keepPlaying) { GameBoard myGame = new GameBoard(); myGame.drawBoard(); int turnCounter = 1; while(myGame.gameActive() && turnCounter < 10 && keepPlaying) { if (turnCounter % 2 == 0 ) myGame.askPlayer('O'); else myGame.askPlayer('X'); turnCounter++; System.out.println("\n"); myGame.drawBoard(); myGame.checkForWinner(); if(turnCounter == 10) { System.out.println("It's a draw!"); } } System.out.println("Want to play again? Yes or no"); String choice = keyboard.nextLine(); if (choice.equalsIgnoreCase("no")) { keepPlaying = false; } } System.out.println("Thanks for playing!"); }

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns

Trädvy Permalänk
Medlem
Registrerad
Okt 2015

@MaxieTheHatter: En pointer är också att du skriver "it's a draw", varför flyttar du inte in den biten in i check for winner och löser all utskrift där? Skicka bara med counter som variabel in i metoden.

Trädvy Permalänk
Medlem
Plats
Stockholm
Registrerad
Okt 2008
Skrivet av for_each_while:

@MaxieTheHatter: En pointer är också att du skriver "it's a draw", varför flyttar du inte in den biten in i check for winner och löser all utskrift där? Skicka bara med counter som variabel in i metoden.

Tack för förslaget, löste ett problem jag inte ännu upptäckt, nämligen att man får en vinnare och oavgjort om någon vinner på sista draget.
La in följande i checkForWinner

if(turnCounter == 10 && gameIsGoing) { System.out.println("It's a draw!"); gameIsGoing = false; }

Dator 1: i7 5820k | Asus X99-S | 16GB DDR4 | GTX 1080ti SLI | NZXT H440
Dator 2: i7 5820k | Asrock X99M | 32GB DDR4 | GTX 970 | SC-512N1-L Capture Card | Fractal Design Node 804
Skärm:Philips BDM4065UC
Mixer: Behringer X2222USB
Mina bästa tider inom speedruns