Permalänk
Medlem

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

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1

Permalänk

@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

Visa signatur

ASUS Crosshair Hero VII Wifi | R7 3700X| ASUS STRIX DCU III GTX980TI| 32 GB DDR4 3200MHz |

Permalänk
Medlem
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

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1

Permalänk
Medlem

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

Skickades från m.sweclockers.com

Permalänk
Medlem
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

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1

Permalänk
Medlem
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.

Permalänk
Medlem

Ä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

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1

Permalänk
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).

Visa signatur

ASUS Crosshair Hero VII Wifi | R7 3700X| ASUS STRIX DCU III GTX980TI| 32 GB DDR4 3200MHz |

Permalänk
99:e percentilen

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.

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Medlem
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; } }

Permalänk
Medlem
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!"); }

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1

Permalänk

@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.

Permalänk
Medlem
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; }

Visa signatur

Stationär: Core i9 13900k | Asus X790 ROG Strix Gaming-F | 32GB DDR5 | RX 7900 XT | Lian Li PC-O11 dynamic evo
Laptop: Macbook Air | Apple M1