Permalänk

Programmering 2 loop hjälp

Hejsan. Jag är nästan klar med min uppgift, vi ska göra en dart-simulator.
Det jag sitter fast med är att jag vill att programmet slutar när någon uppnår en viss poäng eller över, i detta fall 301 eller mer.
Såhär ser min kod ut. (Jag skulle uppskatta tips på hur jag ska tänka)

namespace Dartspel { class Program { static void Main(string[] args) { Game mitt_spel = new Game(); mitt_spel.Run_Game(); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } class Game { private List<Player> player_list = new List<Player>(); public void AddPlayer(string name) { Player person = new Player(name); player_list.Add(person); } public void Run_Game() { int runda = 0; int antal_kast = 6; Random slumptal = new Random(); int pil1; int pil2; int pil3; //Här körs programmet Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Välkommen till dart-simulatorn"); Console.ResetColor(); { Console.Write("\nAnge hur många spelare: "); int playerAmount = Convert.ToInt32(Console.ReadLine()); for (int i = 0; i < playerAmount; i++) { Console.Write("Ange namn på spelaren: "); string playerName = Console.ReadLine(); AddPlayer(playerName); } Console.WriteLine("\nBörja kasta!"); foreach (Player name in player_list) do { runda++; foreach (var player in player_list) { pil1 = slumptal.Next(0, 20); pil2 = slumptal.Next(0, 20); pil3 = slumptal.Next(0, 20); player.Add_turn(pil1, pil2, pil3); } } while (runda <= antal_kast); foreach (var player in player_list) { player.Print_Score(); } } } class Player { private string name { get; set; } private List<Turns> turn_list = new List<Turns>(); public Player(string _name) { name = _name; } public override string ToString() { return name; } public void Add_turn(int tal1, int tal2, int tal3) { turn_list.Add(new Turns(tal1, tal2, tal3)); } public int Calculate_Total() { int total = 0; foreach (var Turns in turn_list) { total = total + Turns.Get_Score(); } return total; } public void Print_Score() { Console.WriteLine("\nStatistik av pilkastning för {0} : ", name); Console.WriteLine("................................................."); foreach (var Turns in turn_list) { Console.WriteLine(Turns); } Console.WriteLine("................................................."); Console.WriteLine("Total poängen för spelaren är {0} poäng", Calculate_Total()); } } class Turns { private int turnOne; private int turnTwo; private int turnThree; public Turns(int _turnOne, int _turnTwo, int _turnThree) { turnOne = _turnOne; turnTwo = _turnTwo; turnThree = _turnThree; } public int Get_Score() { int total; total = turnOne + turnTwo + turnThree; return total; } public override string ToString() { return string.Format("Pilkast ett : {0}, Pilkast två : {1}, Pilkast tre : {2}", turnOne, turnTwo, turnThree); } } } }

Permalänk
Medlem

Först använd [ code ][ / code ] (utan mellanslag) så kanske det g år att läsa det du har.

using System; class Program { static void Main(string[] args) { Console.WriteLine("Hello, world!"); } }

Permalänk
Medlem

I Print_Score-loopen i slutet av Run_Game kan du ju passa på att kolla om någon av poängen överskrider nån gräns. Isåfall kan du avsluta "runda-loopen" genom break;. Nåt i den stilen?

Permalänk

@Granskog: Så långt har mina tankar också gott men alla mina försök leder till olika sorters error, tänker du något i spår med switch och case sats?

Permalänk
Medlem

Skapa en variabel i programmet som innehåller heltal för vinnare, sätt denna till 0 så länge ingen vunnit än, sätt den till 1/2/3/4 osv om någon av spelarna uppnår poäng för automatisk vinst.

Sen gör du en kontroll i början av loopen som kollar om någon vunnit

do { //if (winner > 0) { // printa vinnare eller något här // break; //} runda++; foreach (var player in player_list) { pil1 = slumptal.Next(0, 20); pil2 = slumptal.Next(0, 20); pil3 = slumptal.Next(0, 20); player.Add_turn(pil1, pil2, pil3); } } while (runda <= antal_kast);

Här hade jag gjort en kontroll om någon spelare uppnått maxpoäng, och satt "winner" till spelaren som vunnit.

foreach (var player in player_list) { player.Print_Score(); // gör en poängkontroll här, och sätt "winner" till den spelare som vunnit }

Permalänk

@elBenko: Tack, ska genast undersöka detta!

gjorde en variabel vinst och satte ett värde på 301 sedan försökte jag med detta:

do { if (Calculated_Total >= vinst) { Console.WriteLine("En spelare har vunnit"); break; } runda++; foreach (var player in player_list) { pil1 = slumptal.Next(0, 20); pil2 = slumptal.Next(0, 20); pil3 = slumptal.Next(0, 20); player.Add_turn(pil1, pil2, pil3); } } while (runda <= antal_kast); foreach (var player in player_list) { player.Print_Score(); }

jag får som error att Calculated_Total inte existerar i current context, men jag har ju sådan i min class Player?

Permalänk
Medlem
Skrivet av Rosafaran:

@elBenko: Tack, ska genast undersöka detta!

gjorde en variabel vinst och satte ett värde på 301 sedan försökte jag med detta:

do { if (Calculated_Total >= vinst) { Console.WriteLine("En spelare har vunnit"); break; } runda++; foreach (var player in player_list) { pil1 = slumptal.Next(0, 20); pil2 = slumptal.Next(0, 20); pil3 = slumptal.Next(0, 20); player.Add_turn(pil1, pil2, pil3); } } while (runda <= antal_kast); foreach (var player in player_list) { player.Print_Score(); }

jag får som error att Calculated_Total inte existerar i current context, men jag har ju sådan i min class Player?

Du har en metod Calculate_Total() i Player men den måste anropas på en instans av Player, så som du gör med Add_turn().
Så som du har gjort ovan förväntas en variabel eller liknande med namnet Calculated_Total i klassen Game, men den finns ju inte och därav saknas den i current context.

Permalänk
99:e percentilen
Skrivet av gonace:

Först använd [ code ][ / code ] (utan mellanslag) så kanske det g år att läsa det du har.

Går att demonstrera BB-kod utan mellanslag eller dylikt tack vare [noparse]-taggen.

Skriv

[cmd][noparse]kod[/noparse][/cmd]

för att få

kod

även om den röda texten innehåller BB-kod. (Better SweClockers har särskilda knappar för all BB-kod jag använt i detta inlägg.)

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Medlem

i C# så skulle jag bara skriva något simpelt så som simplast att starta eller stoppa något i detta fall mellan 0-10 ändra bara 10 til 300 om du vill att de ska gå mellan 0 till 300 och värdet den är i är i så klart i värdet DoSomeThingWith

for (int i = 0; i < 10; i++) { if (i == 0) { break; } DoSomeThingWith(i); } for (int i = 0; i < 10; i++) { if(i == 0) { continue; } DoSomeThingWith(i); }

Permalänk

@chrhem: Så det skulle fungera så som jag skrev om jag bara lyckas anropa den till player?

Permalänk
Medlem

@Rosafaran: Ja, det hade det gjort (med lite fix av syntax, förstås). Du har ju tillgång till varje player-objekt i foreach:en där kasten sker så där kan du kolla om spelaren vann under den rundan.

foreach (var player in player_list) { pil1 = slumptal.Next(0, 20); pil2 = slumptal.Next(0, 20); pil3 = slumptal.Next(0, 20); player.Add_turn(pil1, pil2, pil3); // Kolla om spelaren vunnit här }

Permalänk

Hallå, jag håller på med samma uppgift och får inte till att när man anger ett tal som är större än 20 eller mindre än 0 så ska talet inte läggas till. Så anger man 25 t.ex ska programmet säga att det är för högt och man får skriva in ett nytt tal istället. Någon som kan se vad jag missat?

namespace Dart { class Program { static void Main(string[] args) { var MyGame = new Game(); MyGame.PlayGame(); Console.WriteLine("Press any key to continue"); Console.ReadKey(); } } class Game { private List<Player> nameList = new List<Player>(); public void AddPlayer(string name) { Player players = new Player(name); nameList.Add(players); } public void PlayGame() { int arrow1; int arrow2; int arrow3; int total = 0; int winner = 301; Random slumptal = new Random(); Console.WriteLine("Välkommen till dart 301"); Console.WriteLine("Ange hur många ni är som spelar:"); int numberPlayers = int.Parse(Console.ReadLine()); for (int i = 0; i < numberPlayers; i++) { Console.WriteLine("Ange namnen på spelarna"); string playerName = Console.ReadLine(); AddPlayer(playerName); } do { foreach (var player in nameList) { Console.WriteLine("Det är {0}'s tur. Skriv in tre kast mellan 1-20", player); arrow1 = int.Parse(Console.ReadLine()); if (arrow1 > 20 || arrow1 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow1; } arrow2 = int.Parse(Console.ReadLine()); if (arrow2 > 20 || arrow2 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow2; } arrow3 = int.Parse(Console.ReadLine()); if (arrow3 > 20 || arrow3 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow3; } player.AddThrows(arrow1, arrow2, arrow3); total = player.CalculatePoints(); } } while (total <= winner); if (total >= winner) { Console.WriteLine("\nVi har en vinanre!!\n"); } foreach (var player in nameList) { player.PrintTurns(); } } class Player { private string name { get; set; } private List<Turns> throwList = new List<Turns>(); public Player(string _name) { name = _name; } public void AddThrows(int kast1, int kast2, int kast3) { throwList.Add(new Turns(kast1, kast2, kast3)); } public int CalculatePoints() { int score = 0; foreach (var turns in throwList) { score = score + turns.GetScore(); } return score; } public void PrintTurns() { Console.WriteLine("Statistik för spelare {0}", name); Console.WriteLine("----------------------------------------------"); foreach (var turns in throwList) { Console.WriteLine(turns); } Console.WriteLine("----------------------------------------------"); Console.WriteLine("Totalpoängen för {1} {0}\n", CalculatePoints(), name); } public override string ToString() { return name; } } class Turns { private int throwOne; private int throwTwo; private int throwThree; public Turns(int throw1, int throw2, int throw3) { throwOne = throw1; throwTwo = throw2; throwThree = throw3; } public int GetScore() { int totalt = throwOne + throwTwo + throwThree; return totalt; } public override string ToString() { return string.Format("Kasst ett: {0}, Kasst två: {1}, Kasst tre {2} ", throwOne, throwTwo, throwThree); } } } }

Permalänk
Medlem

@chokladkunG:

do { foreach (var player in nameList) { Console.WriteLine("Det är {0}'s tur. Skriv in tre kast mellan 1-20", player); arrow1 = int.Parse(Console.ReadLine()); if (arrow1 > 20 || arrow1 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow1; } arrow2 = int.Parse(Console.ReadLine()); if (arrow2 > 20 || arrow2 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow2; } arrow3 = int.Parse(Console.ReadLine()); if (arrow3 > 20 || arrow3 < 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); --arrow3; } player.AddThrows(arrow1, arrow2, arrow3); total = player.CalculatePoints(); } } while (total <= winner);

Istället för att ta bort ett på talet så lär du vilja återgå till där spelaren får välja ett tal.

Scenariot just nu:

Knappar in 25
25 > 20 SANT
Skriver ut felmeddelandet
tar bort 1 från arrow1.

arrow1 är nu 24.

Knappar in 0
0 > 20 FALSKT || 0 < 0 FALSKT

arrow2 är nu 0.

Knappar in 25
25 > 20 SANT
Skriver ut felmeddelandet
tar bort 1 från arrow3.

arrow3 är nu 24.

Sen lägger du till allt med:

player.AddThrows(arrow1, arrow2, arrow3);
Alltså: 24, 0, 24.

Det du istället vill göra är att låta användaren skriva om sitt tal om det är felaktigt, detta redan vid arrow1.
Alltså, om talet för arrow1 redan är felaktigt så bör inte programmet fortsätta till nästa kast. Spelaren ska helt enkelt inte få gå vidare förrän kraven är uppfyllda.

Logiken för detta kan du lyfta ut till en egen metod, som du ser i din kod så repeterar du dig själv på tre ställen nu (if-satserna och felmeddelandet är identiska).
Vilket innebär att om du behöver ändra spelregler, t.ex. nu ska du kunna välja 1-25, så kommer du att behöva ändra på 6 ställen totalt i koden.
Detta är ett vanligt sätt som kan skapa buggar, du kommer ihåg att ändra på fem ställen i koden men missar på ett, helt plötsligt har du en bugg som bara uppstår ibland och som kan vara svår att felsöka.

En sådan metod skulle t.ex. kunna se ut såhär:

public int GetPlayerNumber() { int result; do { if (int.TryParse(Console.ReadLine(), out result)) { if (result > 20 || result <= 0) { Console.WriteLine("Ange endast ett tal mellan 1-20!"); result = 0; } else break; } else Console.WriteLine("Det är inte ett giltigt tal."); } while(result == 0); return result; }

Notera hur du nu har flyttat logiken för inmatningen och gjort den inkapslad i en egen metod, som du kan anropa om och om igen då du behöver det. Och behöver du ändra någon logik gällande reglerna så behöver du endast göra det på detta ställe, utan att det påverkar ditt spel i övrigt.

Vilket innebär att du i din nuvarande kod kan ändra det till detta:

do { foreach (var player in nameList) { Console.WriteLine("Det är {0}'s tur. Skriv in tre kast mellan 1-20", player); arrow1 = GetPlayerNumber(); arrow2 = GetPlayerNumber(); arrow3 = GetPlayerNumber(); player.AddThrows(arrow1, arrow2, arrow3); total = player.CalculatePoints(); } } while (total <= winner); // Eller förkorta det ännu mer: do { foreach (var player in nameList) { Console.WriteLine("Det är {0}'s tur. Skriv in tre kast mellan 1-20", player); player.AddThrows(GetPlayerNumber(), GetPlayerNumber(), GetPlayerNumber()); total = player.CalculatePoints(); } } while (total <= winner);

Permalänk
Medlem

Väldigt många gånger när jag själv försökt koda något slags simpelt spel så har jag insett att jag använder för många klasser. Det svåraste med objektorienterad programmering är att veta när man ska skapa en klass. Jag brukar låta min logik ligga i spel-loopen och mina klasser vara lite av det dummare laget. Här är ett exempel:

using System; using System.Linq; using System.Collections.Generic; class MainClass { public static void Main (string[] args) { Game game = new Game(); game.run(); } } class Game { Random rn = new Random(); List<Player> players = new List<Player>(){ new Player("Mike"), new Player("Bran") }; int turn = 0; int maxTurns = 6; int dartsPerTurn = 3; public Player winning() { return players.Aggregate((acc, curr) => { if (acc.score < curr.score) { return curr; } return acc; }); } public string ss(int num) { return num != 1 ? "s" : ""; } public void run() { Console.WriteLine("== Dart simulator =="); do { Console.WriteLine($"= Turn: {turn+1} ="); foreach (Player player in players) { for (int i = 0; i < dartsPerTurn; i++) { Dart dart = new Dart(); player.score += dart.hit; Console.Write($"{player.name} throws "); if (dart.hit == 0) { Console.WriteLine("but missed!"); } else { Console.WriteLine($"and got {dart.hit} point{ss(dart.hit)}"); } } } Player leading = winning(); Console.WriteLine($"{leading.name} is in the lead with {leading.score} point{ss(leading.score)}!"); turn++; } while (turn < maxTurns); Console.WriteLine("== The game is over! =="); Player winner = winning(); foreach (Player player in players) { Console.WriteLine($"{player.name} final score: {player.score}"); } Console.WriteLine($"The winner is {winner.name}!"); } } class Player { public int score = 0; public string name; public Player(string name) { this.name = name; } } class Dart { Random rn = new Random(); public int hit; public Dart() { this.hit = rn.Next(0, 20); } }

Går att köra här: https://repl.it/@johanbx/sweclockers-dart-simulator
Observera att jag skippat att använda user input för att kunna iterera snabbare. Men det är enkelt att lägga till i efterhand.

Förslag utan Turns klassen

Edit: Till din fråga om att stanna vid 301 poäng. Om det är 5 rundor och du kan få maximalt 60 poäng per runda, blir inte det 300 poäng maximalt? Borde du inte använda slumptal.Next(0, 60) ? Eller jag kanske inte riktigt har förstått uppgiften.

Permalänk

@zaibuf: super tack verkligen! Har ändrat lite så nu fungerar det som jag vill.

Permalänk

@wirlez: Det var enligt uppgiften som klasserna skulle innehålla dom där metoderna. Och om jag förstår det rätt ska programmet köras endast till någon får poängen 301. Men tror nog jag föredrar ditt sätt jämfört med det här...