Operację na kilku kolekcjach (losowanie kart)

0

Witam, próbuję napisać grę karcianą "oczko" w C#. Niestety gubie się przy losowaniu kart.
Chcę zrobić coś takiego:
Mam list<string> 24 kart (9-A) oraz 2 puste listy<string> - gracza i komputera.
Podczas losowania wyciągam 1 kartę z głównej kolekcji i umieszczam ją w 1 z pustych, itd. Niestety, nie bardzo wiem jak to ugryźć.

            listBox1.Items.Clear();

            i = rand.Next(0, cards.Count);
            cards.RemoveAt(i);
            j = rand.Next(0, cards.Count);
            cards.RemoveAt(j);

            listBox1.Items.Add(cards[i]);
            listBox1.Items.Add(cards[j]); 

Spróbowałem czegoś takiego (listbox jest tymczasowym rozwiązaniem bym widział jakie karty mi losuje).
Czyli, czyszcze listbox, losuje zmienną i z zakresu 0 do ilości kart w głównej talii
usuwam to co jest na miejscu wylosowanego indeksu
powtarzam to dla 2giej karty
wyświetlam

10 razy się uda, za 11 pokażą się 2 takie same karty
co jakiś czas też wywala mi taki błąd
user image

Jakieś pomysły o co chodzi?

2

Wybierasz sobie element z kolekcji. Tylko że potem go z tej kolekcji usuwasz i próbujesz go dodać do innej. Nic dziwnego, ze tak się nie da.

i = rand.Next(0, cards.Count);
cards.RemoveAt(i);
j = rand.Next(0, cards.Count);
cards.RemoveAt(j);
 
listBox1.Items.Add(cards[i]); // tutaj element cards[i] oznacza już coś innego, bo usunąłeś element cards[i], który wybrałeś wcześniej

Dodatkowo, może się zdarzyć, że i (lub j) będzie oznaczało element ostatni - jak go usuniesz, a potem się spróbujesz odwołać do elementu i, to okaże się, że w kolekcji nie ma już tylu elementów i dlatego dostaniesz ArgumentOfOfRangeException.

Może najpierw dodawaj do listBoksa, a potem dopiero usuwaj z kolekcji cards?

0

No tak... udało się, nie ma błędu, z tym że nadal raz na X operacji zdarzy się że wyświetli mi 2 te same karty - czemu? ;/

tak wygląda deklaracja tej listy (nie wiem czy jest sens robić osobną klasę dla kart?)

 public partial class mainForm : Form
    {         
        
        List<string> cards = new List<string>();
(...)
 private void newGameButton_Click(object sender, EventArgs e)
        {

             cards.Add("9 trefl");
            cards.Add("9 karo");
            cards.Add("9 kier");
            cards.Add("9 pik");
            cards.Add("10 trefl");
            cards.Add("10 karo");
            cards.Add("10 kier");
            cards.Add("10 pik");
            cards.Add("Walet trefl");
            cards.Add("Walet karo");
            cards.Add("Walet kier");
            cards.Add("Walet pik");
            cards.Add("Dama trefl");
            cards.Add("Dama karo");
            cards.Add("Dama kier");
            cards.Add("Dama pik");
            cards.Add("Krol trefl");
            cards.Add("Krol karo");
            cards.Add("Krol kier");
            cards.Add("Krol pik");
            cards.Add("As trefl");
            cards.Add("As karo");
            cards.Add("As kier");
            cards.Add("As pik");

            listBox1.Items.Clear();

           
                i = rand.Next(0, cards.Count);
                listBox1.Items.Add(cards[i]);
                cards.RemoveAt(i);
                j = rand.Next(0, cards.Count);
                listBox1.Items.Add(cards[j]);
                cards.RemoveAt(j);
              
                                             
        }
 
1

Przy każdym naciśnięciu przycisku new game dodajesz ponownie wszystkie karty do listy.

Za pierwszym razem jest ok, bo talia zawiera 24 karty i usuwasz z niej 2. Ale po następnym naciśnięciu przycisku znowu dodajesz wszystkie karty(tylko, że tym razem lista zawiera 22 poprzednie karty) i tym sposobem masz duplikaty.

0

Postanowiłem oprzeć to jednak o klasę która reprezentuje kartę, jednak mam problem z wyświetleniem...

  private void button1_Click(object sender, EventArgs e)
        {
            Random random = new Random();
            List<Karta> talia = new List<Karta>();
            foreach (char figura in Karta.Figury)
            {
                foreach (char kolor in Karta.Kolory)
                {
                    talia.Add(new Karta(kolor, figura));
                }
            }
              listBox1.Items.Add(talia);
        }

A tutaj klasa Karta

  class Karta
    {
        public static char[] Kolory = new char[4]
        {
                /* trefl */
                '\u2663',
                /* karo */
                '\u2665',
                /* kier */
                '\u2666',
                /* pik */
                '\u2660'
        };

        public static char[] Figury = new char[13]
        {
            'A', 'K', 'D', 'W', 'X', '9', '8', '7', '6', '5', '4', '3', '2'
        };

        public char Kolor { get; private set; }

        public char Figura { get; private set; }

        public Karta(char kolor, char figura)
        {
            Kolor = kolor;
            Figura = figura;
        }


    }

niestety, w listoboxie przy kazdym kliknieciu wyskakuje mi nowy napis (kolekcja) i tyle..

1

A co miałoby "wyskoczyć" jak do listboxa dodajesz obiekt listy, a nie poszczególne karty?

I uprzedzając kolejne problemy, dodaj metodę public override string ToString() do klasy Karta.

0

Rzeczywiście ;D wygląda na to że działa, udało mi się zrobić do tego tasowanie kart, tak więc jedyne co potrzebuje to teraz ściągać ostatni element z listy i umieścić go w innej liście... pytanie tylko jak to zrobić? Jest jakaś wbudowana metoda do tego?

2

RemoveAt() i Add(). Nic więcej do tego nie jest potrzebne.

0
taliaGracz.Add(talia[talia.Count-1]);
talia.RemoveAt(talia.Count-1);

coś takiego? Jakoś dziwnie to działa, przynajmniej na listboxach talia główna pozostaje cały czas pełna (kilka linijek wyzej odświeżam ten listbox uwzględniając, że powinno się wyświetlić w nim mniej kart).

1

Jak odświeżasz kilka linijek przed usunięciem to co dziwnego, że jest pełna?

0

Racja, zostaje mi jeszcze kwestia obliczenia wyniku, próbowałem napisac metodę w klasie Karta

 public int Wynik(Karta karta, int score)
        {
            if(Karta.Figury.Equals("As"))
                score += 11;

            if (Karta.Figury.Equals("Krol") || Karta.Figury.Equals("Dama") || Karta.Figury.Equals("Walet"))
                score += 10;

            return score;
        }

itd z resztą kart

Niestety bez skutku, nie mogę wywołać tego w żaden sposób ;/
Przykładowo

 
 int score = 0;

            Wynik(taliaGracz, score);

"The name "Wynik" doesnt exist in current context.

0

Metoda Wynik(...) to składowa klasy Karta, a ty nie wywołujesz jej na żadnym obiekcie. Dodatkowo metoda ta przyjmuje JEDNĄ kartę, a próbujesz do niej przekazać całą listę kart.

Jak chcesz żeby to miało ręce i nogi to proponuję zrobić klasę Talia, która będzie trzymała listę kart i udostępniała metody do dodawania/wyrzucania kart z talii gracza, obliczana wyniku itp.

1 użytkowników online, w tym zalogowanych: 0, gości: 1