public class Black Lives Matter

{

Last weekend, our hearts were too heavy with the news of yet another brutal murder of a black man by authorities, reflecting on our own privileges, and trying to come up with ways to help in the ongoing protest movement. So, we did not make a podcast episode. I will be posting a new tech blog article soon, and we hope to be back up and running with new episodes next week!

}

public class Episode 7: Movin’ Along with MVVM

{

Tim & Tim dive into their first deep-tech topic, the MVVM framework!

Subscribe

public void Summary()

{

Tim & Tim dive into their first deep-tech topic, the MVVM framework!

}

public void Links()

{

  • MVVM: Model, View, View-Model pattern
  • MVVM in Depth: Pluralsight course, great overview of WPF/MVVM design
  • XAML Behaviors for WPF: Simple nuget package that makes calling commands from Bindable events simpler
  • Stylet: Full yet simple MVVM framework, based on Caliburn.Micro, provides simple ViewModel-first view-finding
  • MVVM Light: “Light” framework
  • Prism: Another framework

}

public void News()

{

  • Java Streams: Comparable to (but maybe not as full-featured as) .NET LINQ
  • GIVEAWAY COMING UP! Leave a comment here or a review on your podcast source to be entered into our June drawing!

}

public void HotSpot()

{

  • Hand Lotion! Keep your keyboard fingers supple.
  • Surface Book 3: High-end laptop that also becomes a large tablet

}

}

public class Episode 6: Developer Burnout

{

Tim & Tim discuss what developer burnout looks like, how to deal with it, and how to avoid it.

Subscribe

public void Summary()

{

Tim & Tim discuss what developer burnout looks like, how to deal with it, and how to avoid it.

}

public void HotSpot()

{

  • Coding Blocks – Awesome dev podcast
  • Go for a Walk or a Drive! Get up outta your chair!

}

}

public class Episode 5: Java & Risk Assessment with Chris Purdum

{

Chris Purdum is a Senior Software Developer at PayPal. He talks about his work on Fraud and Risk Assessment, and compares language features of Java and .NET with Tim and Tim.

Subscribe

public void Summary()

{

Chris Purdum

Chris Purdum is a Senior Software Developer at PayPal. He talks about his work on Fraud and Risk Assessment, and compares language features of Java and .NET with Tim and Tim.

 

}

public void Links()

{

  • C++ – Low-level, un”managed”, cross-platform programming language, predecessor of Java and C#
  • PayPal – Digital payment transactions
  • Java – Original cross-platform managed language, strong inspiration for C#, still used widely and being developed/improved
  • JVMs – Java Virtual Machines
    • Zing – Azul performance-tuned JVM
  •  Scala – Succinct multi-paradigm (OOP and Functional) language that can run on both the JVM and Javascript runtimes
  • Hadoop – Distributed computing framework

}

public void HotSpot()

{

  • JFR – Java Flight Recorder: gives detailed analysis and diagnostics of the code as it runs
  • FindBugs – Static analysis for Java
  • Music! (You know where to find it…)
  • Pluralsight – Developer and IT-centered online learning site, with courses and IQ quizzes for many languages, frameworks, and patterns.

}

}

public class Episode 4: Teaming Up!

{

Subscribe

public void Summary()

{

Tim & Tim discuss the challenges and rewards of becoming team members vs. working as a solo dev.

}

public void Links()

{

}

public void HotSpot()

{

  • Display Fusion – Advanced Multi-Monitor support tool.
  • PowerToys – Free Windows plugin for multimonitor, shortcut keys, and other simple tools.

}

}

public class Episode 3: Abstract Thoughts on Abstractions

{

Subscribe

public void Summary()

{

Tim & Tim pontificate on the layers of abstractions that both make coding possible, and sometimes get in the way.

}

public void News()

{

public void HotSpot()

{

  • NotePad++ – Replacement for NotePad that will open any file, search through text of all files, and even function as a simple code editor
  • DotNetFiddle.net – Online environment for writing and compiling simple .NET test programs. Embeddable in other applications!

}

}

public class Episode 2: Strong Opinions

{

The Tims discuss what good (and bad) code looks like to them. They lay out their own preferences, from broad-scoped architecture to detailed style guides.

Subscribe

public void Summary()

{

The Tims discuss what good (and bad) code looks like to them. They lay out their own preferences, from broad-scoped architecture to detailed style guides.

}

public void News()

{

}

public void Links()

{

}

public void HotSpot()

{

  • Jetbrains – Multiple tools for developers, including IDEs, code analysis, db management
  • Rider – Powerful cross-platform .NET IDE, based on Resharper code analysis engine

}

}

public class Episode 1: The Path to Being a Developer

{

Subscribe

public void Summary()

{

Tim Purdum and Tim Jay introduce themselves, what drove them to software development, and the unique paths they each took.

}

public void Links()

{

}

public void HotSpot()

{

  • Fody – Compile-time tool for .NET
  • .NET 5 – The unified future of .NET Framework, .NET Core, Mono, and .NET Standard

}

}

public class Lesson6_GoFish_Pt2

{

void StartingTheGame()

{

This is a continuation of Lesson5_GoFish_Pt1. The full project code can be viewed or downloaded at https://github.com/TimPurdum/GoFish. In the previous post, we created a model of all the pieces needed to play the game, namely a Deck of Cards and Players with Hands and Sets.

For this part, we will be describing and programming the action or gameplay. Since the project is short, we will do this all within the Program class, although you could certainly create a Game class and move most of the code there. Let’s start by instantiating two players (one human and one computer) and a deck of cards as class fields that can be accessed from any method. The readonly tag means that these objects cannot be recreated (written to) later, although the methods and properties within are still writable.

        static readonly Deck Deck = new Deck();
        static readonly Player AI = new Player();
        static readonly Player Player = new Player();

Now let’s look at our Main method. Of course, you could put the entire logic into this method, but that would be poor design, and harder to read. Instead, we will simply deal with the introduction, shuffling the deck, and starting a while loop to create the game turns.

        static void Main()
        {
            Console.WriteLine("Let's play Go Fish!");
            Console.WriteLine("Type the letter 's' to shuffle the deck.");
            if (Console.ReadLine()?.ToLower() == "s")
            {
                Console.WriteLine("Shuffling...");
                Deck.Shuffle();
                Console.WriteLine();
                Deck.Deal(new List{Player, AI}, 7);

                while (Deck.Count > 0)
                {
                    ShowHand();
                    Guess();
                    AIGuess();
                }

                GameOver();
            }
        }

Notice that just like in our ChatBot project, we are using Console.WriteLine and Console.Readline to communicate with the user. Of course, you don’t have to introduce the game at all, or you could make it more involved (get the player’s name, for example).

The while loop represents rounds of the game. In each round, first we will ShowHand to the player, so they know what cards they have. Then, they will make a Guess, and we will deal with the results of that guess. Finally, the computer player (AI) will make their AIGuess, and the loop starts over. It ends when the deck is empty.

}

void ShowYourCards()

{

Each turn, we want to tell the player what cards they are holding.

        static void ShowHand()
        {
            Console.WriteLine("Here is your hand:");
            foreach (var card in Player.Hand)
            {
                Console.WriteLine($" - {card.Rank} of {card.Suit}");
            }
        }

}

void PlayersTurn()

{

Now it’s time for the player to take a turn. For this, we need to use Console.ReadLine() again. The player must have that rank in their hand (and if they have none, they simply draw). If the card is found, it is removed from the AI’s hand and given to the player. If not, the player must draw.

        static void Guess()
        {
            if (Player.Hand.Count == 0)
            {
                Console.WriteLine("No cards, you must draw this turn!");
                Deck.Draw(Player, 1);
                return;
            }
            
            Console.WriteLine();
            Console.WriteLine("Ask me if I have a card...");
            Console.WriteLine("(e.g., Ace, Two, Three, Four, King...)");
            var guess = Console.ReadLine();

            while (Player.Hand.All(c => c.Rank.ToString().ToLower() != guess?.ToLower()))
            {
                Console.WriteLine("You may only guess card numbers that you already have.");
                Console.WriteLine("Ask me if I have a card...");
                guess = Console.ReadLine();
            }
            
            Console.WriteLine();
            var cards = FindCards(guess, AI);
            
            if (cards != null)
            {
                var message = $"You got {cards.Count} {cards.First().Rank}!";
                if (cards.Count > 1)
                {
                    message = $"You got {cards.Count} {cards.First().PluralName}!";
                }
                Console.WriteLine(message);
                
                Player.Hand.AddRange(cards);
                foreach (var c in cards)
                {
                    AI.Hand.Remove(c);
                }
                LayoutSets(Player);
                Guess();
            }
            else
            {
                Console.WriteLine("No! Go Fish!");
                Thread.Sleep(1000);
                Deck.Draw(Player, 1);
                var newCard = Player.Hand.Last();
                Console.WriteLine($"You drew the {newCard.Rank} of {newCard.Suit}");
                LayoutSets(Player);
            }
        }

There are two places here where we have called new methods. The first is FindCards, which will search the AI player’s hand for the rank that was guessed. We are making heavy use of LINQ lambda expressions here, which you can learn more about. Any and Where are two LINQ statements that allow you to query a collection, such as a List or Array. Within each one, we declare an internal variable c, which represents each Card in the List, similar to a foreach statement. If the rank isn’t found, we can simply return null, which means no List was found.

        static List FindCards(string guess, Player p)
        {
            var cardGuess = guess.Trim().ToLower();

            if (p.Hand.Any(c => c.Rank.ToString().ToLower() == cardGuess))
            {
                return p.Hand.Where(c => c.Rank.ToString().ToLower() == cardGuess).ToList();
            }
           
            return null;
        }

The second new method is LayoutSets. This is where we will check to see if the player has four matching cards, and if so, move those sets to the Sets List.

        static void LayoutSets(Player p)
        {
            Console.WriteLine();
            
            var numberGroups = p.Hand.GroupBy(c => c.Rank);
            foreach (var numberGroup in numberGroups)
            {
                if (numberGroup.Count() == 4)
                {
                    var numberCards = numberGroup.ToList();
                    p.Sets.Add(numberCards);
                    foreach (var c in numberCards)
                    {
                        p.Hand.Remove(c);
                    }
                }
            }
            
            if (p.Sets.Count == 0)
            {
                return;
            }

            ShowSets(p);
        }

Notice that both FindCards and LayoutSets take a Player as an argument. This means that we can reuse these classes when it comes to the AI’s turn.

}

void ComputersTurn()

{

Once the player has finished, we give the computer (AI) a turn. Using Thread.Sleep() here and there can give the game a more pleasant pace, as modern computers are so fast that they will run through all these commands in less than a second.

Of course, in order to guess, we have to have the AI choose a random card rank from its hand. Luckily, .Net has a function called Random() that can do just that!

        static void AIGuess()
        {
            if (AI.Hand.Count == 0)
            {
                Console.WriteLine("No cards, I must draw this turn!");
                Deck.Draw(AI, 1);
                return;
            }
            
            var randomGenerator = new Random();

            var guessCard = AI.Hand[randomGenerator.Next(0, AI.Hand.Count - 1)];
            
            Console.WriteLine("My turn.");
            
            Console.WriteLine($"Do you have any {guessCard.PluralName}?");
            Thread.Sleep(2000);
            Console.WriteLine();
            var cards = FindCards(guessCard.Rank.ToString(), Player);
            
            if (cards != null)
            {
                if (cards.Count == 1)
                {
                    Console.WriteLine($"Yes? I'll take that {guessCard.Rank}!");
                }
                else
                {
                    Console.WriteLine($"Yes? I'll take those {guessCard.PluralName}!");
                }
                
                AI.Hand.AddRange(cards);
                foreach (var c in cards)
                {
                    Player.Hand.Remove(c);
                }
                LayoutSets(AI);
                AIGuess();
            }
            else
            {
                Console.WriteLine("No? I have to draw...");
                Thread.Sleep(1000);
                Deck.Draw(AI, 1);
                LayoutSets(AI);
            }
        }

As mentioned above, we re-use FindCards and LayoutSets for both players. Code re-use is an important principal in good programming.

}

void GameOver()

{

Let’s wrap up the game by totaling up the sets laid out and declaring a winner!

        static void GameOver()
        {
            Console.WriteLine("Game Over!");
            var playerPoints = 0;
            Player.Sets.ForEach(set => playerPoints += set.Count);
            Console.WriteLine($"Your score is {playerPoints}");
            var aiPoints = 0;
            AI.Sets.ForEach(set => aiPoints += set.Count);
            Console.WriteLine($"My score is {aiPoints}");
            if (playerPoints > aiPoints)
            {
                Console.WriteLine("You Win!");
            }
            else if (aiPoints > playerPoints)
            {
                Console.WriteLine("I Win!");
            }
            else
            {
                Console.WriteLine("Tie Game!");
            }
        }

If you have cloned the GitHub GoFish repository, and made changes to your version, feel free to create a pull request, to share your improvements back to our main repo! Or if you have a variation (maybe a new card game), you can share a link in the comments below.

}

}

public class Lesson5_GoFish_Pt1

{

void LetsPlayAGame()

{

It’s time to tackle a more complex assignment. We will start with a simple card game, “Go Fish.”

If you’ve never played, take a look at the directions at https://www.bicyclecards.com/how-to-play/go-fish/. We will be using a simple version of these rules to make our game. And if you would like to download or view the completed code project, go to https://github.com/TimPurdum/GoFish.

}

void ModelTheWorld()

{

Object-Oriented Programming is excellent for creating models of the real world, which, after all, is made up of objects. Let’s start by creating a model of a deck of cards. Actually, though, a deck of cards is just a collection of card objects, and we already know how to create collections! So, let’s start by creating a card object. What defines a card?

  • Suit – The color and symbol of the card. Hmm…maybe we need to represent suits as an object too. (In some other card games, the red suits are interchangeable, as are the black suits, so color might be important as well.)
  • Rank – The number or name of the card.

One simple way to create a list of value options is to create an enum. We will create two enums, one for Suit:

namespace GoFish
{
    public enum Suit
    {
        Hearts,
        Diamonds,
        Spades,
        Clubs
    }
}

And one for Rank:

namespace GoFish
{
    public enum Rank
    {
        Ace,
        Two,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine,
        Ten,
        Jack,
        Queen,
        King
    }
}

In VS Code, go to File => New File, and add the code above for Suit. Save as Suit.cs, and then repeat and create Rank.cs. You should see these files added to your sidebar explorer, as well as the tabs at the top.

Now let’s create our Card file, saving it as Card.cs. Add the code below. Notice that this is now a class, out of which we can create all our cards. I’ve also created a property called PluralName so that I can return a string representation of the rank in its plural form.

namespace GoFish
{
    public class Card
    {
        public Suit Suit;
        public Rank Rank;
        
        public Card (Suit suit, Rank rank)
        {
            Suit = suit;
            Rank = rank;
        }


        public string PluralName
        {
            get
            {
                if (Rank == Rank.Six)
                {
                    return Rank + "es";
                }

                return Rank + "s";   
            }
        }
    }
}

Once we have the Card class, it is easy to build a collection of cards into a Deck. But instead of creating a collection by hand, I am using inheritance to create a special SubClass of List. Notice in the class declaration line, : List<Card>. This means that a Deck will inherit all the properties and methods of a List, such as Add and Remove. But in addition, we can add our own methods, like Shuffle and Draw.

using System;
using System.Collections.Generic;
using System.Linq;

namespace GoFish
{
    public class Deck : List
    {
        readonly Suit[] suits =
        {
            Suit.Hearts,
            Suit.Clubs,
            Suit.Diamonds,
            Suit.Spades
        };

        public Deck()
        {
            for (var i = 0; i < 13; i++)
            {
                foreach (var suit in suits)
                {
                    Add(new Card(suit, (Rank)i));
                }
            }
        }


        public void Shuffle()
        {
            var rnd = new Random();
            for (var i = 0; i < Count - 1; i++)
            {
                Swap(i, rnd.Next(i, Count));
            }
        }


        public void Deal(List players, int numberOfCards)
        {
            foreach (var player in players)
            {
                player.Hand = new List();
                Draw(player, numberOfCards);
            }
        }


        public void Draw(Player player, int numberOfCards = 1)
        {
            for (var cardNum = 0; cardNum < numberOfCards; cardNum++)
            {
                player.Hand.Add(this.First());
                RemoveAt(0);
            }
        }


        public Card Peek()
        {
            return this.First();
        }


        void Swap(int a, int b)
        {
            var temp = this[a];
            this[a] = this[b];
            this[b] = temp;
        }
    }
}

}

void ReadyPlayerOne()

{

We will create one more data model class, to signify a Player. Very simply, each player needs to have a Hand and Sets, or laid down 4-of-a-kind matches. Rather than create subclasses like we did for Deck, Hand uses the default List<Card> definition. Sets, however, is a List of a List, which allows you to track multiple groups of cards.

using System.Collections.Generic;

namespace GoFish
{
    public class Player
    {
        public List Hand { get; set; }
        
        public List<list> Sets { get; } = new List<list>();
    }
}</list</list

In our next post, we will explore how to lay out the action of the game!

}

}