ASP.NET Website #1: Rock, Paper, Scissors

This is the first website in my new project to create 30 such websites using ASP.NET and C#. For this, I have decided to start with creating a small game which uses image controls. What particularly attracted me was the chance to alter them dynamically during the game.

The Game

The game is fairly well known but if you are one of the few who are unfamiliar with it, it basically begins with two people making their hands into a flat shape (paper), fist (rock) or two-fingered-salute (scissors - I really didn’t know any other way to explain this!). They do this simultaneously facing one another, and the winner, loser or whether it is a draw, is determined by this table:

Quite simple, really!

Technologies Used

  • Image controls
  • CSS

Getting Some Images

First of all, I went hunting for some royalty free images that I could use and quickly settled upon OpenClipart.org which is an excellent site. Here, I found a perfect image by uroesch which was in PNG form but made up of all three hand gestures. I then needed something to signify that a choice hadn’t been taken, ending up with a nice looking question mark by warszawianka.

I chopped these into three square shaped images using GIMP, removed the spare white space around the sides and then scaled them to be 250px by 250px. They finally became these (shown for illustration purposes at 50px square):

The Main Screen

The main Default.aspx page consists of a heading followed by a number of sections. Section one represents the main elements of what you choose and what the computer responds with. That’s stored in a table but originally I used CSS controlled images. The problem was how to label them. I could have added “YOU” or “COMPUTER” to the images, but that would have required editing them and I didn’t want two sets (one for the player and one for the computer). I am sure there were other options too but still, whilst I managed this, this way, I don’t feel it was optimal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<section>
<table class="choices">
<tr>
<th>YOU</th>
<th></th>
<th>COMPUTER</th>
</tr>
<tr>
<td class="choices-item">
<asp:Image
ID="yourChoiceImage"
runat="server"
ImageUrl="~/Assets/question-mark.png"
/>
</td>
<td class="choices-item">&nbsp;VERSUS&nbsp;</td>
<td class="choices-item">
<asp:Image
class="choices-image"
ID="computerChoiceImage"
runat="server"
ImageUrl="~/Assets/question-mark.png"
/>
</td>
</tr>
</table>
</section>

In section two I placed the buttons that the user could click on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<section class="player-buttons">
<asp:ImageButton
class="player-button"
ID="rockImageButton"
runat="server"
ImageUrl="~/Assets/rock.png"
OnClick="rockImageButton_Click"
/>
<asp:ImageButton
class="player-button"
ID="paperImageButton"
runat="server"
ImageUrl="~/Assets/paper.png"
OnClick="paperImageButton_Click"
/>
<asp:ImageButton
class="player-button"
ID="scissorsImageButton"
runat="server"
ImageUrl="~/Assets/scissors.png"
OnClick="scissorsImageButton_Click"
/>
</section>

Section three contained some simple instructions and section four, the result of each match. Lastly, the footer contained the credits for the page.

Game Logic

When the user clicks on one of the player buttons (ImageButton controls) as shown above, that reflected the choice the user made. The computer then needed to choose between one of three choices which I represented as an enumerated type:

1
public enum GameChoice { rock, paper, scissors };

I did this by using the Random package with the Next method:

1
2
3
4
5
6
7
8
9
// method to make a random choice out of 1, 2, 3 for the computer
// which is then mapped to the enumerated type: GameChoice
private GameChoice ChooseComputerResponse()
{
GameChoice[] choices = { GameChoice.rock, GameChoice.paper, GameChoice.scissors };
Random rnd = new Random();
int randomResult = rnd.Next(1, 4);
return choices[randomResult - 1];
}

The logic to control this, starting at the button press was as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void scissorsImageButton_Click(object sender, ImageClickEventArgs e)
{
MakeGameChoices(GameChoice.scissors);
DisplayResult();
}

// main steps for playing the game
// given a player's choice, make the choice for the computer
private void MakeGameChoices(GameChoice player)
{
playerOption = player;
yourChoiceImage.ImageUrl = GameChoiceToAssetURL(playerOption);

computerOption = ChooseComputerResponse();
computerChoiceImage.ImageUrl = GameChoiceToAssetURL(computerOption);
}

Since this needed to happen for all three button presses with only the user’s choice changing, it made sense to organise it like this. The last step was to display the results of each match which is handled with a series of if statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void DisplayResult()
{
if (playerOption == computerOption) // two choices the same
{
resultLabel.Text = "DRAW!";
}
else if ( // options for what will produce a win
(playerOption == GameChoice.rock && computerOption == GameChoice.scissors)
||
(playerOption == GameChoice.paper && computerOption == GameChoice.rock)
||
(playerOption == GameChoice.scissors && computerOption == GameChoice.paper)
)
{
resultLabel.Text = "WIN!";
}
else // everything else must be a draw
{
resultLabel.Text = "LOSE!";
}
}

This was a little like that game Guess Who which we sell in the UK (and which is available just about everywhere, it seems!).

The idea is to guess who someone has chosen from a group of people using questions such as…does this person wear glasses?, in the hope of removing as many people as possible. In this case, I wanted to get rid of all draw results by asking if the computer’s choice matched the user’s. Then I handled the specific win situations, leaving everything else as a loss.

Adding CSS

Getting the VERSUS text to appear between the images, in the middle, was quite interesting. The trick was to set the containing element of the images to have it’s vertical-align property set to center. I did expect to put this on the image, but that won’t work.

1
2
3
.choices-item {
vertical-align: middle;
}

The buttons that the player presses needed some adjusting and experimentation, too. Here you can see how each button was rendered with it’s margin set at 10px to give a little gap between each. The container width required a little guesstimating. I expected it to be 50px x 3, plus 3 x 10px margins, making it about 180px, but I needed a little more.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.player-buttons {
width: 240px;
margin-left: auto;
margin-right: auto;
clear: both;
}

.player-button {
margin: 10px;
border-color: black;
border-style: dotted;
height: 50px;
width: 50px;
}

I also needed to reset the way the blocks flowed (hence the clear: both in the buttons section) so that they appeared underneath the main screen elements.

How Could I Improve it?

  • I added this to GitHub once it was all complete. Next time, I will start with it in the GitHub repository.
  • It might have been nice to make the hands shake at the beginning like you do in the real game before deciding. Would Javascript help here?
  • I used a table to put the headings (You and Computer) above the images of the player and computer choices. How can I do that without a table because I feel like I cheated a little? I’m not sure yet.

Lessons Learnt

  • There seemed to sometimes be a lag between editing the CSS and it appearing in the Design view of Visual Studio.
  • Hosting multiple websites on one ASP.NET hosting platform requires more than just creating sub-directories and copying the deployed files in!
  • CSS is both amazing and truly frustrating; something I keep feeling. I did learn how to embed it into my project, though.
  • ASP.NET litters the server control tags in the .aspx file with attributes that I think are better suited in a CSS file. I will need to keep a close eye on this in future.
  • I can do this!

You can find the source in the GitHub repository.


Hi! Did you find this useful or interesting? I have an email list coming soon, but in the meantime, if you ready anything you fancy chatting about, I would love to hear from you. You can contact me here or at stephen ‘at’ logicalmoon.com