Kod-fel i klass Turtle
Hej! Jag har skrivit kod i klassen Turtle som sedan skall testköras i en given klass TurtleTest, som skall visa om koden jag skrivit i Turtle är korrekt. Nedan finns min kod bifogad samt resultatet av testet. Hur skall detta åtgärdas? Tacksam för svar.
Du bör göra tester på de enskilda funktionerna innan du testar helheten.
Det kallas för unit-tester och är också bra på att fånga upp nya fel som introduceras när man man gör ändringar.
När du testar helheten så är det svårt att se vilka fel om är inblandade.
Exempel: forward(). Sätt koordinaterna och riktningen till något absolut värde. Gör forward() med känt värde. Kontrollera att x och y uppdaterats till rätt (handberäknad) plats.
Sen vrider du riktning och gör samma sak, testar att du kom till förväntad position. Se till att alla typer av rörelser är med.
Du bör städa upp en del risker och några fel. Exempel:
penUp() och penDown() ändrar inte värdet på din klass-variabel isPenDown eftersom du sätter värdet på en lokalt deklarerad variabel.
isPenDown är static, dvs delas mellan alla Turtle-objekt. Det kan inte fungera.
Ett bra sätt att undvika ihopblandning av lokala variabler och klassvariabler är att ALLTID referera klassvariabler med prefixet "this."
Ett annat sätt är att namnge klassvariabler med prefixet "_" ("this." är vanligast, jag föredrar "_").
Det ser inte ut som du har ordning på klassvariablerna x och y respektive x och y i SimpleWindow. Antingen jobbar du med egna variabler i klassen och har ett och endast ett ställe då du sätter motsvarigheten i SimpleWindow, eller så använder du alltid x och y i SimpleWindow (och skippar egna x och y).
Du har getX() och getY() men där sätter du inte dina x och y så de gör ingenting.
forward(): ser ut som du ritar när pennan är uppe och inte när den är nere (men som sagt, din isPenDown ändras aldrig, exempel på samverkande fel).
turnNorth använder radianer, övrig kod antar grader.
Programmeraren skrev:Du bör göra tester på de enskilda funktionerna innan du testar helheten.
Det kallas för unit-tester och är också bra på att fånga upp nya fel som introduceras när man man gör ändringar.
När du testar helheten så är det svårt att se vilka fel om är inblandade.Exempel: forward(). Sätt koordinaterna och riktningen till något absolut värde. Gör forward() med känt värde. Kontrollera att x och y uppdaterats till rätt (handberäknad) plats.
Sen vrider du riktning och gör samma sak, testar att du kom till förväntad position. Se till att alla typer av rörelser är med.Du bör städa upp en del risker och några fel. Exempel:
penUp() och penDown() ändrar inte värdet på din klass-variabel isPenDown eftersom du sätter värdet på en lokalt deklarerad variabel.
isPenDown är static, dvs delas mellan alla Turtle-objekt. Det kan inte fungera.
Ett bra sätt att undvika ihopblandning av lokala variabler och klassvariabler är att ALLTID referera klassvariabler med prefixet "this."
Ett annat sätt är att namnge klassvariabler med prefixet "_" ("this." är vanligast, jag föredrar "_").Det ser inte ut som du har ordning på klassvariablerna x och y respektive x och y i SimpleWindow. Antingen jobbar du med egna variabler i klassen och har ett och endast ett ställe då du sätter motsvarigheten i SimpleWindow, eller så använder du alltid x och y i SimpleWindow (och skippar egna x och y).
Du har getX() och getY() men där sätter du inte dina x och y så de gör ingenting.forward(): ser ut som du ritar när pennan är uppe och inte när den är nere (men som sagt, din isPenDown ändras aldrig, exempel på samverkande fel).
turnNorth använder radianer, övrig kod antar grader.
Tack! Jag tycks ha korrigerat detta med boolean men ändå ritas streck när det "nedan skall vara tomt". Jag antar att metoden forward inte är korrekt skriven, dock lyckas jag inte komma på vad felet kan vara.
Jag håller även på att testa övriga metoder enskilt, som du tipsade om. Jag återkommer om jag inte lyckas lösa det. Tack så mycket för din hjälp!
Finns ingen anledningen att ha if-satserna i penUp() och penDown(), du vill ju bara sätta ett värde. De är förvirrande och dessutom fel, penUp() kommer ju att kontrollera att det inte redan är penDown så det kommer inte göra något (penDown har motdvarande fel). Kan vara det som ger att den ritar/inte ritar.
I slutet av forward avrundar du x1 och y1 på två olika sätt och på flera ställen. Det är inte snyggt, tilldela först dina x och y med korrekt avrundning, sen sätter du moveTo/lineTo till x,y.
I forward() har getDirection() har ingen funktion, samma fel som w.getX() hade i getX().
Programmeraren skrev:Finns ingen anledningen att ha if-satserna i penUp() och penDown(), du vill ju bara sätta ett värde. De är förvirrande och dessutom fel, penUp() kommer ju att kontrollera att det inte redan är penDown så det kommer inte göra något (penDown har motdvarande fel). Kan vara det som ger att den ritar/inte ritar.
I slutet av forward avrundar du x1 och y1 på två olika sätt och på flera ställen. Det är inte snyggt, tilldela först dina x och y med korrekt avrundning, sen sätter du moveTo/lineTo till x,y.
I forward() har getDirection() har ingen funktion, samma fel som w.getX() hade i getX().
Strecken ritas fortfarande inte trots att if-satserna är borta. Ligger felet i forward-metoden?
Du har ett fel som påpekades i den andra tråden, "if (isPenDown=true)" är en tilldelning och inte en jämförelse. Du ska använda "==" för jämförelse men eftersom variabeln redan är en boolean skriver du bättre endast "if (isPenDown)".
Om du efter det har problem, lägg in lite tillfälliga utskrifter av x, y, isPenDown så du ser vad som händer med dem. Skriv även ut om du gör lineTo eller moveTo.
Programmeraren skrev:Du har ett fel som påpekades i den andra tråden, "if (isPenDown=true)" är en tilldelning och inte en jämförelse. Du ska använda "==" för jämförelse men eftersom variabeln redan är en boolean skriver du bättre endast "if (isPenDown)".
Om du efter det har problem, lägg in lite tillfälliga utskrifter av x, y, isPenDown så du ser vad som händer med dem. Skriv även ut om du gör lineTo eller moveTo.
Jag förstår nu vad du menar, tack så mycket det var pedagogiskt beskrivet!
civilingengör skrev:Programmeraren skrev:Du har ett fel som påpekades i den andra tråden, "if (isPenDown=true)" är en tilldelning och inte en jämförelse. Du ska använda "==" för jämförelse men eftersom variabeln redan är en boolean skriver du bättre endast "if (isPenDown)".
Om du efter det har problem, lägg in lite tillfälliga utskrifter av x, y, isPenDown så du ser vad som händer med dem. Skriv även ut om du gör lineTo eller moveTo.
Jag förstår nu vad du menar och linjerna ritas nu upp, tack så mycket det var pedagogiskt beskrivet! Jag ska försöka själv med dina övriga tips igen. Jag återkommer om fler komplikationer uppstår.
Programmeraren skrev:Det ser inte ut som du har ordning på klassvariablerna x och y respektive x och y i SimpleWindow. Antingen jobbar du med egna variabler i klassen och har ett och endast ett ställe då du sätter motsvarigheten i SimpleWindow, eller så använder du alltid x och y i SimpleWindow (och skippar egna x och y).
Jag har tagit till mig dina tips och kommit en bit. Hade du kunnat specificera vad du menar med detta? Jag vet att det fortfarande finns brister i min forward-metod. I uppgiften står det att x och y (endast i forward-metoden) skall vara av typen double, men jag blir inte klok på hur detta skall implementeras. Cirkeln skall dessutom vara helt rund. Såhär ser min kod ut just nu.
SimpleWindow har x och y. Du har x och y. Det är inte fel i sig men det finns en risk att dina x och y divergerar från SimpleWindow:s x och y. Nu är koden mycket snyggare än tidigare. Nu räknar du med dina x och y och sätter SimpleWindows x och y när du räknat om (via moveTo/( och lineTo()).
Du har gjort en metod jumpTo(), aningen snyggare skulle vara att göra en metod lineTo() enligt samma mönster. Sen använder du båda dessa från forward(), då skulle du endast sätta dina x och y samt SimpleWindows x och y i dessa två metoder. Då vet du säkert att de inte kan råka få olika värden.
För att få till en cirkel skulle du kunna göra en metod arc() som tar cirkelbågens vinkellängd och radien. Tecknet på vinkeln ger vänster/höger. Sen loopar du med lagom små steg, sätter som vinkeln med left(), och gör forward().
Att x och y ska vara double låter bra, då får du inte upprepade avrundningsfel. I jumpTo() och nya metoden lineTo() kan du göra avrundningen när du ropar på motsvarande metoder i SimpleWindow.
Programmeraren skrev:SimpleWindow har x och y. Du har x och y. Det är inte fel i sig men det finns en risk att dina x och y divergerar från SimpleWindow:s x och y. Nu är koden mycket snyggare än tidigare. Nu räknar du med dina x och y och sätter SimpleWindows x och y när du räknat om (via moveTo/( och lineTo()).
Du har gjort en metod jumpTo(), aningen snyggare skulle vara att göra en metod lineTo() enligt samma mönster. Sen använder du båda dessa från forward(), då skulle du endast sätta dina x och y samt SimpleWindows x och y i dessa två metoder. Då vet du säkert att de inte kan råka få olika värden.
För att få till en cirkel skulle du kunna göra en metod arc() som tar cirkelbågens vinkellängd och radien. Tecknet på vinkeln ger vänster/höger. Sen loopar du med lagom små steg, sätter som vinkeln med left(), och gör forward().
Att x och y ska vara double låter bra, då får du inte upprepade avrundningsfel. I jumpTo() och nya metoden lineTo() kan du göra avrundningen när du ropar på motsvarande metoder i SimpleWindow.
Tack för ytterligare respons! Angående cirkel-problemet skall cirkeln korrekt ritas ut med en redan given kod:
Och eftersom den endast använder metoden forward och left så ligger felet i någon av de två nedanstående metoderna:
Menar du att det är bättre att basera forward-metoden på arcus-funktioner istället för cos och sin? Jag arbetar fortfarande med övriga tips du givit.
Aha, cirkelkoden fanns redan. Ser ut ungefär som det jag föreslog. Med arc() menade jag inte arcsin, jag menade "arc" som i "cirkelbåge".
Troligen beror felet på att du avrundar i varje steg eftersom x och y är int.
Deklarera x och y som double. Avrunda argumentet när du ropar på w.moveTo() och w.lineTo(), avrunda inte x och y.
Det jag menade i övrigt var att om du skapar en egen lineTo(double x, double y) enligt samma mönster som din jumpTo(double x, double y) (med double-argument) så kapslar du in de ställen där dina x och y och SimpleWindow:s x och y modifieras. Om all annan kod, t ex forward(), använder de metoderna så finns ingen risk att dina x,y och SimpleWindow:s x,y blir olika. forward() använder alltså inte w direkt utan ropar på metoder in din klass.
Detalj: du borde inte behöva moveTo() i början av forward eftersom alla ställen som sätter x och y sätter också SimpleWindow:s x och y. Men den gör ingen skada.
Programmeraren skrev:Aha, cirkelkoden fanns redan. Ser ut ungefär som det jag föreslog. Med arc() menade jag inte arcsin, jag menade "arc" som i "cirkelbåge".
Troligen beror felet på att du avrundar i varje steg eftersom x och y är int.
Deklarera x och y som double. Avrunda argumentet när du ropar på w.moveTo() och w.lineTo(), avrunda inte x och y.
Det jag menade i övrigt var att om du skapar en egen lineTo(double x, double y) enligt samma mönster som din jumpTo(double x, double y) (med double-argument) så kapslar du in de ställen där dina x och y och SimpleWindow:s x och y modifieras. Om all annan kod, t ex forward(), använder de metoderna så finns ingen risk att dina x,y och SimpleWindow:s x,y blir olika. forward() använder alltså inte w direkt utan ropar på metoder in din klass.
Detalj: du borde inte behöva moveTo() i början av forward eftersom alla ställen som sätter x och y sätter också SimpleWindow:s x och y. Men den gör ingen skada.
Okej tack så mycket, det blev mycket tydligare nu. Jag skall testa detta. Tack!
Tack så jättemycket för hjälpen! Det löste sig tillslut. Ha en fortsatt trevlig dag.