4

Below is a game of cribbage that I have been working on. I have come to an elementary blockade that I cannot seem to get through.

In this section of code, I cannot figure out a way to convert the numbers coming from my array into the faces and suits that they correspond to.

Console.WriteLine("A " + deck[Game.DrawCard(deck), 0] + " of " + deck[Game.DrawCard(deck), 1] + " was drawn from the deck and then placed on top");

I can vaguely imagine a route using a long series of variables and if-statements, but I really doubt that there isn't an obvious and much simpler way.

The rest of the code looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CribbageInCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            //Variables//
            int currentPlayer;
            short score1 = 0;
            short score2 = 0;
            short round = 1;
            int[,] deck = new int[52, 2];

            Console.WriteLine("Welcome" + "\r" + "\r" + "Enter Number of Players (Only 2 player mode works right now)");
            while ((Console.ReadLine() != "2"))
            {
                Console.WriteLine("Only two player is working right now \n Make sure you are entering a number between 1-3 \n");
            }
            //A flip is made to determine who goes first//
            currentPlayer = Game.CoinFlip();
            Console.WriteLine("A coin was flipped and it was determined that player " + currentPlayer + " will go first \n");
            //Game.PrintDeck(deck);
            //Now the game is started//
            do
            {
                Console.WriteLine("Shuffling and dealing cards...");
                System.Threading.Thread.Sleep(5000);
                Game.InitDeck(deck);
                Console.WriteLine("Round " + round + "\n");
                //Cutting the Deck now that discarding has been done//
                Console.WriteLine("Cutting the deck... \n");
                System.Threading.Thread.Sleep(2000);
                Console.WriteLine("A " + deck[Game.DrawCard(deck), 0] + " of " + deck[Game.DrawCard(deck), 1] + " was drawn from the deck and then placed on top");    //Insert a swtich statement to convert pairs of numbers into actual cards
                //Player 2's turn is started now that the cut is over//
                Console.WriteLine("");

                //pick up here

                Console.WriteLine("Player " + currentPlayer + " ");


                round++;
            } while ((score1 < 121) && (score2 < 121));  //Loops until either score exceeds 121 points//
        }
    }

    class Game  //Used for functions neccesary to the function of the game that are not neccesarily dependant on turn order and do not create win conditions.
    {
        public static int CoinFlip()    //Flips to see who goes first, results are between 1-2
        {
            var rnd = new Random(DateTime.Now.Millisecond);
            int firstPlayer = rnd.Next(1, 3);
            return (firstPlayer);
        }
        public static void InitDeck(int[,] deck) // First column 11==Jack, 12==queen, 13==king && Second Column 0==diamonds, 1==clubs, 2==spades, 3==hearts
        {
            //Initiallizing the first column==Faces
            for (int i = 0; i < 4; i++)
            {
                deck[i, 0] = 13;
                deck[(i + 4), 0] = 12;
                deck[(i + 8), 0] = 11;
                deck[(i + 12), 0] = 10;
                deck[(i + 16), 0] = 9;
                deck[(i + 20), 0] = 8;
                deck[(i + 24), 0] = 7;
                deck[(i + 28), 0] = 6;
                deck[(i + 32), 0] = 5;
                deck[(i + 36), 0] = 4;
                deck[(i + 40), 0] = 3;
                deck[(i + 44), 0] = 2;
                deck[(i + 48), 0] = 1;
            }
            //Initiallizing second column==Suit
            for (int i = 0; i < 4; i++)
            {
                deck[i, 1] = i;
                deck[(i + 4), 1] = i;
                deck[(i + 8), 1] = i;
                deck[(i + 12), 1] = i;
                deck[(i + 16), 1] = i;
                deck[(i + 20), 1] = i;
                deck[(i + 24), 1] = i;
                deck[(i + 28), 1] = i;
                deck[(i + 32), 1] = i;
                deck[(i + 36), 1] = i;
                deck[(i + 40), 1] = i;
                deck[(i + 44), 1] = i;
                deck[(i + 48), 1] = i;
            }
        }
        public static void PrintDeck(int[,] deck)
        {
            for (int i = 0; i < 52; i++)
            {
                Console.WriteLine(deck[i, 0] + "F");
                Console.WriteLine(deck[i, 1] + "S");
            }
            Console.ReadLine();
        }
        public static int DrawCard(int[,] deck) //Draws a card from the deck, ignoring Cards already drawn this turn. IF THERE ARE ANY ERRORS COME HERE AND CHECK THIS FIRST
        {
            var rnd = new Random(DateTime.Now.Millisecond);
            int o = rnd.Next(0, 51);
            while (deck[o,0]==0)
            {
                System.Threading.Thread.Sleep(1000);
                rnd = new Random(DateTime.Now.Millisecond);
                o = rnd.Next(0, 51);
            }
            int drawnCard = o;
            deck[o, 0] = 0;

            return (drawnCard);
        }

    }
}

I also have had a feeling that an array for the deck of cards might not have been the smartest decision vs. a list, but I am not positive.

I really do apologize. While it may seem obvious to others that my topic has already been covered, my limited understanding of C# is not allowing me to interpret any answers from any posts that I have turned up in the last hour or so. I am trying to learn C# by programming an easy game via console window as that is how I learned what I have of C++.

Thanks ahead of time for anyone's help. I do really appreciate it!

3 Answers3

7

First off, I would store the shuffled cards in a List, or even better, a Queue. This allows you to just "pick off" a card from the deck.

To get the cards and suites, I would create two enums:

public enum Rank
{
   Ace,
   Two,
   Three,
   ...
}

public enum Suits
{
   Hearts,
   Spades,
   ...
}

Now you define your cards such that 0 = aH, 1 = 2H, 13 = aS, and so on.

Now you can do this:

public Rank GetRankForCard(int card)
{
     return (Rank)(card % 13);
}

public Suit GetSuitForCard(int card)
{
    return (Suit)(card / 13);
}

The % (modulus) operator is really useful here. As a final note, cribbage is not a trivial game to implement (having done it myself in WPF), so good luck!

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • I never expected to get so much help so quickly! Thank you guys. After I finish trying to understand dictionaries from the last poster, I will try and learn queues and enums. Both of which I have never even heard of before just right now lol. My only concern is that I dont have a shuffled deck to store, as I have been picking randomly from a sorted deck. This is also a process that has yet to produce more than three numbers in the way that I have it implemented, so I will definitely be trying your way. – hotmaildotcom1 Dec 19 '14 at 19:22
  • 1
    @hotmaildotcom1 The problem with picking randomly from a sorted deck is making sure you don't repeat. By shuffling into a queue, you guarantee that you don't have duplicate cards. – BradleyDotNET Dec 19 '14 at 19:23
  • I'm trying to follow here but I cannot understand the card variable and why it's being divided or "modulo-ed." I'm sure there is a simple implied meaning that I just am not understanding, would you mind clarifying? – hotmaildotcom1 Dec 19 '14 at 19:52
  • @hotmaildotcom1 I have no problem doing so, but it might be a bit too back and forth for comments. Perhaps we should [chat](http://chat.stackoverflow.com/rooms/67349/discussion-of-so-question-27572454) – BradleyDotNET Dec 19 '14 at 19:53
2

What I was getting at in my comment:

Dictionary<int, string> Cards = new Dictionary<int, string>
{
     {1, "Ace" },
     {2, "Two"}
     //etc
};

Dictionary<int, string> Suits = new Dictionary<int, string>
{
     {1, "Hearts"},
     {2, "Clubs"}
     //etc
};

And use it like :

Console.WriteLine("A {0} of {1} was drawn from the deck and then placed on top",                
                     Cards[deck[Game.DrawCard(deck), 0]], 
                     Suits[deck[Game.DrawCard(deck), 0]]);

It's much better to use a formatted string, rather than string concatenation when you need to combine strings. Both performance and readability is better.

Jonesopolis
  • 25,034
  • 12
  • 68
  • 112
  • So by adding Cards[] to the statement after having previously constructed it and it's definitions, any int's matching the int's listed in that dictionary will be converted to that string? – hotmaildotcom1 Dec 19 '14 at 19:27
  • `Cards[i]` will return the `Value` in the dictionary `Cards` with the `Key` `i`. So yes, though it's not really `converted to a string`, it's just looking up the value based on a given key. In our case the value is of type string. – Jonesopolis Dec 19 '14 at 19:32
  • One issue with this approach, you end up with a *lot* of duplicated entries (ie, the Cards one needs a {13, "Ace"} entry). Otherwise a decent approach. @hotmaildotcom1 That is basically correct, you are indexing *into* the dictionary, and it returns the matching value (string in this case). – BradleyDotNET Dec 19 '14 at 19:32
  • Good point @BradleyDotNET. I wasn't paying enough attention to see that deck has a size of 52 instead of 13 like I imagined. You can always throw the `%` in there, but I like your answer better. – Jonesopolis Dec 19 '14 at 19:34
0

You can use a switch statement, something like:

string suit = String.Empty;

switch(SuitIndex)
{
   case 1:
   suit = "Diamonds";
   break;

   case 2:
   suit = "Clubs";
   break;

   case 3:
   suit = "Hearts";
   break;

   case 4:
   suit = "Spades";
   break;
}
Sean
  • 46
  • 3