Permalänk
Medlem

Fråga om Enum

Jag har följande metod. Dit skickar jag kommandon för att styra en fiktiv bil.

Moving(Char.ToUpper(c2), truck, turn);

Det viktiga här är den Char jag skickar som en bokstav. F = forward, B = back, L=left och R = right

Plockar dessa ur en sträng t.ex. LFFBFFL

Detta fungerar bra men funderar på om jag borde använd Enum och i så fall hur.

Som denna:

public enum Turn { Forward = 'F', Back = 'B', Left = 'L', Right = 'R' }

Visa signatur

Chassi: Fractal Design Define C || Processor: Intel i7-8700K || Grafikkort: ASUS GeForce GTX 1080Ti ROG Strix Gaming || Moderkort: Gigabyte Z370 AORUS ULTRA WIFI || Minne: Corsair Vengeance LPX DDR4 3000MHz 32 Gb || Lagring: Samsung 860 EVO 1TB SSD || PSU: Seasonic Focus+ 850W 85+ GOLD PSU || Skärm:Samsung Odyssey G9 || Windows 10

Permalänk
Hedersmedlem

Vad är det för programmeringsspråk?

Svårt att säga om du "bör" använda en enum eller inte utan att se resten av koden. Men spontant undrar jag:

- Varför inte istället använda en funktion per riktning?
- Varför inte istället använda parametrar för fram/bak (negativ för bak, noll för stopp, positiv för fram) etc, och motsvarande för vänster/höger?

Permalänk
Medlem
Skrivet av pv2b:

Vad är det för programmeringsspråk?

Svårt att säga om du "bör" använda en enum eller inte utan att se resten av koden. Men spontant undrar jag:

- Varför inte istället använda en funktion per riktning?
- Varför inte istället använda parametrar för fram/bak (negativ för bak, noll för stopp, positiv för fram) etc, och motsvarande för vänster/höger?

Det är C#.

Det är klart att använda en funktion per riktning är ett sätt.

Min metod ser ut så här nu.

static void Moving(char input4, RadioControlled truck, bool turn) { switch (input4) { case 'F': { if(truck.direction == 'E') truck.startX++; if (truck.direction == 'W') truck.startX--; if (truck.direction == 'N') truck.startY++; if (truck.direction == 'S') truck.startY--; break; } case 'B': { if (truck.direction == 'E') truck.startX--; if (truck.direction == 'W') truck.startX++; if (truck.direction == 'N') truck.startY--; if (truck.direction == 'S') truck.startY++; break; } case 'L': { if (truck.direction == 'W' && turn == false) { truck.direction = 'S'; turn = true; } if (truck.direction == 'E' && turn == false) { truck.direction = 'N'; turn = true; } if (truck.direction == 'N' && turn == false) { truck.direction = 'W'; turn = true; } if (truck.direction == 'S' && turn == false) { truck.direction = 'E'; turn = true; } break; } case 'R': { if (truck.direction == 'W' && turn == false) { truck.direction = 'N'; turn = true; } if (truck.direction == 'E' && turn == false) { truck.direction = 'S'; turn = true; } if (truck.direction == 'N' && turn == false) { truck.direction = 'E'; turn = true; } if (truck.direction == 'S' && turn == false) { truck.direction = 'W'; turn = true; } break; } } }

Visa signatur

Chassi: Fractal Design Define C || Processor: Intel i7-8700K || Grafikkort: ASUS GeForce GTX 1080Ti ROG Strix Gaming || Moderkort: Gigabyte Z370 AORUS ULTRA WIFI || Minne: Corsair Vengeance LPX DDR4 3000MHz 32 Gb || Lagring: Samsung 860 EVO 1TB SSD || PSU: Seasonic Focus+ 850W 85+ GOLD PSU || Skärm:Samsung Odyssey G9 || Windows 10

Permalänk
Hedersmedlem

Hjälp vad komplext du gjort det hela. Nej, du ska inte ha en Enum, här ska du ha lite enkel trigonometri istället.

Jag hade här börjat med att ändra truck.direction från att vara en char (eller en enum) till att stället vara ett vinkelmått, för att få en riktning i grader. Ett exempel är att definiera 0° som norr, och sedan definiera positiv riktning som medsols (d.v.s. 90° blir öster, 180° söder, 270° väster, etc.)

Detta kan du representera som ett flyttal om du vill för att kunna ha vilken riktning som helst. Men om du alltid vet att du kommer att röra dig exakt norr, söder, väster eller öster så kan du representera det som ett heltal, där 0 är norr, 1 är öster, 2 är söder, och 3 är väster. Men jag kommer använda flyttal i mitt exempel för att jag känner att det blir enklare (du kommer se sen!)

När du väl representerar riktningen som en vinkel, så är det mycket enklare att implementera sväng vänster (ta bort 90 grader), sväng höger (lägg till 90 grader). För att implementera "framåt" och "bakåt" kan du antingen ha en funktion som lägger på 180 grader på vinkeln för att vända dig om, eller så kan du ha ett till tal som representerar bilens hastighet. För att backa sätter du då en negativ hastighet. Varje gång du uppdaterar vinkeln ska du bara se till att du lägger på modulo 360, så att vinkeln hamnar i spannet 0-360 grader.

Om du gör något i den stilen så lovar jag att du kommer få kod som är mycket mer flexibel och kortare, och du kan göra massa roliga saker.

Ska se om jag kan slänga ihop lite pseudokod så får du se hur jag menar.

Permalänk
Medlem
Skrivet av pv2b:

Hjälp vad komplext du gjort det hela. Nej, du ska inte ha en Enum, här ska du ha lite enkel trigonometri istället.

Jag hade här börjat med att ändra truck.direction från att vara en char (eller en enum) till att stället vara ett vinkelmått, för att få en riktning i grader. Ett exempel är att definiera 0° som norr, och sedan definiera positiv riktning som medsols (d.v.s. 90° blir öster, 180° söder, 270° väster, etc.)

Detta kan du representera som ett flyttal om du vill för att kunna ha vilken riktning som helst. Men om du alltid vet att du kommer att röra dig exakt norr, söder, väster eller öster så kan du representera det som ett heltal, där 0 är norr, 1 är öster, 2 är söder, och 3 är väster. Men jag kommer använda flyttal i mitt exempel för att jag känner att det blir enklare (du kommer se sen!)

När du väl representerar riktningen som en vinkel, så är det mycket enklare att implementera sväng vänster (ta bort 90 grader), sväng höger (lägg till 90 grader). För att implementera "framåt" och "bakåt" kan du antingen ha en funktion som lägger på 180 grader på vinkeln för att vända dig om, eller så kan du ha ett till tal som representerar bilens hastighet. För att backa sätter du då en negativ hastighet. Varje gång du uppdaterar vinkeln ska du bara se till att du lägger på modulo 360, så att vinkeln hamnar i spannet 0-360 grader.

Om du gör något i den stilen så lovar jag att du kommer få kod som är mycket mer flexibel och kortare, och du kan göra massa roliga saker.

Ska se om jag kan slänga ihop lite pseudokod så får du se hur jag menar.

Gör en uppgift med speciella krav men det är möjligt att jag gör det för komplicerat.

Du får gärna visa vad du menar.

Skickades från m.sweclockers.com

Visa signatur

Chassi: Fractal Design Define C || Processor: Intel i7-8700K || Grafikkort: ASUS GeForce GTX 1080Ti ROG Strix Gaming || Moderkort: Gigabyte Z370 AORUS ULTRA WIFI || Minne: Corsair Vengeance LPX DDR4 3000MHz 32 Gb || Lagring: Samsung 860 EVO 1TB SSD || PSU: Seasonic Focus+ 850W 85+ GOLD PSU || Skärm:Samsung Odyssey G9 || Windows 10

Permalänk
Hedersmedlem

Här är ett litet "leksaksbilexempel" som använder riktningar på det sättet som jag föreslog.

using System; public class Car { // jag låter alla dessa vara public, det förenklar för illustration och labb :-) public double positionN; // antal längdenheter bilen färdats norr från sin ursprungspunkt public double positionE; // antal längdenheter bilen färdats öster från sin ursprungspunkt public double speed; // bilens hastighet, i längdenheter per tick public double heading; // bilens riktning, i radianer, där 0 radianer är norr, och pi/2 radianer är öster etc // Varje gång den här metoden körs så uppdateras bilens position // baserat på dess riktning (heading) och hastighet (speed) public void tick() { positionN += speed * Math.Cos(heading); positionE += speed * Math.Sin(heading); } // skriver ut vad bilen gör just nu! public void report(string meddelande) { Console.WriteLine(meddelande); Console.WriteLine("Bilen befinner sig vid:"); Console.WriteLine(positionN + " N"); Console.WriteLine(positionE + " Ö"); Console.WriteLine("Hastighet: " + speed); Console.WriteLine("Riktning: " + heading * 180.0 / Math.PI); // konverterar till grader! Console.WriteLine(); } // Svänger bilen turnAngle radianer. Positivt värde avser högersväng, negativt blir vänstersväng. public void turn(double turnAngle) { heading += turnAngle; // uppdatera bilens riktning heading %= 2 * Math.PI; // se till att bilens riktning är >= 0 och < 2*pi } // Svänger bilen, men i grader istället. Enklare för människor! public void turnDegrees(double turnAngle) { turn(turnAngle / 180.0 * Math.PI); } // vänstersväng, förenklar lite för den som anropar funktionen public void turnLeft() { turnDegrees(-90); } // högersväng, förenklar lite för den som anropar funktionen public void turnRight() { turnDegrees(90); } // U-sväng, förenklar lite för den som anropar funktionen public void uTurn() { turnDegrees(180); } // ökar bilens hastighet med speedDelta public void accelerate(double speedDelta) { speed += speedDelta; } // retarderar bilens hastighet med speedDelta. obs, om vi retarderar för mycket så går vi baklänges! public void decelerate(double speedDelta) { accelerate(-speedDelta); } // vänder bilen så att den kör baklänges med samma hastighet public void reverse() { speed = -speed; } // stannar bilen public void stop() { speed = 0; } } public class Program { public static void Main() { Car c = new Car(); c.report("Kolla in min nya bil!!!"); c.accelerate(1); c.report("Gasen i botten."); c.tick(); c.report("Tick säger klockan."); c.turnRight(); c.tick(); c.report("Svänger höger, sedan tick!"); c.turnDegrees(-45); c.tick(); c.report("Svänger vänster 45 grader, sedan tick!"); c.reverse(); c.tick(); c.report("Backar, sedan tick!"); c.turnDegrees(-45); c.tick(); c.report("Svänger vänster 45 grader, sedan tick! Kolla! Jag backar norrut så jag kommer söderut!"); } }

Eller lek med koden själv på DotNetFiddle: https://dotnetfiddle.net/y589sX

Som du ser, koden jag precis skrev var förvisso lite längre än ditt exempel, men den gör också sjukt mer. Motsvarigheten till din funktion som du skrev ovan är det som finns i rutinen tick().

Om du inte vill använda trigonometri med sinus och kosinus, och du bara behöver 4 olika riktningar så kan du istället representera hastigheten som en vektor, i hastighet norrut och hastighet österut. Men det blir lite klurigare tycker jag själv, det här var enklare och flexiblare.

Permalänk
Medlem
Skrivet av pv2b:

Här är ett litet "leksaksbilexempel" som använder riktningar på det sättet som jag föreslog.

using System; public class Car { // jag låter alla dessa vara public, det förenklar för illustration och labb :-) public double positionN; // antal längdenheter bilen färdats norr från sin ursprungspunkt public double positionE; // antal längdenheter bilen färdats öster från sin ursprungspunkt public double speed; // bilens hastighet, i längdenheter per tick public double heading; // bilens riktning, i radianer, där 0 radianer är norr, och pi/2 radianer är öster etc // Varje gång den här metoden körs så uppdateras bilens position // baserat på dess riktning (heading) och hastighet (speed) public void tick() { positionN += speed * Math.Cos(heading); positionE += speed * Math.Sin(heading); } // skriver ut vad bilen gör just nu! public void report(string meddelande) { Console.WriteLine(meddelande); Console.WriteLine("Bilen befinner sig vid:"); Console.WriteLine(positionN + " N"); Console.WriteLine(positionE + " Ö"); Console.WriteLine("Hastighet: " + speed); Console.WriteLine("Riktning: " + heading * 180.0 / Math.PI); // konverterar till grader! Console.WriteLine(); } // Svänger bilen turnAngle radianer. Positivt värde avser högersväng, negativt blir vänstersväng. public void turn(double turnAngle) { heading += turnAngle; // uppdatera bilens riktning heading %= 2 * Math.PI; // se till att bilens riktning är >= 0 och < 2*pi } // Svänger bilen, men i grader istället. Enklare för människor! public void turnDegrees(double turnAngle) { turn(turnAngle / 180.0 * Math.PI); } // vänstersväng, förenklar lite för den som anropar funktionen public void turnLeft() { turnDegrees(-90); } // högersväng, förenklar lite för den som anropar funktionen public void turnRight() { turnDegrees(90); } // U-sväng, förenklar lite för den som anropar funktionen public void uTurn() { turnDegrees(180); } // ökar bilens hastighet med speedDelta public void accelerate(double speedDelta) { speed += speedDelta; } // retarderar bilens hastighet med speedDelta. obs, om vi retarderar för mycket så går vi baklänges! public void decelerate(double speedDelta) { accelerate(-speedDelta); } // vänder bilen så att den kör baklänges med samma hastighet public void reverse() { speed = -speed; } // stannar bilen public void stop() { speed = 0; } } public class Program { public static void Main() { Car c = new Car(); c.report("Kolla in min nya bil!!!"); c.accelerate(1); c.report("Gasen i botten."); c.tick(); c.report("Tick säger klockan."); c.turnRight(); c.tick(); c.report("Svänger höger, sedan tick!"); c.turnDegrees(-45); c.tick(); c.report("Svänger vänster 45 grader, sedan tick!"); c.reverse(); c.tick(); c.report("Backar, sedan tick!"); c.turnDegrees(-45); c.tick(); c.report("Svänger vänster 45 grader, sedan tick! Kolla! Jag backar norrut så jag kommer söderut!"); } }

Eller lek med koden själv på DotNetFiddle: https://dotnetfiddle.net/y589sX

Som du ser, koden jag precis skrev var förvisso lite längre än ditt exempel, men den gör också sjukt mer. Motsvarigheten till din funktion som du skrev ovan är det som finns i rutinen tick().

Om du inte vill använda trigonometri med sinus och kosinus, och du bara behöver 4 olika riktningar så kan du istället representera hastigheten som en vektor, i hastighet norrut och hastighet österut. Men det blir lite klurigare tycker jag själv, det här var enklare och flexiblare.

Ok, ska kolla på det, tack 😀

Skickades från m.sweclockers.com

Visa signatur

Chassi: Fractal Design Define C || Processor: Intel i7-8700K || Grafikkort: ASUS GeForce GTX 1080Ti ROG Strix Gaming || Moderkort: Gigabyte Z370 AORUS ULTRA WIFI || Minne: Corsair Vengeance LPX DDR4 3000MHz 32 Gb || Lagring: Samsung 860 EVO 1TB SSD || PSU: Seasonic Focus+ 850W 85+ GOLD PSU || Skärm:Samsung Odyssey G9 || Windows 10

Permalänk
Medlem

pv2b exempel är lite bättre även om jag skulle skippa radianer när man bara pratar kvarts rotationer och köra på grader istället direkt modulo 360.
Du kan även använda tilldelning för exempel höger/vänster samt skicka in grader direkt så slipper du tre funktioner för något som kräver en m.m

Visa signatur

"One is always considered mad, when one discovers something that others cannot grasp."
- Ed Wood

Permalänk
Hedersmedlem
Skrivet av Ferrat:

pv2b exempel är lite bättre även om jag skulle skippa radianer när man bara pratar kvarts rotationer och köra på grader istället direkt modulo 360.
Du kan även använda enum för exempel höger/vänster samt skicka in grader direkt så slipper du tre funktioner för något som kräver en m.m

Jodå, det är lite av en smaksak, om man gillar radianer eller grader bättre. Jag gjorde på det här sättet för att minimera antalet gånger konvertering behöver ske mellan grader och radianer.

Ska man bara hantera kvarts rotationer kanske den bästa enheten är ett heltal, där 1 enhet motsvarar 90 grader. Men jag tyckte att det bara skulle bli mer kod för mindre flexibilitet att göra så, så jag gjorde inte det.

Permalänk
Medlem

@pv2b: Jo rättade mig själv, menade att man sätter höger = 90 , vänster = -90 sedan tar bort de specifika funktionerna så kan du använda bara turnDegree, byter det till turn så kan du direkt passa genom turn(höger) eller turn(vänster) och vill du sedan specificera så tar den även antalet grader.

Hur menar du minimera antalet konverteringar? Blir bara en per uppdatering eller missar jag något? Samt att du slipper göra om det när du skriver ut.

Visa signatur

"One is always considered mad, when one discovers something that others cannot grasp."
- Ed Wood

Permalänk
Hedersmedlem
Skrivet av Ferrat:

@pv2b: Jo rättade mig själv, menade att man sätter höger = 90 , vänster = -90 sedan tar bort de specifika funktionerna så kan du använda bara turnDegree, byter det till turn så kan du direkt passa genom turn(höger) eller turn(vänster) och vill du sedan specificera så tar den även antalet grader.

Hur menar du minimera antalet konverteringar? Blir bara en per uppdatering eller missar jag något? Samt att du slipper göra om det när du skriver ut.

Absolut, du kan ta bort turnLeft och turnRight, syftet var bara att visa att man *kan* lägga till såna bekvämlighetsfunktioner om man vill.

Som jag tänker mig så är det metoden tick() som kommer vara den som anropas oftast. Att ändra bilens riktning eller hastighet är relativt sällsynt. Att inte behöva konvertera varje tick kändes bara... som att det var mindre. Det handlar inte om CPU-tid eller något, utan bara mest att man vill göra så få onödiga operationer på flyttal som möjligt för att bibehålla så mycket precision som möjligt. (Med det sagt så är det förmodligen bättre att lagra det i antal grader om man prompt ska lagra det i en double, eftersom så små heltal kan representeras exakt i en double, till skillnad från pi...)