Repeat your code with For, While and Do
Sometimes you just want to repeat yourself. Sometimes you just need to repeat yourself. All programming languages have a concept of loops and C# is no different.
Download this lesson as a Polyglot Notebook to open in Visual Studio Code, or open directly in your web browser with Binder.
We have the following keywords available to deliver looping capabilities:
for
while
do
In this lesson, we'll discuss the different ways to loop over data. This time, we will use the example of dealing cards to players in a game. This is a repeated action that you really wouldn't want to write over and over again:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInDeck = 52; cardsInDeck--; cardsInPlayer1Hand++; cardsInDeck--; cardsInPlayer2Hand++; cardsInDeck--; cardsInPlayer1Hand++; cardsInDeck--; cardsInPlayer2Hand++; display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}");
That's going to be rough to maintain if we have more than 2 players or if we want to deal more than 2 cards to each player. Let's introduce a for
loop
For Loops
For loops are a looping statement that allow you to repeat a block of code depending on a counter expression.The for statement takes the general form:
for (Initializer; Condition; Iterator) { CODE TO EXECUTE }
The Initializer
typically initializes a counter variable to be worked with.
The Condition
is a test to be executed at the beginning of each attempt to execute the code block.If the Condition
evaluates to true
then the code block will be executed.
The optional Iterator
code executes after each loop and typically increments the initialized variable , stepping towards the end value.
Let's write our first for
loop to deal 5 cards to each of 2 players:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInDeck = 52; for (var cardsDealt=0; cardsDealt<5; cardsDealt++) { cardsInDeck--; cardsInPlayer1Hand++; cardsInDeck--; cardsInPlayer2Hand++; } display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}");
That's MUCH easier to read and to work with. Why don't you try these two test scenarios to see if you understand this code:
- Deal 3 cards to each player
- Introduce a variable for the number of cards to deal and set that value to 7
You can even run for
loops inside for
loops. Let's update our sample code to introduce a for
loop for a different number of players:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInPlayer3Hand = 0; var cardsInPlayer4Hand = 0; var cardsInDeck = 52; for (var cardsDealt=0; cardsDealt<5; cardsDealt++) { for (var player=0; player<4; player++) { cardsInDeck--; if (player == 0) cardsInPlayer1Hand++; else if (player == 1) cardsInPlayer2Hand++; else if (player == 2) cardsInPlayer3Hand++; else cardsInPlayer4Hand++; } } display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}"); display($"Cards in player 3's hand: {cardsInPlayer3Hand}"); display($"Cards in player 4's hand: {cardsInPlayer4Hand}");
Pretty neat! Notice how we can also use the counter variable player
to inspect and make decisions about how we walk through the loop and what values we want to update.
WARNING: You can write infinite loops using the for
statement.The following block contains an infinite loop.Be prepared to stop the Jupyter notebook and restart it after you remove the loop.
display("this is an infinite loop... be ready to kill your notebook with the STOP button above"); /* for (var counter=1; counter>0; counter++) { ? display("Counting " + counter); } */
Stopping loops with Break
If you need to exit a loop you can execute the break
statement.
Let's go back to our dealing example, and let's deal 7 cards to each of four players but we only have 20 cards in the deck to start. This would be a problem because we are 8 cards short. We can introduce a break
statement to stop attempting to deal cards if we run out of cards:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInPlayer3Hand = 0; var cardsInPlayer4Hand = 0; var cardsInDeck = 20; for (var cardsDealt=0; cardsDealt<7; cardsDealt++) { for (var player=0; player<4; player++) { cardsInDeck--; if (player == 0) cardsInPlayer1Hand++; else if (player == 1) cardsInPlayer2Hand++; else if (player == 2) cardsInPlayer3Hand++; else cardsInPlayer4Hand++; } if (cardsInDeck < 1) { display("We've dealt all of the cards!"); break; } } display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}"); display($"Cards in player 3's hand: {cardsInPlayer3Hand}"); display($"Cards in player 4's hand: {cardsInPlayer4Hand}");
break
is a simple keyword that doesn't take any arguments and just stops the execution of the loop immediately and moves outside the loop.
There's a slight bug in this code... we deal cards to each player and then check if we have cards left in the deck. As an exercise for you, consider the following:
- We only have 23 cards left in the deck
- How should we modify this code to ensure there are always cards left in the deck when dealing to a player?
- What changes would you make to ensure that we always deal the same number of cards to each player?
Continuing processing with Continue
We can also turn this logic around and instead of testing and stopping the loop, we can continue the loop. Continue keyword allows us to stop processing any further statements in this block for the loop and resume at the beginning of the block. Let's rewrite that last example so that it continues looping even if we've run out of cards, but doesn't actually deal to the players.
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInPlayer3Hand = 0; var cardsInPlayer4Hand = 0; var cardsInDeck = 20; for (var cardsDealt=0; cardsDealt<7; cardsDealt++) { if (cardsInDeck < 1) { display("We've dealt all of the cards!"); continue; } for (var player=0; player<4; player++) { cardsInDeck--; if (player == 0) cardsInPlayer1Hand++; else if (player == 1) cardsInPlayer2Hand++; else if (player == 2) cardsInPlayer3Hand++; else cardsInPlayer4Hand++; } } display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}"); display($"Cards in player 3's hand: {cardsInPlayer3Hand}"); display($"Cards in player 4's hand: {cardsInPlayer4Hand}");
Notice that the 'we've dealt all the cards' message is displayed twice because it detected that we were out of cards twice and continued the loop. This isn't an efficient use of resources for this sample, but shows that you can continue looping if you need to.
While and Do Loops
while
and do
loops have almost identical structure and perform the same task.You provide a test condition over which the contents of the loop should continue to be executed.The while
loop executes the test FIRST before the loop statements, and the do
loop executes the test AFTER the statements.
Let's revisit our card dealing scenario and this time lets deal out ALL of the cards in the deck. If we use a while
loop, we can check if there are any cards left before we attempt to deal to the players:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInPlayer3Hand = 0; var cardsInPlayer4Hand = 0; var cardsInDeck = 52; while (cardsInDeck > 0) { for (var player=0; player<4; player++) { cardsInDeck--; if (player == 0) cardsInPlayer1Hand++; else if (player == 1) cardsInPlayer2Hand++; else if (player == 2) cardsInPlayer3Hand++; else cardsInPlayer4Hand++; } } display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}"); display($"Cards in player 3's hand: {cardsInPlayer3Hand}"); display($"Cards in player 4's hand: {cardsInPlayer4Hand}");
We could structure this so that we test if we have any cards remaining in the deck by using a do...while
loop expression like this:
var cardsInPlayer1Hand = 0; var cardsInPlayer2Hand = 0; var cardsInPlayer3Hand = 0; var cardsInPlayer4Hand = 0; var cardsInDeck = 52; do { for (var player=0; player<4; player++) { cardsInDeck--; if (player == 0) cardsInPlayer1Hand++; else if (player == 1) cardsInPlayer2Hand++; else if (player == 2) cardsInPlayer3Hand++; else cardsInPlayer4Hand++; } } while (cardsInDeck > 0); display($"Cards left in deck: {cardsInDeck}"); display($"Cards in player 1's hand: {cardsInPlayer1Hand}"); display($"Cards in player 2's hand: {cardsInPlayer2Hand}"); display($"Cards in player 3's hand: {cardsInPlayer3Hand}"); display($"Cards in player 4's hand: {cardsInPlayer4Hand}");
This APPEARS similar and in this case runs identically, but there are scenarios where you do want to test at the end of the loop instead of testing at the beginning.
The break
and continue
keywords work the same in while
and do...while
loops.