Permalänk
Skrivet av lydell:

I if (lottoBoll[i] < 1 && lottoBoll[i] > 25) verkar du har blandat ihop && (and) och || (or). Ett tal kan inte vara både mindre än 1 och större än 25 på samma gång

Haha tror jag hade behövt en paus där innan jag kommenterade..

Permalänk
Medlem
Skrivet av KodarPolle:

Har försökt lägga en if-sats, men det händer liksom ingenting... tänkte även lägga en else sats som läste in lottoBollar[i] = användarensSvar; men det gick inte.. Vad gör jag för fel.. ?

Du har lagt din if-sats utanför for-loopen nu, så den kommer bara köras efter att användaren redan matat in alla tal. Du skriver även över alla inmatningar med användarensSvar som alltid är 0. Som du själv skrev tidigare så är användarensSvar-variabeln helt onödig och krånglar bara till det, så ta bort den variabeln.

Permalänk

Jag skulle rekommendera att du använder int.TryParse istället för att använda int.Parse då det medför att du måste hantera eventuella fel med try catch. Exceptions ska inte användas som ett normalt programflöde, utan när oväntade fel uppstår, t.ex. om man plötsligt tappar nätverksanslutning.

Det verkar som om du faktiskt vill lära dig, inte bara kopiera en färdig lösning, så här kommer en lösning du kanske vill kika på

static void Main(string[] args) { var lottoBoll = new int[10]; int användarensSvar; Console.WriteLine($"Hej och välkommen till Lotto, låt oss spela!\nVälj {lottoBoll.Length}st nummer mellan 1-25\n"); for (int i = 0; i < lottoBoll.Length; i++) { Console.Write($"Spela på nummer {i + 1}: "); int.TryParse(Console.ReadLine(), out användarensSvar); if (användarensSvar < 1 || användarensSvar > 25) { Console.WriteLine("Vänligen ange ett heltal mellan 1 och 25"); i--; } else { lottoBoll[i] = användarensSvar; } } int slumptal = new Random().Next(1, 26); bool spelarenVann = false; for (int i = 0; i < lottoBoll.Length; i++) { if (lottoBoll[i] == slumptal) { spelarenVann = true; break; } } if (spelarenVann) { Console.WriteLine($"\nBINGO! Det rätta talet var {slumptal}"); } else { Console.WriteLine($"\nIngen bingo denna gång, det slumpade talet var {slumptal}!"); } Console.WriteLine("\nSpelet är slut, välkommen åter!"); Console.ReadKey(); }

Här använder jag int.TryParse för att få tag på värdet användaren skriver in och break för att sluta leta efter träffar om man gissat rätt siffra. Det är kanske inte exakt så här jag skulle löst det själv, men jag försökte hålla mig så nära din kod som möjligt, samma variabelnamn och struktur.

Permalänk
Skrivet av perost:

Du har lagt din if-sats utanför for-loopen nu, så den kommer bara köras efter att användaren redan matat in alla tal. Du skriver även över alla inmatningar med användarensSvar som alltid är 0. Som du själv skrev tidigare så är användarensSvar-variabeln helt onödig och krånglar bara till det, så ta bort den variabeln.

Nu fattar jag! Den måste självklart vara inne i for loopen! TACK!

for (int i = 0; i < lottoBoll.Length; i++) { int nummer = i + 1; Console.Write("Spela på nummer " + nummer + ": "); try { lottoBoll[i] = int.Parse(Console.ReadLine()); // Matar in värdet och konverterar från string till heltal. } catch { Console.WriteLine("Vänligen ange ett heltal"); i--; } if (lottoBoll[i] < 1 || lottoBoll[i] > 25) { Console.WriteLine("Vänligen ange ett tal mellan 1-25"); i--; } }

Förstod dock inte vart jag ska ha continue; för om jag har det istället för i--; så hamnar jag på indexen efter och får inte skriva om på samma index. Förstår du hur jag menar?

Det verkar som att det fungerar bra med det jag gjorde ovan. Vad kan gå fel alltså? Har försökt testa runt lite med både för höga tal och siffror, det verkar funka som det ska.

Permalänk
Medlem
Skrivet av KodarPolle:

Förstod dock inte vart jag ska ha continue; för om jag har det istället för i--; så hamnar jag på indexen efter och får inte skriva om på samma index. Förstår du hur jag menar?

Det verkar som att det fungerar bra med det jag gjorde ovan. Vad kan gå fel alltså? Har försökt testa runt lite med både för höga tal och siffror, det verkar funka som det ska.

Om spelaren matar in något som inte är ett tal på första platsen så kommer du köra i--, vilket innebär att i = 0 - 1 = -1. Så när if-satsen körs så kommer du hämta värdet på lottoBoll[-1], vilket borde kasta en exception tror jag (har inte riktigt koll på hur det fungerar i C#).

Grejen med continue är att om ett fel inträffar, t.ex. att användaren matar in något som inte är ett tal, så vill du ju inte köra resten av koden i loopen utan hantera felet och hoppa vidare till nästa iteration så att användaren får mata in ett nytt tal. continue ersätter alltså inte i--, utan de används tillsammans för att "köra om" en iteration av loopen.

Permalänk
Skrivet av SanguinSE:

Jag skulle rekommendera att du använder int.TryParse istället för att använda int.Parse då det medför att du måste hantera eventuella fel med try catch. Exceptions ska inte användas som ett normalt programflöde, utan när oväntade fel uppstår, t.ex. om man plötsligt tappar nätverksanslutning.

Det verkar som om du faktiskt vill lära dig, inte bara kopiera en färdig lösning, så här kommer en lösning du kanske vill kika på

static void Main(string[] args) { var lottoBoll = new int[10]; int användarensSvar; Console.WriteLine($"Hej och välkommen till Lotto, låt oss spela!\nVälj {lottoBoll.Length}st nummer mellan 1-25\n"); for (int i = 0; i < lottoBoll.Length; i++) { Console.Write($"Spela på nummer {i + 1}: "); int.TryParse(Console.ReadLine(), out användarensSvar); if (användarensSvar < 1 || användarensSvar > 25) { Console.WriteLine("Vänligen ange ett heltal mellan 1 och 25"); i--; } else { lottoBoll[i] = användarensSvar; } } int slumptal = new Random().Next(1, 26); bool spelarenVann = false; for (int i = 0; i < lottoBoll.Length; i++) { if (lottoBoll[i] == slumptal) { spelarenVann = true; break; } } if (spelarenVann) { Console.WriteLine($"\nBINGO! Det rätta talet var {slumptal}"); } else { Console.WriteLine($"\nIngen bingo denna gång, det slumpade talet var {slumptal}!"); } Console.WriteLine("\nSpelet är slut, välkommen åter!"); Console.ReadKey(); }

Här använder jag int.TryParse för att få tag på värdet användaren skriver in och break för att sluta leta efter träffar om man gissat rätt siffra. Det är kanske inte exakt så här jag skulle löst det själv, men jag försökte hålla mig så nära din kod som möjligt, samma variabelnamn och struktur.

Om jag ska använda mig av int.TryParse så måste jag alltså deklarera en variabel? Tex int användarensSvar; ? Eller kan jag lösa det utan att deklarera en variabel? ..

Testade din kod nyss. Alltså säger den ifrån allt som skrivs så länge det inte är mellan tal 1-25. På så sätt slipper man ha en try-catch för både "vänligen ange heltal" och "För högt/lågt tal" eller hur?

Så jag bör använda mig av tryParse om det handlar om sådana här saker istället?

Permalänk
Skrivet av perost:

Om spelaren matar in något som inte är ett tal på första platsen så kommer du köra i--, vilket innebär att i = 0 - 1 = -1. Så när if-satsen körs så kommer du hämta värdet på lottoBoll[-1], vilket borde kasta en exception tror jag (har inte riktigt koll på hur det fungerar i C#).

Grejen med continue är att om ett fel inträffar, t.ex. att användaren matar in något som inte är ett tal, så vill du ju inte köra resten av koden i loopen utan hantera felet och hoppa vidare till nästa iteration så att användaren får mata in ett nytt tal. continue ersätter alltså inte i--, utan de används tillsammans för att "köra om" en iteration av loopen.

Jaha, jag fattar! Stämmer bra, det gick inte att skriva fel på första talet som du sa.
Tack! Den ska alltså ligga här? :

for (int i = 0; i < lottoBoll.Length; i++) { int nummer = i + 1; Console.Write("Spela på nummer " + nummer + ": "); try { lottoBoll[i] = int.Parse(Console.ReadLine()); // Matar in värdet och konverterar från string till heltal. } catch { Console.WriteLine("Vänligen ange ett heltal"); i--; continue; } if (lottoBoll[i] < 1 || lottoBoll[i] > 25) { Console.WriteLine("Vänligen ange ett tal mellan 1-25"); i--; } }

Anser du också att jag bör använda mig att tryParse istället för try catch ?

Permalänk
Medlem
Skrivet av KodarPolle:

Jaha, jag fattar! Stämmer bra, det gick inte att skriva fel på första talet som du sa.
Tack! Den ska alltså ligga här? :

Precis

Skrivet av KodarPolle:

Anser du också att jag bör använda mig att tryParse istället för try catch ?

Säger uppgiften något om det? Annars är väl tryParse aningen enklare att använda i det här fallet.

Permalänk
Skrivet av perost:

Precis
Säger uppgiften något om det? Annars är väl tryParse aningen enklare att använda i det här fallet.

"Ni ska nu kontrollera så att användaren bara skriver in ett tal mellan 1 och 25.
Detta lösas enklast genom att man styr inmatning till respektive position i vektorn med en for-loop. I
for-loopen finns en variabel (förändring, exempelvis i) som kontrollerar vilken position man för
närvarande ”pekar på” i vektorn.
Om talet som användaren skriver in är under 1 eller över 25 kan man minska värdet i variabeln (i) som
styr positionen med ett (1) enligt figuren nedan. Då ”backar” vi ett steg i vektorn.
Alltså – för varje varv som for-loopen itererar så kommer värdet på variabeln som styr förändring att
öka med ett (1). Men om vi skriver in ett ”olämpligt” värde så kommer värdet att minska med ett (1) i
koden inuti loopen.
Alternativet är att ni sparar det inmatade talet i en temporär variabel och lagrar det i vektorn om det
uppnår kraven (det vill säga är mellan ett och tjugofem)."

Så den säger väl inget om tryParse eller try-catch egentligen. Så om jag ska köra tryParse istället, måste jag då deklarera en variabel? tex användarensSvar? Eller kan man göra det utan att behöva deklarera ny variabel? Försökte utan men gick inge vidare ..

Permalänk
Medlem
Skrivet av KodarPolle:

Så den säger väl inget om tryParse eller try-catch egentligen. Så om jag ska köra tryParse istället, måste jag då deklarera en variabel? tex användarensSvar? Eller kan man göra det utan att behöva deklarera ny variabel? Försökte utan men gick inge vidare ..

Jag antar att out kräver att namnet som används är en variabel, och t.ex. lottoBoll[i] är inte en variabel utan ett uttryck. Så troligtvis behöver du en variabel för att lagra inmatningen innan du lägger in den i arrayen. Jag kan egentligen inte C#, så något får gärna rätta mig om jag har fel.

Men om du väljer den vägen så kan du även försöka implementera alternativet som den sista meningen i uppgiften nämner. D.v.s. istället för att alltid köra i++ i for-satsen och behöva köra i-- när något går fel så kan du välja att köra i++ endast när du lagt in ett giltigt värde i arrayen (om du inte redan har koll på det så är delarna i for-satsen valfria, for(;;) är t.ex. en giltig for-loop). Koden blir lite mer robust om man gör så, eftersom du då kan lägga till mer felhantering senare utan att behöva kopiera i---raden överallt.

Permalänk
Skrivet av KodarPolle:

Om jag ska använda mig av int.TryParse så måste jag alltså deklarera en variabel? Tex int användarensSvar; ? Eller kan jag lösa det utan att deklarera en variabel? ..

Testade din kod nyss. Alltså säger den ifrån allt som skrivs så länge det inte är mellan tal 1-25. På så sätt slipper man ha en try-catch för både "vänligen ange heltal" och "För högt/lågt tal" eller hur?

Så jag bör använda mig av tryParse om det handlar om sådana här saker istället?

Nej, du måste deklarera en variabel om du vill använda TryParse. Om du kikar på raden

int.TryParse(Console.ReadLine(), out användarensSvar);

så ser du att det står "out" innan variabelnamnet. Det innebär att funktionen placerar ett värde i variabeln du skickar in, du måste alltså "ta emot" det värdet med en tidigare deklarerad int-variabel. Detta är rätt ovanligt sätt att skicka runt värden på, i princip är detta det enda stället jag generellt använder den metoden. Anledningen till att det görs på det sättet här är att funktionen i sig, int.TryParse, returnerar en bool som indikerar om den lyckades konvertera indatasträngen, här console.ReadLine(), till en int eller inte. Jag ignorerar dock det värdet då returvärdet i användarensSvar ändå sätts till 0 om den misslyckas med att parsa strängen, vilket kontrolleras efteråt. Vill man att användaren ska kunna skriva värdet 0 måste man dock se om funktionen lyckades eller inte, typ

if (int.TryParse(console.ReadLine(), out användarensSvar)) ...

Citat:

Testade din kod nyss. Alltså säger den ifrån allt som skrivs så länge det inte är mellan tal 1-25. På så sätt slipper man ha en try-catch för både "vänligen ange heltal" och "För högt/lågt tal" eller hur?

Ungefär så. Man slipper try-catch för att man använder TryParse istället för Parse, sedan utnyttjar jag det faktum att TryParse returnerar 0 om den misslyckas, alltså ett värde utanför det godkända intervallet 1-25, för att kontrollera om man skrivit ett giltigt tal. På det sättet behöver man inte både verifiera att det är ett tal och att talet är mellan 1 och 25, utan man kan göra det i ett steg.

Det är alltid bra att veta vad funktioner returnerar, inte både när den lyckas/misslyckas, men även om den kan kasta ett exception eller inte. Parse kastar exception medan TryParse inte gör det.

Citat:

Så jag bör använda mig av tryParse om det handlar om sådana här saker istället?

Hehe... ja... i princip... Men det är inte så att Parse är en meningslös funktion. Det är betydligt bättre prestanda i Parse-funktionen, så om jag t.ex. skulle läsa in en stor textfil där jag behövde konvertera massa värden till int och jag var relativt säker på att den var i rätt format så skulle jag använda Parse med en try-catch. Ska man bara ta emot data inskriven av en användare är TryParse rätt val.

Permalänk
Skrivet av perost:

Jag antar att out kräver att namnet som används är en variabel, och t.ex. lottoBoll[i] är inte en variabel utan ett uttryck. Så troligtvis behöver du en variabel för att lagra inmatningen innan du lägger in den i arrayen. Jag kan egentligen inte C#, så något får gärna rätta mig om jag har fel.

Men om du väljer den vägen så kan du även försöka implementera alternativet som den sista meningen i uppgiften nämner. D.v.s. istället för att alltid köra i++ i for-satsen och behöva köra i-- när något går fel så kan du välja att köra i++ endast när du lagt in ett giltigt värde i arrayen (om du inte redan har koll på det så är delarna i for-satsen valfria, for(;;) är t.ex. en giltig for-loop). Koden blir lite mer robust om man gör så, eftersom du då kan lägga till mer felhantering senare utan att behöva kopiera i---raden överallt.

Nejdå, du kan använda lottoBoll[i] istället för variabeln användarensSvar i TryParse, det var nog bara jag som misstolkade frågan. Då kan man helt plocka bort både den variabeln och else-satsen i if:en, men jag skulle personligen inte gjort så. Det blir bara krångligare att läsa koden då när man använder arrayen för att både spara korrekta värden plus det senast inmatade värdet som behöver kontrolleras. När man kommer tillbaka till sin kod 10 år senare upptäcker man att lättläst kod är en miljon gånger bättre än kod där man sparat ett par rader bara för att det gick.

Permalänk
Skrivet av KodarPolle:

"Ni ska nu kontrollera så att användaren bara skriver in ett tal mellan 1 och 25.
Detta lösas enklast genom att man styr inmatning till respektive position i vektorn med en for-loop. I
for-loopen finns en variabel (förändring, exempelvis i) som kontrollerar vilken position man för
närvarande ”pekar på” i vektorn.
Om talet som användaren skriver in är under 1 eller över 25 kan man minska värdet i variabeln (i) som
styr positionen med ett (1) enligt figuren nedan. Då ”backar” vi ett steg i vektorn.
Alltså – för varje varv som for-loopen itererar så kommer värdet på variabeln som styr förändring att
öka med ett (1). Men om vi skriver in ett ”olämpligt” värde så kommer värdet att minska med ett (1) i
koden inuti loopen.
Alternativet är att ni sparar det inmatade talet i en temporär variabel och lagrar det i vektorn om det
uppnår kraven (det vill säga är mellan ett och tjugofem)."

Så den säger väl inget om tryParse eller try-catch egentligen. Så om jag ska köra tryParse istället, måste jag då deklarera en variabel? tex användarensSvar? Eller kan man göra det utan att behöva deklarera ny variabel? Försökte utan men gick inge vidare ..

Man kan plocka bort användarSvar-variabeln och göra så här istället

for (int i = 0; i < lottoBoll.Length; i++) { Console.Write($"Spela på nummer {i + 1}: "); int.TryParse(Console.ReadLine(), out lottoBoll[i]); if (lottoBoll[i] < 1 || lottoBoll[i] > 25) { Console.WriteLine("Vänligen ange ett heltal mellan 1 och 25"); i--; } }

Men som jag skrev i ett annat svar är inte detta en lösning jag personligen skulle föredra då man i det här fallet använder arrayen för flera ändamål vilket gör det stökigt att felsöka och svårare för någon annan att följa. Läraren borde inte ha föreslagit det som en primär lösning. Visst, man ska inte deklarera massa variabler i onödan, man kan ofta komprimera ihop flera kodrader till en istället för att mellanlagra värden i variabler, men om någon annan (eller du själv om några år) ska läsa koden blir det då mycket svårare att förstå vad som händer. Det är en avvägning man lär sig med tiden, efter att man sett sin egen, bortglömda, kod ett antal gånger Men att använda samma variabel (eller array) för flera ändamål, som läraren föreslår här, är definitivt en dålig idé. Undantaget skulle vara om man kodar något extremt CPU-intensivt, t.ex. en 3D-motor, där varje operation man kan undvika resulterar i bättre prestanda, men sådant kodar man knappast i C#. För vanliga affärsapplikationer / websidor är läsbar kod a och o.

Permalänk
Hedersmedlem

Man kan deklarera en variabel "inline" med out genom att använda var out. Alltså

int.TryParse(Console.ReadLine(), var out användarensSvar);

... så behöver inte "användarensSvar" finnas innan den raden.

Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
NAS: 6700K/16GB/Debian+ZFS | Backup (offsite): 9600K/16GB/Debian+ZFS

Permalänk
Skrivet av Thomas:

Man kan deklarera en variabel "inline" med out genom att använda var out. Alltså

int.TryParse(Console.ReadLine(), var out användarensSvar);

... så behöver inte "användarensSvar" finnas innan den raden.

Du råkade visst byta plats på out och var där
Men, ja, så kan man göra. Jag vet dock inte hur detta hanteras i en loop, om man då skapar en ny variabel i varje iteration som GCn sedan behöver ta hand om.

Efter lite googlande; nej, det skapas tydligen inga onödiga, kortlivade variabler på det sättet, det blir samma resultat i IL. Där lärde man sig något nytt

Edit: Råkade använda code istället för cmd...
Edit2: Man kan väl säga att det är snäppet bättre att deklarera variabeln på det sätt som Thomas visade då man i så fall indikerar i vilket scope den används.

Permalänk
Skrivet av Thomas:

Man kan deklarera en variabel "inline" med out genom att använda var out. Alltså

int.TryParse(Console.ReadLine(), var out användarensSvar);

... så behöver inte "användarensSvar" finnas innan den raden.

Skrivet av SanguinSE:

Du råkade visst byta plats på out och var där
Men, ja, så kan man göra. Jag vet dock inte hur detta hanteras i en loop, om man då skapar en ny variabel i varje iteration som GCn sedan behöver ta hand om.

Efter lite googlande; nej, det skapas tydligen inga onödiga, kortlivade variabler på det sättet, det blir samma resultat i IL. Där lärde man sig något nytt

Edit: Råkade använda code istället för cmd...
Edit2: Man kan väl säga att det är snäppet bättre att deklarera variabeln på det sätt som Thomas visade då man i så fall indikerar i vilket scope den används.

Uppskattar verkligen all er hjälp!!
Jag hoppas och tror att jag fått till det nu, ni får gärna kolla så jag gjort rätt, och att jag förstått rätt med mina kommentarer hehe.

using System; namespace Lotto { class Program { static void Main(string[] args) { Console.WriteLine("Hej och välkommen till Lotto, låt oss spela!\nVälj 10st nummer mellan 1-25\n"); Random randomerare = new Random(); //Här har jag skapat en randomerare som jag kan slumpa tal med int slumpTal = randomerare.Next(1, 26); //Slumpar tal mellan 1-25 // Skapar vektorn: int[] lottoBoll = new int[10]; // siffran 10 beskriver hur många element vi vill använda oss av for (int i = 0; i < lottoBoll.Length; i++) // Denna loop körs tills användaren matat in tio st nummer { int nummer = i + 1; // Deklarerar variabel för visa nummer på gissning Console.Write("Spela på nummer " + nummer + ": "); int.TryParse(Console.ReadLine(), out var användarensSvar); // TryParse kontrollerar om användaren skriver in något annat än nummer mellan 1-25, använder out var för att deklarera variabeln användarensSvar if (användarensSvar < 1 || användarensSvar > 25) { Console.WriteLine("Vänligen ange ett heltal mellan 1 och 25"); i--; // Hoppar tillbaka ett steg i indexposition } else { lottoBoll[i] = användarensSvar; // Lägger in värdet i vektorn } } bool spelarenVann = false; for (int i = 0; i < lottoBoll.Length; i++) { if (lottoBoll[i] == slumpTal) { spelarenVann = true; break; // Slutar leta efter träffar om användaren gissat på rätt nummer. } } if (spelarenVann) // Detta skrivs ut om användaren lyckats gissa på det slumpade talet { Console.WriteLine($"\nBINGO! Det rätta talet var {slumpTal}"); } else // Annars skrivs nedan ut { Console.WriteLine($"\nIngen bingo denna gång, det slumpade talet var {slumpTal}!"); } Console.WriteLine("\nSpelet är slut, välkommen åter!"); Console.ReadKey(); } } }