Trädvy Permalänk
Medlem
Registrerad
Maj 2019

Java hjälp layout

Skulle behöva lite hjälp med ett projekt, skall skapa ett tärningsspel.

Jag har kommit halvvägs och det har gått bra men har lite fler saker som måste läggas till, bl.a sum av tärningar/antal slag samt ett alternativ ifall man slår en 6a.
Koden fungerar som den är nu men vill veta om jag har lagt upp det på fel sätt? Bör jag använda mig av arrayer eller looper för att kunna lägga till resterande krav?

import java.util.Scanner; public class dice { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("Hur många tärningar vill du slå? Välj minst 1, max 5"); int choice = sc.nextInt(); int nrOfToss; int dice1 = (int)(Math.random() * 6+1); int dice2 = (int)(Math.random() * 6+1); int dice3 = (int)(Math.random() * 6+1); int dice4 = (int)(Math.random() * 6+1); int dice5 = (int)(Math.random() * 6+1); if (choice == 1) { System.out.println("Tärning 1 = " +dice1); } else if (choice == 2) { System.out.println("Tärning 1 = " +dice1); System.out.println("Tärning 2 = " +dice2); } else if (choice == 3) { System.out.println("Tärning 1 = " +dice1); System.out.println("Tärning 2 = " +dice2); System.out.println("Tärning 3 = " +dice3); } else if (choice == 4) { System.out.println("Tärning 1 = " +dice1); System.out.println("Tärning 2 = " +dice2); System.out.println("Tärning 3 = " +dice3); System.out.println("Tärning 4 = " +dice4); } else if (choice == 5) { System.out.println("Tärning 1 = " +dice1); System.out.println("Tärning 2 = " +dice2); System.out.println("Tärning 3 = " +dice3); System.out.println("Tärning 4 = " +dice4); System.out.println("Tärning 5 = " +dice5); } } }

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Okt 2009

Något i denna stilen skulle funka för att göra ditt program mer skalbart

Alla tärningsslag läggs i en ArrayList så att man lätt kan löpa igenom dem.

Nu saknas ju en koll på huruvida antalet tärningar användaren matar in är mellan 1-5 också...

import java.util.Scanner; import java.util.List; import java.util.ArrayList; public class dice { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("Hur många tärningar vill du slå? Välj minst 1, max 5"); int choice = sc.nextInt(); System.out.println("Du slår " + choice + " tärningar..."); List<Integer> dies = new ArrayList<Integer>(choice); for(int i = 0; i < choice; i++) { int diceValue = (int)(Math.random() * 6 + 1); dies.add(diceValue); } System.out.println("Alla slag: " + dies.toString()); } }

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2007

@LdyUx: Lite oklart vad du menar med "alternativ ifall man slår en 6a", men det verkar ju inte som att du behöver spara tärningsslagen alls. D.v.s. det räcker troligtvis med att bara använda en for-loop där varje tärning skrivs ut direkt utan att sparas. För att räkna ut medelvärdet behöver du bara spara den löpande summan.

Trädvy Permalänk
Medlem
Registrerad
Maj 2019

@Kaizoku: Tack för inputen om en mer clean kodning, tog till mig av det och har korrigerat, ser mycket bättre ut!
@perost:
Om man slår en 6a så ska programmet slå om två tärningar, Jag behöver även skriva ut summan av de slagna tärningarna samt hur många tärningar man har skrivit, antalet tärningar verkar jag ha fått till men inte summan, den blir bara 1, beror nog på min forLoop?
Har du något tips på hur jag ska gå vidare med ifall man slår en 6a? Jag antar att jag behöver använda mig av en If-sats för att bestämma vad som ska hända i så fall?

import java.util.Scanner; import java.util.List; import java.util.ArrayList; public class diceroll { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("Hur många tärningar vill du slå? Välj minst 1, max 5"); int choice = sc.nextInt(); int nrOfRolls; nrOfRolls = 0; int sum; sum= 0; List<Integer> dies = new ArrayList<Integer>(choice); for(int i = 0; i < choice; i++) { int diceValue = (int)(Math.random() * 6 + 1); dies.add(diceValue); nrOfRolls ++; } sum ++; System.out.println("Du fick: " + dies.toString()); System.out.println("Total poäng: " + sum); System.out.println("Antal kast: " + nrOfRolls); } }

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

EDIT: Började skriva detta inlägg innan ditt senaste svar.

Observera hur vissa mönster återkommer väldigt tydligt om och om igen. Du vill istället sträva efter att skriva kod enligt principen Don't Repeat Yourself (DRY); din kod är i dagsläget väldigt "våt" (repetitiv). @Kaizoku är inne på samma linje, men jag vill fästa extra vikt vid att du förstår varför din kod är "våt", varför det är dåligt och hur du kan "torka" den. Därför vill jag uppmana dig att beskriva, för dig själv och gärna för oss, vilka mönster som återkommer och hur du kan abstrahera dem.

Rent praktiskt: Du ska kunna ha, högst upp i ditt program,

private static final MAX_DICE = 5;

och den raden ska avgöra hur många tärningar användaren max kan välja att kasta. Du ska då exempelvis kunna ändra maxantalet till 100 genom att på den raden ändra 5 till 100 utan att ändra någonting annat.

Skrivet med hjälp av Better SweClockers

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2007
Skrivet av LdyUx:

... antalet tärningar verkar jag ha fått till men inte summan, den blir bara 1, beror nog på min forLoop?

sum++ ligger just nu utanför for-loopen, kolla vart du har { } någonstans. Och sum++ är ju dessutom fel, sum++ är samma sak som sum += 1, men det är ju tärningens värde du ska addera och inte 1.

Skrivet av LdyUx:

Har du något tips på hur jag ska gå vidare med ifall man slår en 6a? Jag antar att jag behöver använda mig av en If-sats för att bestämma vad som ska hända i så fall?

Ja, använd en if-sats. Du kan slå extra tärningar antingen genom att minska i i for-loopen, eller genom att öka choice. Om du väljer att öka choice så behöver du inte nrOfRolls, eftersom choice kommer ha samma värde (nrOfRolls är ju dock ett mer beskrivande namn).

Trädvy Permalänk
Medlem
Registrerad
Maj 2019

@perost: Tack, jag löste sum nu så den biten fungerar!
Bör IF-satsen läggas i eller utanför For-loopen? Är lite osäker på hur jag skall bygga upp den, förmodar att jag inte kan loopa tillbaka till ursprungskoden där den tar fram antalet tärningar utifrån choice eftersom att det specifikt ska slås om två tärningar om man slår en sexa och sen efter det lägga till det i resultatet...

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2007

@LdyUx: Det är fortfarande lite oklart vad som menas med att slå om tärningar. Ska programmet slå om redan slagna tärningar? Eller ska 6:an slängas bort och sen ska två nya tärningar slås istället?

Jag misstänker att det kanske är det andra alternativet, d.v.s. att det ska slås nya tärningar. I så fall kan du ha en if-sats inne i for-loopen som kollar om den slagna tärningen är en 6:a. Du kan ändra värdena på i och choice inne i loopen för att påverka hur loopen körs. Man kan skriva om loopen på följande sätt, det kanske hjälper dig att förstå hur allt hänger ihop:

int choice = 6; int i = 0; while (i < choice) { ...kod som ska upprepas... i++; }

Sen finns det två olika synsätt på hur man slår tärningarna. Antingen kan man se det som att man ignorerar 6:an och slår två extra tärningar (choice += 2), eller så slår man om 6:an och slår en extra tärning (i--, choice++). choice kommer i båda fallen innehålla antalet tärningar som slagits, men inklusive alla 6:or i det förstnämnda alternativet och exklusive alla 6:or i det sistnämnda.

Trädvy Permalänk
Medlem
Registrerad
Maj 2019

@perost: Tack för förtydligande av koden, det känns mer bekant nu och jag ser lättare hur allt hänger ihop och fungerar!
Koden fungerar relativt bra nu, men jag fattar inte hur jag ska få bort sexorna i summeringen? Som det ser ut nu så körs programmet precis så som jag vill ha det om inga sexor slås, när en/flera sexor slås så slår den två tärningar till men sexorna finns fortfarande med och samlas upp i slutet och räknas med i totalen, hur får jag bort sexorna? Har provat allt möjligt och vridit och vänt på min If sats men jag får inte till det...
I koden nedan så ser man att jag lagt till något som heter diceValue2, men det fungerar inte heller riktigt som jag vill att det ska göra... Är jag på rätt spår?

import java.util.Scanner; import java.util.List; import java.util.ArrayList; public class dice { public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("Hur många tärningar vill du slå? Välj minst 1, max 5"); int choice = sc.nextInt(); int nrOfRolls; nrOfRolls = 0; int result; result = 0; List<Integer> dies = new ArrayList<Integer>(choice); int i = 0; while (i < choice) { int diceValue = (int)(Math.random() * 6 + 1); dies.add(diceValue); nrOfRolls ++; result = result + diceValue; i++; if (diceValue == 6){ i--; choice++; System.out.println("Du fick: " + dies.toString()); System.out.println("6or är ogilitiga, två nya tärningar slås"); int diceValue2 = (int)(Math.random() * 6 + 1); dies.add(diceValue2); nrOfRolls ++; result = result + diceValue2; i++; } else { } } System.out.println("Du fick: " + dies.toString()); System.out.println("Total poäng: " + result); System.out.println("Antal kast: " + nrOfRolls); } }

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2007

@LdyUx: Jag menade inte riktigt att du skulle ersätta for-loopen med en while-loop, det var mest bara för att demonstrera vad for-loopen egentligen gör. Det går förstås att lösa det med en while-loop om du vill, man kan alltid ersätta en for-loop med en while och tvärtom, men en for-loop blir mindre kod att skriva i det här fallet.

För att inte räkna 6:orna så låter du helt enkelt bli att lägga till dem i listan, just nu lägger du till alla tärningsslag innan du kontrollerat värdet. Sen är hela poängen med att ändra på värdena som styr loopen att du kan få loopen att köra extra varv, d.v.s. du behöver inte ha kod i loopen som slår extra tärningar. I pseudokod skulle det se ut ungefär så här:

choice = antal tärningar att slå dice = tom lista för i från 1 till choice: die = slumpa tärning om die är 6: i-- // Slå om denna tärning choice++ // Slå en extra tärning annars: lägg till die i dice

Loopen slår alltså endast en tärning per varv, men genom att ändra på variablerna som styr loopen så körs extra varv. Se dock till att du förstår mitt förra inlägg om varför man kanske vill ändra på både i och choice, det är en sån där sak som läraren kanske frågor dig om för att kolla att du faktiskt förstår koden du skrivit.

Tillägg: Just ja, du kan få ut längden på listan genom dies.size(), så du behöver egentligen inte räkna tärningarna med en separat variabel.

Sen om man ska vara lite petig så är die = en tärning, dice = flera tärningar, dies = verbet dör, eller t.ex. formar för metall. Inte för att Java bryr sig

Trädvy Permalänk
Medlem
Registrerad
Maj 2019

@Kaizoku: Skulle du kunna förklara denna kodrad som du skrivit i ditt förslag på hur jag kan lägga upp programmet lite mer specifikt? Tror jag behöver förstå hur den används/fungerar för att jag ska kunna färdigställa mitt program.

List<Integer> dies = new ArrayList<Integer>(choice);

Trädvy Permalänk
Medlem
Plats
Linköping
Registrerad
Jun 2007

@LdyUx: Har du använt vanliga arrayer i Java? Du kan deklarera en array som t.ex.:

int arr[] = new int[10];

Detta skapar en ny array med 10 element. Om du inte har använt arrayer tidigare så bör du börja med att lära dig hur dessa fungerar innan du går vidare.

Men problemet i det här fallet, och i många andra fall, är att du inte vet hur stor array du faktiskt behöver i förväg. Och det går inte att ändra storleken på en array när man väl allokerat den, så vad man får göra om man behöver en större array är att helt enkelt allokera en ny array (t.ex. dubbelt så stor) och flytta över datan till den. Detta är precis vad ArrayList är, d.v.s. en ArrayList innehåller en array som automatiskt allokeras om när det behövs så att man slipper göra det själv.

Så vad raden du undrade över gör är helt enkelt att skapa en ny ArrayList med en initial kapacitet av choice element. Detta betyder inte att den innehåller choice element i början, utan bara att det finns kapacitet att lägga till choice element innan arrayen den innehåller behöver allokeras om. Det finns inget tvång att ange en initial kapacitet, men vet man ungefär hur många element man kommer lägga till så kan man undvika onödiga omallokeringar och få bättre prestanda (vilket inte spelar någon större roll i ett sånt här program).

Trädvy Permalänk
Medlem
Plats
Göteborg
Registrerad
Okt 2009

Mycket väl förklarat @perost! Väldigt pedagogiskt

@LdyUx:
Tanken med att göra det på det sättet är att samla alla dina tärningsslag på ett ställe! Du kan sedan enkelt använda den listan för att exempelvis löpa igenom och summera tärningsslagen, hitta om något slag är en sexa eller kanske bara printa ut dem med någon fin formatering. Allt detta kan du givetvis göra redan i den första loopen då programmet är relativt simpelt och inte behöver spara undan slagen egentligen!

Min tanke med att spara undan var att kunna göra något i denna stilen (pseudokod):

public static void main(...) { // läs in antal slag // for(antal slag) { // slumpa tal // lägg in i lista // } } /* ytterligare funktioner för utökad funktionalitet */ public static int sum(lista) { // löp igenom lista och summera // returnera summa } public static void printSix(lista) { // löp igenom lista och printa ut om värdet är en sexa }

Jag själv föredrar den typen utav programmering snarare än att låta metoder bli s.k. guda-metoder som löser alla problem. Lite mer dekorativt åt folket

I detta fallet är som sagt problemet så pass simpelt att det går minst lika bra att summera och printa sexor redan i den första for-loopen. Att ha separata metoder för i detta fallet är egentligen overkill och gör det hela bara mer förvirrande eftersom operationerna är så enkla.

Edit: korvfingrade iväg ett svar för tidigt

Trädvy Permalänk
Medlem
Registrerad
Maj 2019

@Kaizoku:
@perost:

Tusen tack för all hjälp, koden såg i slutändan lite annorlunda ut mot vad ni rekommenderade men programmet fungerar och jag förstår Hur det fungerar, så tack!