16 svar
321 visningar
civilingengör är nöjd med hjälpen
civilingengör 193
Postad: 29 mar 2022 16:25

simulering av kortspel

Hej! Varför får jag detta felmeddelande? Och vad är fel med min kod? Jag är medveten om att min kod innehåller fel. Koden skall simulera ett spel patiens som beskrivs en liga följande: 

"Patiensen 1–2–3 läggs på följande sätt: Man tar en kortlek, blandar den och lägger sedan ut korten ett efter ett. Samtidigt som man lägger korten räknar man 1–2–3–1–2–. . . , det vill säga när man lägger det första kortet säger man 1, när man lägger det andra kortet säger man 2, osv. Patiensen går ut om man lyckas lägga ut alla kort i leken utan att någon gång få upp ett ess när man säger 1, någon 2-a när man säger 2 eller någon 3-a när man säger 3.

Bestäm med hjälp av sannolikhetslära bestämma exakt hur stor sannolikheten är att patiensen ska gå ut. Patiensen skall alltså läggas många gånger och man ska räkna antalet gånger som den går ut."

Min kod ser ut enligt följande:

Laguna 28468
Postad: 29 mar 2022 17:27

Det står att a är null på rad 24. a kommer från card.pick(), men vi ser inte hur den ser ut.

Fermatrix 7841 – Fd. Medlem
Postad: 29 mar 2022 17:35

Ett starkt tips jag kan ge dig i övrigt är att använda dig av debugging mode. Det är verkligen din bästa vän eftersom du då kan följa koden och se varför a fortfarande är null. Kanske har du en bugg? Kanske har du glömt sätta a osv.

Annars kan du göra det en vana att visa all kod när du ber om hjälp. Vad jag har sett brukar du ha 3-4 klasser som alla interagerar med varandra och då är det extremt svårt att veta vart felet ligger om vi inte kan se all relevant kod! :)

civilingengör 193
Postad: 29 mar 2022 18:40

Tack! Jag testar nu med debuggern. Här är koden till metoderna:

CurtJ 1143
Postad: 29 mar 2022 18:41

Du använder returvärdet null för att signalera att korten i leken är slut. Då måste du också hantera det returvärdet när du anropar pick()

civilingengör 193
Postad: 29 mar 2022 18:54

Men enligt debuggern returneras "null" redan då iter = 8

CurtJ 1143
Postad: 29 mar 2022 18:59

Ja och i loopen "while (iter < ..." så har en en loop till "for (int k ... " så när iter är 8 så har du exekverat pick() 24 gånger. Det börjar närma sig de korten du har i leken.

civilingengör 193
Postad: 29 mar 2022 19:03

Okej jag tror jag förstår. Värdet av "a" kommer alltså tillslut bli null vilket måste hanteras. regleras inte redan detta av villkoret while(card.more())? Eftersom loopen inte kommer köra då det inte finns fler kort i kortleken?

CurtJ 1143
Postad: 29 mar 2022 19:05

Nja problement är nog att du exekverar pick() 3 ggr efter att du  kontrollerat card.more() så finns det två par kvar så smäller det.
Det är bra att testa sig  fram så som du gör. Det är så man lär sig den hårda vägen. Jag kan ge dig lite feedback  på din konstruktion om du vill

CurtJ 1143
Postad: 29 mar 2022 19:33

Här är några kommentarer om du vill. Ignorera annars.

 

Visa spoiler

I din main skapar du en kortlek (PairSet) som du skall använda. Sen utför du din patiens med den kortleken NBT_ITERATIONS gånger och eftersom kortleken håller reda på hur många kort du dragit så måste du väl skapa en ny kortleksinstans i varje iteration.

Variabeln nopatiens används inte. Då bör den tas bort

while (iter < NBR_ITERATIONS && avsluta) { ...}
Här har du två villkor och det andra sätter du false när du passerar NBR_ITERATIONS-1 vilket innebär att båda villkoren är samma sak så du kan ta bort avsluta helt. Dessutom är namnet på variabeln väldigt missvisande. Heter den avsluta så bör den ju va true när loopen ska avslutas. Men som sagt, ta bort den helt.

if () {

} else if () {}

Där behöver du inte ha något villkor i else if (). Är (a.second != k) falskt så är
a.second() == k alltid sant.

Var sätter du win för övrigt?

I PairSet så ska du lagra din kortlek. Du kanske kunde kalla klassen Deck i stället för att visa det.
När du sen populerar den i konstruktorn så räknar du lite konstigt. Jag skulle nog populera korten i två loopan, en för färg och en för valör. Jag skulle dessutom göra färg och valör till enum men det kan va överkurs, dina siffror funkar bra men det blir ite svårare att debugga.

I PairSet.more så gör du ett fel som man ser ofta i produktionskod. Du kontrollerar om ett villkor är sant och då returnerar du sant, annars falskt. Det rätta är att alltid returnera villkoret
public boolean more() {
return (n>0)
}

PairSet.pick() skulle jag nog lösa med att pairs låg i en ArrayList där du kan plocka ur element utan att skyffla element själv. Det blir enklare och säkrare.

civilingengör 193
Postad: 29 mar 2022 19:58 Redigerad: 29 mar 2022 20:17

Ja gärna! Jag har också märkt att jag lär mig bäst av att testa mig fram. Just denna metod har jag inte alls mycket tid på mig att redovisa, fick 2 dagar på mig att jobba med den och av den anledningen behöver jag lite extra hjälp. Du får gärna ge mig feedback, jag vill alltid bli bättre:) 

Här är den uppdaterade versionen:

Här är kod för metoderna:

CurtJ 1143
Postad: 29 mar 2022 21:54

Jag har gjort en implementation som du kan titta på som i stort följer de förslag jag visade i svar #10. Det är nog inte kutym enl pluggakutens regler att "hjälpa" med fullständiga lösningar men det tar lite för lång tid att iterera lösningar fram och tillbaks så du får ett exempel med kommentarer som du kan titta på. Se det som en av alla möjliga lösningar, jag hade nog modifierat den lite med lite "modernare" javastuk men för att hålla det enkelt så gjorde jag såhär. Använd det du vill, ändra och fråga om det är något mer du funderar över.

 

Visa spoiler

Definition av kort-klassen
package base;


public class Card {
	/*
	 * Representation av ett kort
	 * Lagra färg och värde som heltal som börjar på 1
	 */
	private int color; 
	private int value; 
	
	public Card (int color, int value) {
		this.color = color; 
		this.value = value; 
	}
	
	
	public int getColor() {
		return color; 
	}
	
	public int getValue() {
		return value; 
	}


	@Override
	public String toString() {
		return "Card [color=" + color + ", value=" + value + "]";
	}
	
}

 

Kortlek:

package base;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/*
 * Representation av en kortlek, numeriska värden på färg och valör
 */
public class Deck {
	
	/*
	 * Standardstorlek på kortlek
	 */
	private static final int NUM_COLORS = 4;
	private static final int NUM_VALUES = 13; 
	
	/*
	 * Lagra i en ArrayList som tillåter dig att plocka ur element 
	 */
	private List<Card>  cards = new ArrayList<Card>(NUM_COLORS*NUM_VALUES);
	
	/*
	 * Slumptalsgenerator som men initierar med aktuell tid så får man olika 
	 * resultat för varje körning
	 */
	private Random random = new Random(new Date().getTime()); 
	
	public Deck() {
		/*
		 * Initiera kortleken
		 */
		for (int color = 0; color<NUM_COLORS; color++) {
			for (int value = 0; value < NUM_VALUES; value++) {
				/*
				 * Färg och värde börjar på 1
				 */
				cards.add(new Card(color+1,value+1));
			}
		}
	}
	
	/*
	 * Finns det kort kvar i leken
	 */
	public boolean more() {
		return cards.size()>0;
	}
	
	/*
	 * Plocka ett kort slumpmässigt ur leken och returnera
	 */
	public Card pick() {
		int cardIdx = random.nextInt(cards.size());
		return cards.remove(cardIdx);
	}
}

Main-klassen

package base;

/*
 * Drivare för att köra ett antal rundor av en patiens och 
 * beräkna sannolikheten att den går ut
 */
public class Patiens {

	private static final int NUM_ITERATIONS = 1000000;
	
	public static void main(String[] args) {
		Patiens pat = new Patiens(); 		
		pat.doRun();
	}
	public void doRun() {
		int iter = 0; 		// Antalet körningar
		int loss = 0;		// Antalet förluster
		
		while (iter < NUM_ITERATIONS) {
			Deck cards = new Deck(); 
			/*
			 * Börja med att räkna 1
			 */
			int stack = 1;  	// Iterator for stacks
			
			/*
			 * Kör så länge det finns kort i leken
			 */
			do {
				/*
				 * Slumpa ett kort
				 */
				Card card = cards.pick();
				
				/*
				 * Om valören stämmer med 1-2-3-räknaren så har gick den inte ut
				 */
				if (card.getValue() == stack) {
					loss++;
					break;
				}
				/*
				 * Öka räknaren till 3 och börja på 1 igen
				 */
				if (++stack > 3) {stack = 1;}
				
			} while (cards.more());
			iter++;
		}
		System.out.println(String.format("Sannolikheten för att patiensen går ut är %f procent, %d loss", 100.0*(NUM_ITERATIONS-loss)/NUM_ITERATIONS, loss));
	}
}
civilingengör 193
Postad: 30 mar 2022 08:24

Hej igen, jag har arbetat lite med klasen och har nu detta resultat, vilket är ett lägre värde än vad det borde ( ska bli ungefär 0.008). Vart finns felet? Min debug genererar ingen output. Jag ska kolla på din kod nu. Tusen tack!

Uppdaterad kod:

Fermatrix 7841 – Fd. Medlem
Postad: 30 mar 2022 08:43

Tänk på att iter och win båda är en int. Antingen gör du om win till en double eller så får du casta resultatet.

civilingengör 193
Postad: 30 mar 2022 10:10

Ja tack jag märkte det...men det är ordnat nu. Dock är svaret fortfarande inte helt korrekt:

Laguna 28468
Postad: 30 mar 2022 10:30

Står det någonstans hur patiensen går till?

civilingengör 193
Postad: 1 apr 2022 06:52

Ja, högst upp i tråden. Jag har nu lyckats lösa koden. Tack så mycket för allas tid och hjälp! Jag önskar er en fin dag :)

Svara Avbryt
Close