Simple Explanation of Foreach Iterarion

Foreach iteration 

Let consider below Example for this article;
Using "foreach iteration" on array's variables that consist  4 and 13 values for each variable, to generate 52 Cards rather than using collection initializer that could cause mistype and errors.
Creating an application that stimulate the playing of  war card game:  This application would involve the use of List  as a generic type that we had treated in the previous lesson.



This Application consists of 52 cards that are divided evenly between two players on a deck. Each player reveals the top card of their deck which is a battle and the player that has the highest card value takes both of the cards played and move them to the bottom of their deck (Ace - high,  2 is low). The only reason when there would be a war is when the two cards played are of equal values from each player.   Also for the sake of time while programming how this game could be play on computer we would cut the game off after the round of 20 as this game could continue as long as both players have cards. You can read more on how this game is played on wikipedia .

Step 1 :Set up the deck
Get the deck set up,as this would consist all the cards that the rest of our application would use.
On Deck there  should be total of 52 cards:

1.1 :  Create the deck class

public class Deck

{
  private List<Card> _deck;
}

Deck class is created and has a private property named _deck that holds the List of Cards.Now we need to initialises  _deck within the Deck constructor.
public Class Deck
{
  private List<Card> _deck;
   public Deck
    {
     _deck = new List<Card> ();
    }
}
Now that we are expecting our _deck to be populated with Cards , we need to populate our Card class with properties that it would use to make it functions. Navigate to the Cards.cs and populate it with properties.

In this case we are going to use 2 strings, named: Suit and Kind.
Suit would represents each of the cards name either: Clubs, Diamonds, Hearts, Spades while Kind would represents each of the cards kind, either: 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king, ace. 2 is low and ace is high.

1.2 : Create and populate the cards class
public Class Card
{  
public string Suit{ get; set;}  
public string Kind {get; set;}
}


Now that Card class is ready with properties, we need to assign these properties with values the would store.
Suit refers to either , Clubs, Diamonds, Hearts, Spades:
therefore we create an array name suits as a collection of these values:
string[ ] suits = new string [ ] { "Clubs", "Diamonds", "Hearts", "Spades"};
While Kind refers to either the number or jack, queen, king or ace:
string [ ] kinds = new string [ ]{"2", "3", "4", "5", "6",  "7",  " 8",  " 9",  "10 ", " jack", " queen", "king ", "ace " };

Now we could iterate through these arrays and add their values for each of the array to _deck.


1.3 : Navigate back to Deck class and add the array's values to _deck within the constructor


_deck = new List<Card>();

string[ ] suits = new string [ ] { "Clubs", "Diamonds", "Hearts", "Spades"};

string [ ] kinds = new string [ ]{"2", "3", "4", "5", "6",  "7",  " 8",  " 9",  "10 ", " jack", " queen", "king ", "ace " };


Now iterate through these arrays:

foreach ( var suit in suits )
{
   
foreach (var kind in kinds)   
{    
_deck.Add(new Card{Suit = suit , Kind = kind});   
}

}


That's for each suit each kind is evaluated, with this each suit is populated with all the kinds needed.
This actually gives 52 cards to the _deck for the players to make use of them. Iterating through it like this would have been the best rather than using a collection intializer as:

 _deck = new List<Card>();

{   
new Card{ Suit = "Clubs", Kind = "2"},   
new Card{ Suit = "Clubs", Kind = "3"},  
new Card{ Suit = "Clubs", Kind = "4"}

}


This collection intializer would result in a lot of typing for each Card , 52 in total which could open door for mistypes and cluster error.
Now that we believe to have 52 cards in _deck for the player to use them, we could as well check if this cards are really added to _deck already by printing them out to screen.

Learn also: List in C#

To do this Navigate to default.aspx.cs and inside the playButton code block, create an instance of Deck and initialize it to a new Deck.Then iterate through _deck with the help of the Deck instance created: Note: To make our _deck property visible in default.aspx.cs change the identifier from private to public. i.e. go back to the Deck class and type
public List<Card> _deck; 


TEST IF CARDS ARE  POPULATED IN _deck:

protected void playButton_Click (Object sender , EventArgs e)
{  
Deck deck = new Deck();  
foreach( var card in deck._deck)    
{     
string result= string.Format( "{0}  of  {1}" , card.Kind, card.Suit );    
}  
resultLabel.Text = result;
}


https://www.maxybyte.com/2017/10/using-foreach-iteration-on-array.html
Application Overview



































If this is done correctly, we should see our cards listening once the play Button is pressed.
Once we have tested out this code and see that it's functioning well, go back to Deck class and change back the public to private, while also we need to delete the code we had written within the playButton code block.


1.4. Randomly distribute the cards to each player


With our evaluations, we have cards on _deck and we need these cards to be given to the players equally, in this case 26 cards for each player.
Create the Player's class  and populate it with the necessary properties needed to function:
public Class Player

{   
public string Name {get; set;}  
public List<Card> Cards{get; set;} 
}


Now that Player's class is created, we need to give values to it's properties. within the Player's class code block create Player's constructor:

public Player()  
{     
Cards = new List<Card>();  
}

To populate players with Cards now, we would go back to Deck class and create a method called Deal, that will deal the Cards to each player Randomly. Now that we know we need an instance of Random class we would need to create a private Random field and set it's instance within the Deck Constructor:

public Class Deck
{
  private Random _random;
  private List<Card> _deck;


  public Deck
    {
     _random = new Random();
     _deck = new List<Card> ();
    }
}
public void Deal( Player player1, Player player2)
  {
     while(_deck.Count > 0)
     {
        int player1Card = _deck.ElementAt(_random.Next(_deck.Count));
        player1.Cards.Add(player1Card);
       _deck.Remove(player1Card);
     
        int player2Card = _deck.ElementAt(_random.Next(_deck.Count));
        player2.Cards.Add(player2Card);
       _deck.Remove(player2Card);
      }
  }


Notice the use of Random instance inside the parenthesis of ElementAt method, the purpose is to pick the Cards randomly for each player from the _deck list of cards.
In other to separate our concerns, we could simplify the Deal method so that it doesn't know too much on how card is added to each player and how cards are removed from players since it's primary assignment is to deal cards to each player. Therefore  create a private helper method called dealCard()  that returns a string to the caller this method would take in single Player's parameter: and inside its code block we could simplify what we have written within the Deal code block below:

private void dealCard(Player player)
{    
Card card = _deck.ElementAt(_random.Next(_deck.Count));    
player.Cards.Add(card);  
 _deck.Remove(card); 
}



Now rewrite our Deal( ) method, and call dealCard( ) method within it for each player:

public void Deal( Player player1, Player player2)
  {
     while(_deck.Count > 0)
     {
        dealCard(player1);
        dealCard(player2);
      }
  }





STEP 2:

2.1: GET THE DEAL CARDS WITH THE HELP OF STRINGBUILDER CLASS
As to piece together our strings by checking if our cards are dealt correctly, we would use a StringBuilder class to do this and we also need to add the using statement as to make StringBuilder available or press Ctr+ to generate the using statement. Then create a private StringBuilder field and name it _sb while right within the Deck constructor we would initialize _sb to a new StringBuilder. Therefore type these codes inside the Deck.cs :

  • private Stringbuilder _sb;

      and within the constructor type:

  • _sb = new Stringbuilder();

  Now our Deck.cs should looks like this at this point:

public Class Deck

{  
private Stringbuilder _sb;  
private Random _random;  
private List<Card> _deck;   
public Deck    
{    
_sb = new Stringbuilder();    
_random = new Random();   
 _deck = new List<Cards> ();   
 }

}


2.1: MAKE USE OF THE STRINGBUILDER INSTANCE TO FORMAT OUR RESULT TO SCREEN

According to what the dealCard() method does, we need to be able to extract our cards and print them out to the screen. So for us to be able to do this we would need to use the instance of the Stringbuilder we had created to piece together what we expect from this dealCard() method:

Now within the dealCard() method code block underneath _deck.Remove(card), type these codes:
  _sb.Append(</br>);
  _sb.Append( player.Name);
  _sb.Append(" is dealt the");
  _sb.Append(card.Kind);
  _sb.Append("of");
  _sb.Append(card.Suit);

Then the dealCard() method should look like this:

private void dealCard(Player player)
{
    Card card = _deck.ElementAt(_random.Next(_deck.Count));
    player.Cards.Add(card);
   _deck.Remove(card);
  _sb.Append(</br>);
  _sb.Append( player.Name);
  _sb.Append(" is dealt the");
  _sb.Append(card.Kind);
  _sb.Append("of");
  _sb.Append(card.Suit);
 
}



2.3: MODIFY THE DEAL METHOD TO RETURN A STRING TO THE CALLER

public string Deal( Player player1, Player player2)  
{     
while(_deck.Count > 0)    
 {       
 dealCard(player1);        
dealCard(player2);      
}     
return _sb.Tostring();  
}

Note : Since _sb is a private field within the Deck class we could reference it directly inside any of the method within this class and not outside the scope of this class. That's why we could return _sb directly to the caller after the while loop within this code block has been executed.

2.4:  CALL THE DEAL METHOD AND PRINT OUT EACH PLAYER'S CARDS
Our Deal() method is ready to give out cards to the caller, but how we do call this method to carry out this task is what next for us to setup now:
To do this we will basically look into how a game is been play on the normal life. Game is play by 2 players and each player most have a name and must be able to take an action and play. 

This would eventually lead us to creating a Game.cs that would be the manager to call our Play() method; It is obvious now that we would need to create a Play() method and a Game.cs:

public Class Game

{   
private Player _player1;   
private Player _player2;
 

}


Now that we have the Game class we would need to set up a constructor within the Game class code block that would initialize our _player's to a new Player and set up their names right up at their Object initializer:

public Game (string player1Name , string player2Name)
  

{
    

_player1 = new Player() {Name = "player1Name"};
    

_player2 = new Player() {Name = "player2Name"};
 
   

}

Now that the Game class is ready , this class still needs a method that would house our Deck logic which eventually allows the  game to be playable. In this case create a new helper method call Play() that would return a string:

public Play()
 

{
 
 

}

Our Play() method would initializes the instance of Deck and set it to a new Deck(). While the instance would call our Deal method:

public string Play()
 

{
  

 Deck  deck = new Deck();
    

 return deck.Deal();
 

}

Now Game.cs:

public Class Game
 
{
   private Player _player1;
   private Player _player2;
public Game (string player1Name , string player2Name)
 {
    _player1 = new Player() {Name = "player1Name"};
    _player2 = new Player() {Name = "player2Name"};
 }
public string Play()
    {
    Deck  deck = new Deck();
    return deck.Deal(_player1, _player2);
    }
 }


2.4.1: CALL THE PLAY METHOD WITHIN playButton_Click EVENT
Navigate to Default.aspx.cs and inside the code block of playButton Event  we need to create an instance of the Game and initializes it to a new Game that would take in 2 strings player's name within the constructor, this instance would call  the play method:

Game game = new Game("Player1" , "Player2");
resultLabel.Text = game.Play();

As it is we could see the cooperation of our methods calls, Deal returns a string to its caller, Play takes in the Deal through the help of game instance and returns finally the string we are expecting to be populated to our screen, which are the Kind and Suit for each player.
Now that these players have cards to play,  there are 3 steps for this game to pass through:


  1.  Each player would compare their cards.
  2. Player with highest card value (Ace is High) wins.
  3. Wining player would take both cards and add it to his deck.


Therefore we would treat all these steps under step 3.

STEP 3:
3.1 : CONVERT THE CARD VALUES TO INTEGER FOR COMPARISON SAKE
We had created a string type for our card's kind which we need to convert to numeric values for comparison sake, in this regards we need to create a method in Card.cs  that would set in action and convert those string values to integers:


public int CardValues()
 {
   int  value = 0;
   Switch(this.Kind)
     {
       Case  " jack" :
       value =  11;
        break;
     
       Case " queen" :
       value =  12;
        break;
     
        Case  " king " :
        value = 13 ;
        break;
     
        Case  "ace " :
        value = 14 ;
        break;
        default:
        int.TryParse(this.Kind , out value);
        break;
      }
      return value;
 }


What this method does is to check for each evaluated string values and convert it to literal integer and return the value to the caller; it starts checking with a specific typed string values and convert its value to an integer and once all the typed string values are checked, it later default to a TryParse() method and convert each string value (e.g. "2") within it to a literal int (literal 2).

3.2: PERFORM BATTLE AND CHECK THAT BOTH PLAYER'S CARD ARE NOT EQUAL TO ZERO WITHIN  THE PLAY METHOD IN THE GAME CLASS
Now that we have seen that both players have an hand of cards that they could battle with. We need to check through a while loop  that none of these players has exhausted their cards right inside a while loop within the play() method, return to the Game.cs  and within the play() method type this:

while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
{
Card player1Card = _player1.Cards.ElementAt(0);
Card player2Card = _player2.Cards.ElementAt(0);
}

 After this , we need to compare the player's card values and the player with higher card values win:

 while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
      {
         Card player1Card = _player1.Cards.ElementAt(0);
         Card player2Card = _player2.Cards.ElementAt(0);
      if (player1Card.CardValue()  >  player2Card.CardValue())
          {
          }
       }


Well in other to follow the principle of single responsibility, which states that a method should do one task and one task only.  Therefore, this concern should be house inside its own method while play() method could later incorporate the method. Therefore we need to create a private method called performEvaluation() in other to obey SoC (separation  of concerns) principle:
Now let's take this step by step:
1) Obviously we need to make sure that our player1Card and player2Card within the while loop are assigned card and that this card is removable, also that the removed card could be stored so that whichever players that win would have access to the card by taking it and place at the bottom of his deck: Therefore create a private getCard() method that returns Card to it's caller:

private Card getCard(Player player)
 {
  Card card = player.Cards.ElementAt(0);
  player.Cards.Remove(card);

 }


The getCard() method already is expecting a return value of card, but before we return card to the method , we need a _bounty of type List<Card> that would store the retrieved card from each player on each method call. So returning back to the Game.cs create  a List<Card> _bounty  and initialize _bounty to a new List<Card> within the Game constructor:

public Class Game
 {
   private Player _player1;
   private Player _player2;
   private List<Card> _bounty;
    public Game (string player1Name , string player2Name)
       {
    _player1 = new Player() {Name = "player1Name"};
    _player2 = new Player() {Name = "player2Name"};
    _bounty = new List<Card>();
        }
   }


Returning to the getCard() method and add the retrieved card to _bounty and return the card:

private Card getCard(Player player)
 {
  Card card = player.Cards.ElementAt(0);
  player.Cards.Remove(card);
  _bounty.Add(card);
    return card;
 }



 3.2.1:  The while loop Card variables should now be initialized to our getCard() method:
  while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
      {
         Card player1Card = getCard(_player1);
         Card player2Card = getCard(_player2);
      if (player1Card.CardValue()  >  player2Card.CardValue())
          {
          }
       }



This concerns would need to be place inside its own method,therefore create a private method within the Game.cs block scope that would house the if() evaluation name it performEvaluation() and pass in the Players and their Cards and the instance of these Players and Cards would call our CardValue() method to determine each player's card value: 

private void performEvaluation(Card card1, Card card2, Player player1, Player player2)
{
  if( card1.CardValue() > card2.CardValue() ) 

_player1.Cards.AddRange(_bounty);
  
else if (card2.CardValue() < card1.CardValue()) 

_player2.Cards.AddRange(_bounty);

  _bounty.Clear();
}

Notice the use of else if() right after our if () statement this is because we would use our else() for evaluations leading to a tie that would cause a  war(i.e.when the two players card values are same). After each evaluation, we added the _bounty to _player's cards with the help of AddRange() method. AddRange( ) would actually add more to the Cards on each player's hand which is absolutely differ from what Add() method does. Moreso we would need to clear out _bounty once it has been added to each _player's cards.

Returning to the Play() method in the Game.cs and replace the if () block of code within the while() loop with performEvaluation() method that we have created passing in the necessary available parameters of our Cards and Players:

while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
  {
         Card player1Card = getCard(_player1);
         Card player2Card = getCard(_player2);

         performEvaluation(player1Card, player2Card, _player1, player2 );
  }

According to one of the requirement for this challenge we would need to terminate out of the while( ) loop after 20 rounds. Returning to the the while() loop within the play() method and type: 

int round = 0;

while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
  {
     Card player1Card = getCard(_player1);
     Card player2Card = getCard(_player2);

      performEvaluation(player1Card, player2Card, _player1, player2 );
      round++;
      if ( round > 20);
      break;
  }

Right beneath the while() loop code block of codes we would need to determine the winning player after the battle, create a private method for this:

private string determineWinner()
{
   string result="";
   if (_player1.Cards.Count > _player2.Cards.Count)
     result += "<br/>Player1 Wins";
    else 
    result+= "<br/>Player2 Wins";
   
     result += "<br/> Player 1:" + _player1.Cards.Count  +
                    "<br/> Player 2:" + _player2.Cards.Count;  
     return result;
}

Within the play() method we need to change the return deck.Deal() and initializes deck.Deal() to a string variable named result so as to allow the execution flow of our codes down to the while() loop while right after the while() loop code block we could add the determineWinner() method to the result variable and return the entire result to its caller:

public string Play()
{
   Deck  deck = new Deck();
    string result = deck.Deal(_player1, _player2);

     int round = 0;

      while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
       {
         Card player1Card = getCard(_player1);
         Card player2Card = getCard(_player2);

         performEvaluation(player1Card, player2Card, _player1, player2 );
         round++;
         if ( round > 20);
         break;
         }
       result += determineWinner();
       return result;
 }


STEP 4: WAR SCENARIO:

Three things would happen when there is a war:


  1. Each player would turn up 3 more  cards with the card played that led to war.
  2. The second card out of the 3 cards would be revel by each player.
  3. Player with the high card values would take all the 8 cards and place it under his deck.

In other to separate this concerns we would create a private method called war and call getCard() method within this method three times for each player:

private void War(Player player1, Player player2)
{
   getCard(player1);
   getCard(player1);
   getCard(player1);

   getCard(player2);
   getCard(player2);
   getCard(player2);
}

Since we have a getCard() method that gives a card to each player once the method is called , we would therefore call this method three times for each player which we have done and also since we need the second card in  their list to be compared we would assigned that a variable that we would use to hold that card for evaluation. Now that we have an handle to refer to as to compare card value for each player then we could call performEvaluation() method right beneath these codes inside the War() method code block and pass in those handles as the Card parameter:

   getCard(player1);
   Card warCard1 = getCard(player1); // assigned variable to hold card value for comparison
   getCard(player1);

   getCard(player2);
   Card warCard2 = getCard(player2); // assigned variable to hold card value for comparison
   getCard(player2);
   
    performEvaluation(warCard1, warCard2, player1, player2 );

Now call War() method right beneath the else if () within the performEvaluation() method code block, this would serve as our "else": That means when neither of the if() and else if( ) statements are true then "else" would be executed. 

STEP 5: REFACTORING THE CODE WITHIN PLAY() METHOD:
Obviously play() method is doing too much, as It should house the game logic rather than performing the logic within its own code block.In this case this would lead us to create a battle class that would handle this battle logic and transfer some of the methods withing the Game class code block to the battle class, while removing those methods from the Game class:

       private class Battle
       {
               private List<Card> _bounty;
private StringBuilder _sb;
public Battle()
{
_bounty = new List<Card>();
// a new list of cards in _bounty
_sb = new StringBuilder();
// a new list of string built up by stringbuilder in _sb.
}
private Card getCard(Player player)
{
Card card = player.Cards.ElementAt(0);
// Gives a card to each player out of the 26 cards from each
player.Cards.Remove(card);
// removes the card from the losing player's hand
_bounty.Add(card);
// add the removed card to a _bounty of the type List<Card>
return card; // return the card to its caller.
}
private void performEvaluation(Card card1, Card card2, Player player1, Player player2)
{
displayBattleCards(card1, card2);
if (card1.CardValue() == card2.CardValue()) war(player1, player2);
if (card1.CardValue() > card2.CardValue()) awardWinner(player1);
else awardWinner(player2);
}
public string performBattle(Player player1, Player player2)
{
Card player1Card = getCard(player1);
Card player2Card = getCard(player2);
performEvaluation(player1Card, player2Card, player1, player2);
return _sb.ToString();
}
private void war(Player player1, Player player2)
{
// supply 3 cards for each player.
// we created a handle for the second getCard() method
//in other to use the handle for comparison
getCard(player1);
Card warCard1 = getCard(player1);
getCard(player1);
getCard(player2);
Card warCard2 = getCard(player2);
getCard(player2);
// we now called on the performevaluation to compare
// the second card for each player during war.
performEvaluation(warCard1, warCard2, player1, player2);
}
// Create a helper method to determine which cards are taking place in battle
private void displayBattleCards(Card card1, Card card2)
{
_sb.Append("<br/> Battle begins:");
_sb.Append(card1.Kind);
_sb.Append("of");
_sb.Append(card1.Suit);
_sb.Append("Versus");
_sb.Append(card2.Kind);
_sb.Append("of");
_sb.Append(card2.Suit);
}
private void displayBountyCards()
{
_sb.Append("</br>bounty...");
foreach (var card in _bounty)
{
_sb.Append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;");
_sb.Append(card.Kind);
_sb.Append("of");
_sb.Append(card.Suit);
}
}
private void awardWinner(Player player)
{
if (_bounty.Count == 0) return;
displayBountyCards();
player.Cards.AddRange(_bounty);
_bounty.Clear();
_sb.Append("<br/><strong>");
_sb.Append(player.Name);
_sb.Append("wins!</strong><br/>");
}
}

Finally call the performBattle( ) method withing the While( ) loop inside the Play( ) method code block:
public string Play()
{
   Deck  deck = new Deck();
    string result = deck.Deal(_player1, _player2);

     int round = 0;

      while(_player1.Cards.Count !=0 && _player2.Cards.Count !=0 )
       {
         Battle battle =  new Battle( );
         result += battle.perfomBattle( _player1, _player2);
         round++;
         if ( round > 20);
         break;
         }
       result += determineWinner();
       return result;
 }
Save and run:
https://www.maxybyte.com/2017/10/using-foreach-iteration-on-array.html


https://www.maxybyte.com/2017/10/using-foreach-iteration-on-array.html


https://www.maxybyte.com/2017/10/using-foreach-iteration-on-array.html

2 comments:

  1. Awesome blog. I would love to see true life prepared to walk, so please share more informative updates. Great work keeps it up. hostgator coupon

    ReplyDelete

Note: only a member of this blog may post a comment.

New Post

New style string formatting in Python

In this section, you will learn the usage of the new style formatting. Learn more here . Python 3 introduced a new way to do string formatti...