30 svar
221 visningar
Schwartz 42
Postad: 22 jul 18:42

Skapa enklare spel med klassarv, polymorfism m.m. Programmering 2

Hej. Jag har fått i uppgift att skapa ett spel, typ tre i rad, sten sax påse eller nått kortspel i C#. Vi ska använda oss av klassarv, polymorfism, parametrar, variabler och funktioner m.m. Det är de instruktionerna jag fått, inget mer. Jag sitter totalt fast, jag vet inte ens hur jag ska börja. Googlat hela dagen och jag får ju upp färdiga lösningar som jag inte fattar nånting av. Läser kursen programmering 2 och får inte jättebra hjälp från läraren. Någon av er kanske kan putta igång mig åt rätt håll iaf. Känner mig totalt värdelös som inte ens vet vart jag ska börja. :( 

Vilka variabler behövs? Kanske poängsumman till exempel. En funktion kan vara bra till att undersöka vem som vinner om man matar in varje spelares val. En annan funktion kan skriva ut resultatet på skärmen. En tredje funktion kan ge ett slumpmässigt val, om man spelar mot datorn. Dessutom behövs kanske en meny i början av spelet? 

Sedan kan du fundera på vad som skulle kunna vara användbara objekt i spelet.

Schwartz 42
Postad: 22 jul 19:09

Tack för svar! Ja, om man tänker sig sten sax påse, då behöver man ju poängsumman, så den den som först kommer till 3 vinner, då kan man ju skapa en int poängsumma1 för spelare 1 o en int poängsumma2 för datorn som man spelar mot. Funktionen för o undersöka vem som vinner klurar jag nog ut. Men hur får man in det här i klasser? O klasser som ärver från sin huvudklass? Läser en komvuxkurs, som är 5 veckor, o dessutom läste jag programmering 1 i c++, eftersom det var det enda skolan erbjöd så har jävligt svårt o få ihop nånting alls just nu känns det som. :( 

thedifference 409
Postad: 22 jul 19:16 Redigerad: 22 jul 19:18

Kanske Blackjack skulle passa. Du kan ha en klass Player med subclasses HumanPlayer och ComputerPlayer. Du kan ha en klass Card med variabler suit, value och isHidden.

Schwartz 42
Postad: 22 jul 19:17

Ska kolla! Tack för tips!

Schwartz 42
Postad: 22 jul 19:34

thedifference Har du lust o förklara lite närmare hur jag kan göra BlackJack? Insåg att jag inte vet hur spelet fungerar ens utan o blanda in programmering. :/

Det kan vara klurigt att få med klasser i sådana här "enkla" uppgifter på ett naturligt sätt. Kanske du kan ha klassen spelare och sedan låta klasserna spelare 1, 2, 3 o.s.v. ärva från den klassen. Annars kan du ha klassen utskrift och låta andra klasser som meny och resultat ärva från den klassen.

Schwartz 42
Postad: 22 jul 20:07

Magnus_O tack, det ska jag titta vidare på. Men det får nog bli imorgon, för hjärnan har sagt upp sig efter en hel dag av funderande o totalt tvärstopp. 

thedifference 409
Postad: 22 jul 22:01 Redigerad: 22 jul 22:11
Magnus O skrev:

Det kan vara klurigt att få med klasser i sådana här "enkla" uppgifter på ett naturligt sätt. Kanske du kan ha klassen spelare och sedan låta klasserna spelare 1, 2, 3 o.s.v. ärva från den klassen. Annars kan du ha klassen utskrift och låta andra klasser som meny och resultat ärva från den klassen.

Min tanke i Blackjack-fallet är att Player kan ha en funktion för att beräkna poäng och en abstrakt för att besluta om spelaren vill dra ett kort till.

Schwartz, du kanske känner till det som Tjugoett. Jag tror det här blir för rörigt om du inte kan spelet. Som alternativ skulle du bara kunna ta nån form av Poker där båda spelarna får fem kort och får byta en gång, och den som har bäst hand efteråt vinner.

Det blir väldigt jobbigt om datorn ska göra smarta val, men om den beter sig helt på måfå så är det ju samma som i sten, sax och påse, vilket också var okej att designa. Inget i din uppgiftsbeskrivning säger att datorn behöver vara en värdig motståndare. Om du fixar allt annat och har tid kvar så kan jag komma med förslag på hur den kan resonera.

Kan dock bli utmanande att skriva kod som kollar om en spelare har färg, kåk etc. Du får känna efter om detta är lämpligt för dig.

Förresten, behöver du ha GUI eller kan det vara ren terminalapp?

Schwartz 42
Postad: 22 jul 23:26

The difference, känner tyvärr inte till vare sig 21 eller poker 😅 är ingen stor kortspelare,har aldrig fastnat för det. Kämpar vidare med sten sax påse imorgon, o nej,står ingenting om att datorn måste vara en värdig motståndare. Står ingenting heller om gui eller inte, så antar att det kan vara en ren terminalapp. 🙂 Återigen, tack för svar o att ni hjälper till! 

thedifference 409
Postad: 23 jul 07:32

Okej. Det känns lite krystat med inheritance till ett så enkelt program. Du skulle kunna göra typ detta

Väldigt bra uppgift för enums, om du har lärt dig om såna.

Schwartz 42
Postad: 23 jul 09:11

Läst litegrann i boken om det, så det får säkert vara med också, men är väl inget jag känner mig jättehaj på 😅 men det gör jag ju iof inte med nånting i den här kursen känner jag 😅

Schwartz 42
Postad: 23 jul 13:02

Håller på med sten sax påse o sliter mitt hår -:) Såhär ser det ut hittills, o min fråga är ju hur jag får ihop människospelarens klick på en av knapparna med funktionen välj hand. För sen borde det ju i själva spelfunktionen som inte är byggd ännu gå o jämföra spelarens val med datorns slumpade val o därigenom få fram en vinnare? Eller är jag helt ute o cyklar?

Har en del felmeddelanden också, bla An object reference is required for the non static field, method or property Form1.Spelare.speladHand på rad 58, 63, 69. Vad beror detta på o hur löser jag det? Är det fler fel ni ser så påpeka gärna det o hjälp mig!

using static WinFormsApp9.Form1;

namespace WinFormsApp9
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public abstract class Spelare
        {
            
            public string namn;
            public int speladHand;

            public Spelare(string n)
            {
                namn = n;
            }

            public abstract int VäljHand();
        }

        public class MänskligSpelare : Spelare
        {
            MänskligSpelare minMänskligaSpelare = new MänskligSpelare("Anna");


            public MänskligSpelare(string n) : base(n)
            {

            }

            public override int VäljHand()
            {
               
            }
        }
        

        public class DatornSpelare : Spelare
        {
            public DatornSpelare(string n) : base(n)
            {
            }

            public override int VäljHand()
            {
                
                Random Slumpmässig = new Random();
                return Slumpmässig.Next(1, 3);
            }
        }
        private void btnSten_Click(object sender, EventArgs e)
        {
            MänskligSpelare.speladHand = 1; //Sten
        }

        private void btnSax_Click(object sender, EventArgs e)
        {
            MänskligSpelare.speladHand = 2; // Sax
        }

        private void btnPåse_Click(object sender, EventArgs e)
        
        {
            MänskligSpelare.speladHand = 3; // Påse
        }
        

    }

     
}
thedifference 409
Postad: 23 jul 17:05

För det första, ska du ha GUI ändå? Annars får du sluta kladda med Windows Forms. Bestäm dig här, för det blir en stor skillnad.

Du får fel för att du anropar klassen (MänskligSpelare) och inte objektet (minMänskligaSpelare).

Schwartz 42
Postad: 23 jul 17:33

Jag vet inte 😅 jag bifogar uppgiften jag fått av läraren, så kanske ni kan råda mig? Läraren rådde mig o göra sten sax påse i Windows form så jag antar att han helst vill det. Jag har löst uppgiften i consollen iaf, där har jag fått ett helt spel som fungerar, skriver ut vinnaren, räknar poäng, sparar det i en lista o sen skriver ut det när man anropar, har en meny där med. Så om ni kan hjälpa mig med Iform då, så kanske jag kan lära mig nått med. Ber om ursäkt för att det blir olika budskap från gång till gång. Får ladda upp uppgiften när jag kommer in till datorn igen,det ville sig inte i mobilen. 

Schwartz 42
Postad: 23 jul 17:35

thedifference 409
Postad: 23 jul 20:47

Nej, det är väldigt krångligt att använda polymorphism här. Har inte kommit på något vettigt sätt än.

Tillsvidare, flytta ut

MänskligSpelare minMänskligaSpelare = new MänskligSpelare("Anna");

ur klassen. Lägg det någonstans där det används.

Laguna Online 30704
Postad: 23 jul 21:06

Jag kan tänka mig att det är vettigt att definiera en klass Spelare, som får ha underklasserna MänskligSpelare (som frågar människan vid tangentbordet allting) och DatorSpelare (som gör drag automatiskt).

Då kan huvudloopen fråga spelare 1 och sen spelare 2 vad den vill göra, och så vidare, och behöver inte veta vad spelarna är för sort.

Om det förenklar någonting att göra så vet jag inte.

Schwartz 42
Postad: 23 jul 21:26

Tack för er hjälp. Fått lite feedback från läraren nu att det tydligen räckte o göra programmet i konsollen, o det har jag ju typ fått o funka, har kvar o fixa så  highscorelistan sparas till en fil som kan läsas in och användas i programmet o även spara nya resultat till den. Men det får bli imorgon. Kan ladda upp min kod för konsol programmet imorgon så får ni gärna kolla på den och komma med feedback. Blir lite lagom trött när läraren är så fruktansvärt otydlig o ena sekunden ska ha programmet i Windows form o sen går det bra i konsollen. Han borde nog gå en kurs i hur man är pedagogisk 😅 återigen, tack för er hjälp! 

thedifference 409
Postad: 23 jul 21:47
Laguna skrev:

Jag kan tänka mig att det är vettigt att definiera en klass Spelare, som får ha underklasserna MänskligSpelare (som frågar människan vid tangentbordet allting) och DatorSpelare (som gör drag automatiskt).

Då kan huvudloopen fråga spelare 1 och sen spelare 2 vad den vill göra, och så vidare, och behöver inte veta vad spelarna är för sort.

Jo, det var poängen innan GUI kom in i bilden. Problemet är att det lätt blir att med GUI så är det vyn som styr.

Eftersom TS fick gå tillbaka till konsoll så ska det här nog sluta lyckligt =)

Schwartz 42
Postad: 24 jul 12:37

Här kommer det färdiga resultatet på Sten sax påse i konsollen. Spelet kan spara ner highscore till en lista och sedan ladda upp det från listan. Synpunkter, förbättring m.m. mottages väldigt gärna, och återigen, superstort tack för all er hjälp!! :)

using System;
using System.Reflection;
using static StenSaxPåse.program;

namespace StenSaxPåse
{
    /*Klassen program som innehåller allting
     * som behövs körs i spelet. Har läst 
     * tipset att använda engelska ord för 
     * variabler, och kommer att göra det
     * i framtiden, men nu fick det bli på 
     * svenska i den sista uppgiften med.*/
    class program
    {
        /*Listan som alla highscoreresultat sparas i,
         * den innehåller både datorns och spelarens 
         * resultat samt namn*/
        static List<(string, int, string, int)
        > highScoreList = new List<(string, int, string, int)>();

        /*Basklassen Spelare som innehåller namnen,
         * vilket alternativ spelaren valde att 
         * spela med samt poäng. Klassen är 
         * abstract för att spelarna får sina 
         * variabler tilldelade i sina underklasser
         * likaså används en av funktionerna olika beroende
         * på vilken typ av spelare det handlar om. */
        public abstract class Spelare
        {
            public string namn;
            public int speladHand;
            public int poäng = 0;

            //Konstruktorn för Spelare.
            public Spelare(string n)
            {
                namn = n;
            }

            /*Funktion som konverterar spelarnas val till ord. 
             * Använder variabeln val som spelarnas val lagras i 
             * och skickar den som en parameter till funktionen för 
             * att få rätt ord.*/
            public string GörOmValTillText(int val)
            {
                if (val == 1)
                    return "Sten";
                else if (val == 2)
                    return "Sax";
                else if (val == 3)
                    return "Påse";
                else
                    return "Ogiltig inmatning";
            }

            //Funktion som lägger till poäng.
            public void LäggTillPoäng()
            {
                poäng++;
            }

            /*Den funktion som används olika beroende på vilken
             * typ av spelare det handlar om, därav är den abstract.*/
            public abstract int VäljHand();
        }

        /*Underklass till Spelare, står för den 
         * mänskliga spelaren. Ärver variabeln namn 
         * från basklassen. */
        public class MSpelare : Spelare
        {

            //Konstruktorn till klassen.
            public MSpelare(string n) : base(n)
            {
            }

            /*Funktionen VäljHand har en override funktion
             * eftersom den används på ett sätt i denna klass
             * och på ett annat sätt i en annan klass, kommer 
             * ifrån basklassen Spelare, men deklareras och skapas 
             * i denna klassen så vi kan specifikt bestämma hur vi 
             * vill att funktionen ska bete sig här. Funktionen här
             * ger den mänskliga spelaren ett val att välja om 
             * denne vill spela med Sten, Sax eller påse. Det 
             * finns också en möjlighet att gå tillbaka till 
             * huvudmenyn om man inte vill spela längre. */
            public override int VäljHand()
            {
                Console.WriteLine("Välj vad du vill spela med:");
                Console.WriteLine("1 - Sten");
                Console.WriteLine("2 - Sax");
                Console.WriteLine("3 - Påse");
                Console.WriteLine("4 - Gå tillbaka till huvudmenyn");

                int val = 0;

                while (val < 1 || val > 4)
                {
                    if (!int.TryParse(Console.ReadLine(), out val))
                    {
                        Console.WriteLine("Ogiltig inmatning, välj ett nummer mellan 1 och 4.");
                    }
                    else if (val < 1 || val > 4)
                    {
                        Console.WriteLine("Ogiltig inmatning, välj ett nummer mellan 1 och 4.");
                    }
                }
                return val;
            }
        }

        /*Underklass till Spelare, står för datorn. 
         * Ärver variabeln namn från basklassen. */
        public class DSpelare : Spelare
        {
            
            //Konstruktorn till klassen.
            public DSpelare(string n) : base(n)
            {
            }

            /*Funktionen VäljHand har en override funktion 
             * eftersom man vill att den beter sig annorlunda 
             * denna klass jämfört med den första. Deklareras 
             * därför som abstract i basklassen Spelare. Här 
             * vill vi att funktionen slumpmässigt väljer 
             * ett nummer mellan 1 och 3, vilket då 
             * motsvarar Sten, Sax eller Påse. */
            public override int VäljHand()
            {
                Random slumpmässigt = new Random();
                return slumpmässigt.Next(1, 4);
            }
        }

        /*Det här är klassen för spelet. Den innehåller
         * alla funktioner som spelet behöver för att 
         * fungera. */
        class Spelet
        {
            /*Funktionen SparaHighscore sparar och 
             * skriver ner highscorelistan 
             * till en textfil som sparas tillsammans
             * med programmet. Den sparar 
             * spelarens namn, poäng och datorns namn 
             * och poäng.*/
            public static void SparaHighscore()
            {
                using (StreamWriter writer = 
                    new StreamWriter("highscores.txt"))
                {
                    foreach (var (snamn, spoäng, 
                        dnamn, dpoäng) in highScoreList)
                    {
                        writer.WriteLine($"{snamn},{spoäng}," +
                            $"{dnamn},{dpoäng}");
                    }
                }
                Console.Clear();
                Console.WriteLine("Highscore-listan har" +
                                  " sparats till filen.");
            }

            /*Funktionen LaddaHighscore laddar in texten 
             * som finns i textfilen highscores.txt och 
             * laddar upp den i programmets minne så den 
             * sedan kan visas om spelaren väljer det. */ 
            public static void LaddaHighScore()
            {
                if (File.Exists("highscores.txt"))
                {
                    string[] rader = File.ReadAllLines
                        ("highscores.txt");
                    foreach (string rad in rader)
                    {
                        string[] lista = rad.Split(',');
                        if (lista.Length == 4 && int.TryParse
                            (lista[1], out int spoäng) && 
                            int.TryParse(lista[3], out int dpoäng))
                        {
                            highScoreList.Add((lista[0], spoäng,
                                lista[2], dpoäng));
                        }
                    }
                }
            }

            /*Funktionen VisaHighScoreLista skriver ut
             * highscorelistan. Den sorterar även 
             * listan så det högsta spelarHighscoret 
             * hamnar överst i listan. Har lagt till en 
             * ReadKey för att man bara ska få upp 
             * själva listan och inte huvudmenyn under.*/
            public static void VisaHighScoreLista()
            {
                Console.Clear();
                Console.WriteLine("Highscore-lista:");
                foreach (var (snamn, spoäng, dnamn, dpoäng)
                    in highScoreList.OrderByDescending(x => x.Item2))
                {
                    Console.WriteLine($"{snamn}: {spoäng} poäng," +
                                      $" {dnamn}: {dpoäng} poäng");
                }
                Console.Write("Tryck ned valfri tangent för att komma " +
                              "tillbaka till huvudmenyn");
                Console.ReadKey();
            }

            /*Funktionen som visar reglerna som gäller för spelet.
             * Lagt till en ReadKey för att huvudmenyn inte ska 
             * skrivas ut under reglerna.*/
            public static void VisaRegler()
            {
                Console.Clear();
                Console.WriteLine("Regler för Sten, Sax, Påse:");
                Console.WriteLine("1. Sten vinner över Sax");
                Console.WriteLine("2. Sax vinner över Påse");
                Console.WriteLine("3. Påse vinner över Sten");
                Console.WriteLine("4. Oavgjort om båda spelarna" +
                                  " väljer samma val.");
                Console.WriteLine("Tryck ned valfri tangent för" +
                                  " att komma tillbaka till huvudmenyn");
                Console.ReadKey(); 
            }

            //Funktion som avslutar spelet.
            public static void AvslutaSpelet()
            {
                Console.WriteLine("Tack för att du spelade" +
                                  " Sten, Sax, Påse!");
                Environment.Exit(0);
            }

            /*Funktion som låter spelaren skapa
             * sin spelare med namn*/
            static MSpelare SkapaSpelare()
            {
                Console.Clear();
                Console.Write("Vad är ditt namn? ");
                string spelarNamn = Console.ReadLine();
                return new MSpelare(spelarNamn);
            }

            /*Funktionen som bestämmer vilken av
             * spelarna som vinner när deras resultat
             * jämförs med varandra.*/
            static string BestämVinnare(int Mval, int DVal)
            {
                if (Mval == DVal)
                {
                    return "Oavgjort!";
                }
                else if ((Mval == 1 && DVal == 2) ||
                         (Mval == 2 && DVal == 3) ||
                         (Mval == 3 && DVal == 1))
                {
                    return "Spelaren";
                }
                else
                {
                    return "Datorn";
                }
            }
            /*Funktionen som kör själva speldelen i Sten Sax Påse.
             * Använder funktionerna som SkapaSpelare, VäljHand,
             * BestämVinnare m.fl. Sparar ner det funktionerna
             * returnerar i olika variabler som sedan används vidare.
             * Sparar ned resultatet till highscorelistan efter 
             * avslutat spel.*/
            public static void SpelaSpelet()
            {
                /*Skapar objekten för mSpelare och dSpelare.*/
                MSpelare mSpelare = SkapaSpelare();
                DSpelare dSpelare = new DSpelare("Dator");
                Console.Clear();
                bool spelar = true;
                while (spelar)
                {
                    int mVal = mSpelare.VäljHand();
                    int dVal = dSpelare.VäljHand();
                    string mValOrd = mSpelare.GörOmValTillText(mVal);
                    string dValOrd = dSpelare.GörOmValTillText(dVal);
                    string vinnare = BestämVinnare(mVal, dVal);
                    if (mVal == 4)
                    {
                        spelar = false;
                        break;
                    }
                    if (vinnare == "Spelaren")
                    {
                        mSpelare.LäggTillPoäng();
                    }
                    else if (vinnare == "Datorn")
                    {
                        dSpelare.LäggTillPoäng();
                    }

                    Console.Clear();
                    Console.WriteLine(mSpelare.namn + " valde: " + mValOrd);
                    Console.WriteLine("Datorn valde: " + dValOrd);
                    Console.WriteLine("Vinnaren är: " + vinnare);
                    Console.WriteLine("Datorns poäng: " + dSpelare.poäng);
                    Console.WriteLine(mSpelare.namn + "'s poäng: " + mSpelare.poäng);
                }
                if (mSpelare.poäng > 0 || dSpelare.poäng > 0)
                {
                    highScoreList.Add((mSpelare.namn, mSpelare.poäng, dSpelare.namn, dSpelare.poäng));
                }
            }
        }

        /*En meny i main, som låter användaren göra val på
         * vad denne vill göra, och beroende på val anropas 
         * olika funktioner i klassen Spelet.*/
        static void Main(string[] args)
        {
            Console.WriteLine("Välkommen till Sten, Sax, Påse!");
            Spelet.LaddaHighScore();
            
            while (true)
            {
                Console.Clear();
                Console.WriteLine("1 - Spela spelet");
                Console.WriteLine("2 - Visa regler");
                Console.WriteLine("3 - Visa highscore-listan");
                Console.WriteLine("4 - Avsluta");
                Console.Write("Välj ett alternativ: ");

                string choice = Console.ReadLine();

                switch (choice)
                {
                    case "1":
                        Spelet.SpelaSpelet();
                        break;
                    case "2":
                        Spelet.VisaRegler();
                        break;
                    case "3":
                        Spelet.VisaHighScoreLista();
                        break;
                    case "4":
                        Spelet.SparaHighscore();
                        Spelet.AvslutaSpelet();
                        break;
                    default:
                        Console.WriteLine("Ogiltigt val. Vänligen välj ett giltigt alternativ.");
                        break;
                }
            }
        }
    }
}
Laguna Online 30704
Postad: 24 jul 13:49

Varför behöver du System.Reflection?

Schwartz 42
Postad: 24 jul 13:55

Hmm, ingen aning, det har den lagt till själv. Ska kolla vad som händer om jag tar bort den. 

Schwartz 42
Postad: 24 jul 13:57 Redigerad: 24 jul 14:35

Det behövdes inte alls, så det är bortplockat. Tack! Såg att int speladHand inte heller användes så den har jag med plockat bort och ändrat i kommentaren. 

Vad roligt att se spelet du knåpat ihop. Du frågade efter synpunkter, så jag tog mig friheten att göra några små ändringar. Jag har inte stökat om i koden så mycket, för att det skall gå att jämföra sida vid sida. Visst kan man göra mer, men det här några förslag:

  • Använd en enum för de olika valen. Koden blir tydligare och du slipper bolla konstanter och strängar, exempelvis 1 och "Sten".
  • BestämVinnare kan ta två Spelare som argument och returnera den som vinner. Då kan du anropa LäggTillPoäng för det vinnar-objekt som returneras.
  • Duplicera inte kod, som vid valideringen av det val spelaren kan göra.

Kika på den här koden och gör med den vad du vill, men se till att du förstår den innan du "tar den som din egen". 

namespace StenSaxPåse
{
    /*Klassen program som innehåller allting
     * som behövs körs i spelet. Har läst 
     * tipset att använda engelska ord för 
     * variabler, och kommer att göra det
     * i framtiden, men nu fick det bli på 
     * svenska i den sista uppgiften med.*/
    public static class Program
    {
        /*Listan som alla highscoreresultat sparas i,
         * den innehåller både datorns och spelarens 
         * resultat samt namn*/
        private static readonly List<(string, int, string, int)> highScoreList = [];

        /*Basklassen Spelare som innehåller namnen,
         * vilket alternativ spelaren valde att 
         * spela med samt poäng. Klassen är 
         * abstract för att spelarna får sina 
         * variabler tilldelade i sina underklasser
         * likaså används en av funktionerna olika beroende
         * på vilken typ av spelare det handlar om. */
        public abstract class Spelare
        {
            public string Namn { get; private set; }
            public int Poäng { get; private set; }
            public Hand ValdHand { get; protected set; }

            //Konstruktorn för Spelare.
            public Spelare(string namn)
            {
                Namn = namn;
            }

            //Funktion som lägger till poäng.
            public void LäggTillPoäng()
            {
                Poäng++;
            }

            /*Den funktion som används olika beroende på vilken
             * typ av spelare det handlar om, därav är den abstract.*/
            public abstract void VäljHand();
        }

        /*Underklass till Spelare, står för den 
         * mänskliga spelaren. Ärver variabeln namn 
         * från basklassen. */
        public class MSpelare : Spelare
        {

            //Konstruktorn till klassen.
            public MSpelare(string namn) : base(namn)
            {
            }

            /*Funktionen VäljHand har en override funktion
             * eftersom den används på ett sätt i denna klass
             * och på ett annat sätt i en annan klass, kommer 
             * ifrån basklassen Spelare, men deklareras och skapas 
             * i denna klassen så vi kan specifikt bestämma hur vi 
             * vill att funktionen ska bete sig här. Funktionen här
             * ger den mänskliga spelaren ett val att välja om 
             * denne vill spela med Sten, Sax eller påse. Det 
             * finns också en möjlighet att gå tillbaka till 
             * huvudmenyn om man inte vill spela längre. */
            public override void VäljHand()
            {
                Console.WriteLine("Välj vad du vill spela med:");

                Console.WriteLine("0 - Gå tillbaka till huvudmenyn");
                Console.WriteLine("1 - Sten");
                Console.WriteLine("2 - Sax");
                Console.WriteLine("3 - Påse");

                while (true)
                {
                    var val = Console.ReadLine();

                    if (Enum.TryParse<Hand>(val, out var hand))
                    {
                        ValdHand = hand;

                        return;
                    }

                    Console.WriteLine("Ogiltig inmatning, välj ett nummer mellan 0 och 3.");
                }
            }
        }

        /*Underklass till Spelare, står för datorn. 
         * Ärver variabeln namn från basklassen. */
        public class DSpelare : Spelare
        {
            // @sictransit: Behöver inte skapa ny instans av Random för varje val.
            private readonly Random slumpmässigt = new();

            //Konstruktorn till klassen.
            public DSpelare(string namn) : base(namn)
            {
            }

            /*Funktionen VäljHand har en override funktion 
             * eftersom man vill att den beter sig annorlunda 
             * denna klass jämfört med den första. Deklareras 
             * därför som abstract i basklassen Spelare. Här 
             * vill vi att funktionen slumpmässigt väljer 
             * ett nummer mellan 1 och 3, vilket då 
             * motsvarar Sten, Sax eller Påse. */
            public override void VäljHand()
            {
                ValdHand = (Hand)slumpmässigt.Next(1, 4);
            }
        }

        /*Det här är klassen för spelet. Den innehåller
         * alla funktioner som spelet behöver för att 
         * fungera. */
        internal class Spelet
        {
            /*Funktionen SparaHighscore sparar och 
             * skriver ner highscorelistan 
             * till en textfil som sparas tillsammans
             * med programmet. Den sparar 
             * spelarens namn, poäng och datorns namn 
             * och poäng.*/
            public static void SparaHighscore()
            {
                using (StreamWriter writer =
                    new("highscores.txt"))
                {
                    foreach (var (snamn, spoäng,
                        dnamn, dpoäng) in highScoreList)
                    {
                        writer.WriteLine($"{snamn},{spoäng}," +
                            $"{dnamn},{dpoäng}");
                    }
                }
                Console.Clear();
                Console.WriteLine("Highscore-listan har" +
                                  " sparats till filen.");
            }

            /*Funktionen LaddaHighscore laddar in texten 
             * som finns i textfilen highscores.txt och 
             * laddar upp den i programmets minne så den 
             * sedan kan visas om spelaren väljer det. */
            public static void LaddaHighScore()
            {
                if (File.Exists("highscores.txt"))
                {
                    string[] rader = File.ReadAllLines
                        ("highscores.txt");
                    foreach (string rad in rader)
                    {
                        string[] lista = rad.Split(',');
                        if (lista.Length == 4 && int.TryParse
                            (lista[1], out int spoäng) &&
                            int.TryParse(lista[3], out int dpoäng))
                        {
                            highScoreList.Add((lista[0], spoäng,
                                lista[2], dpoäng));
                        }
                    }
                }
            }

            /*Funktionen VisaHighScoreLista skriver ut
             * highscorelistan. Den sorterar även 
             * listan så det högsta spelarHighscoret 
             * hamnar överst i listan. Har lagt till en 
             * ReadKey för att man bara ska få upp 
             * själva listan och inte huvudmenyn under.*/
            public static void VisaHighScoreLista()
            {
                Console.Clear();
                Console.WriteLine("Highscore-lista:");
                foreach (var (snamn, spoäng, dnamn, dpoäng)
                    in highScoreList.OrderByDescending(x => x.Item2))
                {
                    Console.WriteLine($"{snamn}: {spoäng} poäng," +
                                      $" {dnamn}: {dpoäng} poäng");
                }
                Console.Write("Tryck ned valfri tangent för att komma " +
                              "tillbaka till huvudmenyn");
                Console.ReadKey();
            }

            /*Funktionen som visar reglerna som gäller för spelet.
             * Lagt till en ReadKey för att huvudmenyn inte ska 
             * skrivas ut under reglerna.*/
            public static void VisaRegler()
            {
                Console.Clear();
                Console.WriteLine("Regler för Sten, Sax, Påse:");
                Console.WriteLine("1. Sten vinner över Sax");
                Console.WriteLine("2. Sax vinner över Påse");
                Console.WriteLine("3. Påse vinner över Sten");
                Console.WriteLine("4. Oavgjort om båda spelarna" +
                                  " väljer samma val.");
                Console.WriteLine("Tryck ned valfri tangent för" +
                                  " att komma tillbaka till huvudmenyn");
                Console.ReadKey();
            }

            //Funktion som avslutar spelet.
            public static void AvslutaSpelet()
            {
                Console.WriteLine("Tack för att du spelade" +
                                  " Sten, Sax, Påse!");
                Environment.Exit(0);
            }

            /*Funktion som låter spelaren skapa
             * sin spelare med namn*/
            static MSpelare SkapaSpelare()
            {
                Console.Clear();
                Console.Write("Vad är ditt namn? ");
                string spelarNamn = Console.ReadLine();
                return new MSpelare(spelarNamn);
            }

            /*Funktionen som bestämmer vilken av
             * spelarna som vinner när deras resultat
             * jämförs med varandra.*/
            static Spelare BestämVinnare(Spelare spelare1, Spelare spelare2)
            {
                if (spelare1.ValdHand == spelare2.ValdHand)
                {
                    return null;
                }

                return spelare1.ValdHand switch
                {
                    Hand.Sten => spelare2.ValdHand == Hand.Påse ? spelare2 : spelare1,
                    Hand.Sax => spelare2.ValdHand == Hand.Sten ? spelare2 : spelare1,
                    Hand.Påse => spelare2.ValdHand == Hand.Sax ? spelare2 : spelare1,
                    _ => throw new ArgumentOutOfRangeException("Whoops! Kan inte hantera detta val: " + spelare1.ValdHand),
                };
            }

            /*Funktionen som kör själva speldelen i Sten Sax Påse.
             * Använder funktionerna som SkapaSpelare, VäljHand,
             * BestämVinnare m.fl. Sparar ner det funktionerna
             * returnerar i olika variabler som sedan används vidare.
             * Sparar ned resultatet till highscorelistan efter 
             * avslutat spel.*/
            public static void SpelaSpelet()
            {
                /*Skapar objekten för mSpelare och dSpelare.*/
                MSpelare mSpelare = SkapaSpelare();
                DSpelare dSpelare = new("Dator");
                Console.Clear();

                while (true)
                {
                    mSpelare.VäljHand();

                    if (mSpelare.ValdHand == Hand.None)
                    {
                        break;
                    }

                    dSpelare.VäljHand();

                    Spelare vinnare = BestämVinnare(mSpelare, dSpelare);

                    vinnare?.LäggTillPoäng();

                    Console.Clear();
                    Console.WriteLine(mSpelare.Namn + " valde: " + mSpelare.ValdHand);
                    Console.WriteLine("Datorn valde: " + dSpelare.ValdHand);
                    Console.WriteLine("Vinnaren är: " + (vinnare != null ? vinnare.Namn : "ingen"));
                    Console.WriteLine("Datorns poäng: " + dSpelare.Poäng);
                    Console.WriteLine(mSpelare.Namn + "'s poäng: " + mSpelare.Poäng);
                }

                if (mSpelare.Poäng > 0 || dSpelare.Poäng > 0)
                {
                    highScoreList.Add((mSpelare.Namn, mSpelare.Poäng, dSpelare.Namn, dSpelare.Poäng));
                }
            }
        }

        /*En meny i main, som låter användaren göra val på
         * vad denne vill göra, och beroende på val anropas 
         * olika funktioner i klassen Spelet.*/
        static void Main(string[] args)
        {
            Console.WriteLine("Välkommen till Sten, Sax, Påse!");
            Spelet.LaddaHighScore();

            while (true)
            {
                Console.Clear();
                Console.WriteLine("1 - Spela spelet");
                Console.WriteLine("2 - Visa regler");
                Console.WriteLine("3 - Visa highscore-listan");
                Console.WriteLine("4 - Avsluta");
                Console.Write("Välj ett alternativ: ");

                string choice = Console.ReadLine();

                switch (choice)
                {
                    case "1":
                        Spelet.SpelaSpelet();
                        break;
                    case "2":
                        Spelet.VisaRegler();
                        break;
                    case "3":
                        Spelet.VisaHighScoreLista();
                        break;
                    case "4":
                        Spelet.SparaHighscore();
                        Spelet.AvslutaSpelet();
                        break;
                    default:
                        Console.WriteLine("Ogiltigt val. Vänligen välj ett giltigt alternativ.");
                        break;
                }
            }
        }

        public enum Hand
        {
            None = 0,
            Sten,
            Sax,
            Påse,
        }
    }
}
Schwartz 42
Postad: 24 jul 15:05

Tack för synpunkter, ska absolut titta igenom o se om jag förstår det såpass bra att jag kan använda något. Tack! 

Schwartz skrev:

Tack för synpunkter, ska absolut titta igenom o se om jag förstår det såpass bra att jag kan använda något. Tack! 

Bara att fråga annars. 

thedifference 409
Postad: 24 jul 17:11

Tankar om din originalkod: Till att börja med, bra struktur.

Jag tänkte att BestämVinnare skulle kunna använda enum: SpelareVinner, DatorVinner, Oavgjort.

Detta har ett antal fördelar, som inte är så tydliga när man jobbar själv:

  1. Det är tydligt vilka utfall som finns. Behöver bara läsa en fin enum-lista, inte förstå hela din funktion (även om den är liten i det här fallet).
  2. Det kan inte bli misstag med att man stavar fel.
  3. Du har just nu egentligen gett den funktionen två uppgifter. Dels att avgöra vinnare och dels att presentera resultatet ("Oavgjort!"). Det är bättre att den bara gör det första, och sen får den funktion som frågade om resultatet själv avgöra hur det ska användas.

Sen tar vi en titt på denna kodsnutt (leta efter kommentaren):

while (spelar)
{
	int mVal = mSpelare.VäljHand();
	int dVal = dSpelare.VäljHand();
	string mValOrd = mSpelare.GörOmValTillText(mVal);
	string dValOrd = dSpelare.GörOmValTillText(dVal);
	string vinnare = BestämVinnare(mVal, dVal);
	if (mVal == 4) // speciellt här
	{
		spelar = false;
		break;
	}
	if (vinnare == "Spelaren")
	{
		mSpelare.LäggTillPoäng();
	}
	else if (vinnare == "Datorn")
	{
		dSpelare.LäggTillPoäng();
	}

	Console.Clear();
	Console.WriteLine(mSpelare.namn + " valde: " + mValOrd);
	Console.WriteLine("Datorn valde: " + dValOrd);
	Console.WriteLine("Vinnaren är: " + vinnare);
	Console.WriteLine("Datorns poäng: " + dSpelare.poäng);
	Console.WriteLine(mSpelare.namn + "'s poäng: " + mSpelare.poäng);
}	

break avslutar hela while-loopen, så det hade kunnat stå självt (utan att du uppdaterar din boolean). Dessutom så kör du en massa onödig kod innan du kollar detta. Om spelaren väljer 4, då var det ju bortkastat att köra allt emellan. 

Istället skulle du kunna göra så här:

while (spelar)
{
	int mVal = mSpelare.VäljHand();
	
	if (mVal == 4)
	{
		spelar = false; // kan vara break; här istället, och en while (true)-loop, eftersom din boolean inte behövs längre då
	} else {	
		int dVal = dSpelare.VäljHand();
		string mValOrd = mSpelare.GörOmValTillText(mVal);
		string dValOrd = dSpelare.GörOmValTillText(dVal);
		string vinnare = BestämVinnare(mVal, dVal);
		if (vinnare == "Spelaren")
		{
			mSpelare.LäggTillPoäng();
		}
		else if (vinnare == "Datorn")
		{
			dSpelare.LäggTillPoäng();
		}

		Console.Clear();
		Console.WriteLine(mSpelare.namn + " valde: " + mValOrd);
		Console.WriteLine("Datorn valde: " + dValOrd);
		Console.WriteLine("Vinnaren är: " + vinnare);
		Console.WriteLine("Datorns poäng: " + dSpelare.poäng);
		Console.WriteLine(mSpelare.namn + "'s poäng: " + mSpelare.poäng);
	}
}	
Schwartz 42
Postad: 24 jul 17:16

Tack för kommentarer! Ska absolut flytta på if satsen som hör till val o lägga den högre upp. Om jag skulle vilja använda mig av enum, hur går jag om då för att få det bra? Inte riktigt fattat mig på den biten 😅 

thedifference 409
Postad: 24 jul 17:28

Prova att köra detta lilla program för att bekanta dig med enums =)

using System;

namespace GuessTheNumber

{
    class Program
    {

        enum GuessResult
        {
            Correct,
            TooHigh,
            TooLow
        }

        static GuessResult EvaluateGuess(int guess, int target)
        {
            if (guess < target) return GuessResult.TooLow;
            if (guess > target) return GuessResult.TooHigh;
            return GuessResult.Correct;
        }

        static void Main(string[] args)
        {
            Random rnd = new Random();
            int target = rnd.Next(0, 20);
            bool guessedIt = false;

            Console.WriteLine("Gissa!");

            while (!guessedIt)
            {
                int guess = Convert.ToInt32(Console.ReadLine());
                GuessResult result = EvaluateGuess(guess, target);

                switch (result)
                {
                    case GuessResult.TooLow:
                        Console.WriteLine("Högre!");
                        break;
                    case GuessResult.TooHigh:
                        Console.WriteLine("Lägre!");
                        break;
                    case GuessResult.Correct:
                        Console.WriteLine("Rätt!");
                        guessedIt = true;
                        break;
                }
            }
        }
    }
}
Schwartz 42
Postad: 24 jul 17:41

Tack, det ska jag göra! 

Svara
Close