Computer Science 1xx – Assignment #N

DUE DATE: mmddyyyy  

Objects & Arrays of Object References:

The 'Snakes And Ladders' Assignment

 

Learning Objectives:
(This is a list of the major topics that you, as students, will learn in this assignment:)

  1. One-Dimensional ('Normal' ) Arrays of References To Objects:
    In this assignment, you will need to become proficient in manipulating arrays that contain references to objects.  You will need to keep track of a small subset of all the possible atomic elements, including writing code that is able to handle object references that are null.
     
  2. Basic object oriented programming:
    In this assignment, you will need to implement two, interacting classes.  One class, the GameCell class, has a minimum amount of code provided to you, and you'll need to implement most of it (this shouldn't be too tricky, though, since it's a fairly small class).  The other class, the GameBoard class, has more material provided to you, to get you started, but will require more advanced logic in order to complete the program.  The code that handles all interaction with the user, has been provided to you.  The goal here is to learn how to implement functionality that is spread across multiple classes, rather than putting everything into a single class.

Grading Rubric: This document is available for you use - you should use it to  to help guide your work.  The rubric is a document which explains how your work will be evaluated, and is located here.

Part 1: Writing the program

 

    For this assignment, you will create a C# program that begins to explore how to use object oriented programming to store and look up information. For this assignment, you'll be implementing a game of 'Snakes And Ladders' (aka 'Ropes And Ladders', aka 'Chutes And Ladders) ', which (as of July 20, 2007) Wikipedia has minimal description of here.  You can probably find better descriptions elsewhere on the web, and you can also try playing the pre-compiled example solution, in order to get a feel for how the game should be played.  The pre-compiled version that your instructor has provided for you is available at http://your.school.name/goes/here.  Please note that the starter project will compile, but won't run until you fill in your code (so compiling the starter project, running it, and having it crash is the expected result, until you add your code.

 

    While many students will undoubtedly be familiar with this common children's game, it is highly recommended that all students read through the Example Of Play document, as it describes the particulars of this variation.  Once you've read through that document (and have played the example version) , you should have a clear idea of what the final product of your work needs to look like.

 

    For this assignment, you will need to implement the logic behind two classes: the GameCell class, and the GameBoard class.  The GameBoard keeps track of all the cells on the board, using an array of references to GameCell objects.  A GameCell object is used to keep track of any gold in a cell, or if there is a snake/ladder to another cell.  Each GameCell does one, or the other, but not both.  Many/most cells on the board will have neither gold, nor a snake/ladder, and those should be represented using a null reference (instead of an object) in the GameBoard array.  Because of the linear nature of movement in the game, the GameBoard must use a one-dimensional array (a 'normal' array) to keep track of the GameCell references.

    For this assignment, you will be given a 'starter project' that contains all the code to handle the user interface of the program (all the on-screen drawing, and all the user input), and also contains starter files for the two classes you need to implement.  The GameBoard class is found in the GameBoard.cs file, and the GameCell class is found in the GameCell.cs file. 

    From here, you should finish reading this document (skimming the following tables), then open the starter project and examine the code that you'll need to finish.  At that point, return here, and read through the following tables in detail, in order to understand what your code needs to do.

    Make sure that you read the rest of this document, as the homework instructions continue after these tables!

Table 1: Methods That You Have To Implement on the GameCell class

    A couple of quick notes on the GameCell class: The GameCell class is responsible for both keeping track of two things: (1) of the amount of gold at a location (if any - this may be 'zero'), and (2) the snake (or ladder) at a location.  Normally, one would separate these two different purposes out into two separate classes, one for tracking gold, and another for ladders/snakes, so that each one would have a single, coherent, clearly identified purpose.  (These two classes might then be connected by inheriting from a common, abstract base class).  However, In order to avoid introducing advanced topics, or extra complexity,  we've decided to merge these two classes into one.  At this point, each cell contains either a snake/ladder, or gold, but not both. This keeps the GameBoard object relatively simple, as it is implemented with a single array of GameCells, (as opposed to multiple arrays, or an array of structs, etc, etc)

Data Field Name

Type

Description:

You're free to add any data fields

that you need to, in order to accomplish

the objectives set forth in this assignment

Note: all data fields should be marked private (if you need to expose them, use Properties, or accessor/mutator methods)

Method Name

Returns

Description/Parameters:

Constructor

< none >

Parameters:

  1. int myCell: This is the index of the cell with the array managed by the GameBoard object (see below).  So if a GameCell is going to be stored at slot 0 in the array, myCell will be 0.  GameCells are not moved within the array, so there is no need to change this after the object has been created.

The constructor initializes the GameCell object, so that it is ready to be used by the rest of the program.  By default, a GameCell should have no gold points, and no cells to skip (see below).

 

getCellIndex

int

The index of the cell that this GameCell object represents. 

Parameters: None

The number returned must be identical to the myCell parameter that was passed into the constructor.

setGoldPoints

void

This method will return nothing - it merely needs to remember the value (the number of gold points) that was passed into it.

Parameters:

  1. int numGoldPoints: This is the number of points that this particular piece of gold is worth.

When this method is called, the GameCell object will remember that this particular cell on the game board contains numGoldPoints worth of gold.  Note that in this game, we currently only create squares with 1 gold point each, but by using an integer (rather than,say, a bool), we can easily change this later, if we wanted.

By default, a GameCell object should have no gold points associated with it.  If the provided code needs to assign points to a GameCell object, it will do so by calling this method.

 

getGoldPoints

int

The number of gold points that this cell contains.   A GameCell that has no gold poitns should return 0

Parameters: None

The return value says it all

 

setDestination

void

This method will return nothing - it merely needs to remember where the snake/ladder at this cell goes to, so that the getCellsToSkip method will work properly (see below)

Parameters:

  1. int dstCell: The index of the cell that this snake/ladder leads to.  Note that this is the array index of the destination, so a snake/ladder going to the first cell would be given a dstCell of zero (0), NOT one.

When this method is called, the GameCell object will remember that this particular cell on the game board contains a snake (or a ladder), and that the snake/ladder leads to the cell specified by the parameter.  Both snakes AND ladders are represented in the game as a generic GameCell - the code that is provided to students handles drawing Snakes (those cells whose getCellsToSkip method returns a negative number) in one color, and drawing Ladders (those cells whose getCellsToSkip method returns a positive number) in another color.

getCellsToSkip

int

The number of cells that the snake/ladder in this cell will skip.  Ladders will return a positive number (meaning that the player will jump forwards when landing on this square), and Snakes will return a negative number (meaning that the player will jump backwards when landing on this square).

Parameters: None

As an example, let's say that a GameCell object is created in array slot #1, and that setDestination(4) is called on that object, in order to set things up so that if the player lands on slot #1, the player will skip ahead to slot #4.  In that case, getCellsToSkip should return 3 (which is 4 - 1).  This cell contains ladder because it returns a positive number, meaning that the player will jump ahead if the player lands on it.

Similarly, let's say that a GameCell object is created in array slot #5, and that setDestination(1) is called on that object, in order to set things up so that if the player lands on slot #5, the player will skip backwards to slot #1.  In that case, getCellsToSkip should return -4 (which is 1 - 5).  This cell contains snake because it returns a negative number, meaning that the player will jump backwards if the player lands on it.

Make sure that you properly encapsulate this class -
data fields should private, and unless methods are intended to be used by another class, they should be marked private, too.


 

Table 2: Methods That You Have To Implement on the GameBoard class

    A couple of quick notes on the GameBoard class: Firstly, the class itself is fairly simple and small, but in order to draw everything on the screen, it will be used by the GameBoardGUI class, which handles all the graphical user-interface logic on behalf of the game board.  In order for that class to be able to do it's job, it needs to be able to ask the GameBoard for information about how the game board is configured.  This is why there are a bunch of methods (like getTotalCellsOnBoard, and getMaxColumn) that you need to implement, that all pretty much just return information about the GameBoard.  Secondly, the GameBoard object is responsible for keeping track of where the player currently is. The GameBoardGUI class will make use of this functionality by calling the  setPlayerCellByIndex and getCellContainingPlayer methods, which you will need to implement.

Data Field Name

Type

Description:

You're free to add any data fields

that you need to, in order to accomplish

the objectives set forth in this assignment

Note: all data fields should be marked private (if you need to expose them, use Properties, or accessor/mutator methods)

Method Name

Returns

Description/Parameters:

Constructor

< none >

Parameters:

  1. int numCells: This is the total number of spaces on the board.  For a 10x10 board, this parameter would be 100.
     
  2. int maxColumn: This is the number of cells per column.  You won't be using this information, but you will need to save it, since the XNA-based graphics routines will need to know this, in order to draw the board correctly.
     

The constructor initializes the GameBoard object, so that it is ready to be used by the rest of the program.  This method should allocate any memory that will need to be used in any other methods.  The player will start out in the very first cell on the gameboard (cell #0)
 

getMaxColumn

int

This method will return the number of cells per column in the game board.

Parameters: None

The number returned must be identical to the maxColumn parameter that was passed into the constructor.

getTotalCellsOnBoard

void

This method will return the total number of spaces on the board

Parameters: None

The number returned must be identical to the numCells parameter that was passed into the constructor.

setPlayerCellByIndex

void

This method will return nothing.

Parameters:

  1. int newLocation: The index of the array slot that the player is going to move to.

When this method is called, the game board object should remember that the player's location has changed, and the location that is has changed to is indicated by the newLocation parameter.

If that parameter is out of bounds, then this method should put the player on the very first cell on the game board.

getCellContainingPlayer

GameCell

This method will return the GameCell object that the player is currently on.  If there is no GameCell object at that location, then this will return null.

Note that this is a GameCell object, and not an index (unlike the setPlayerCellByIndex method)

Parameters: None

The return value says it all.

getPlayerCellIndex

int

This method will return the index of the GameCell object that the player is currently on. 

Parameters: None

The return value says it all.

getCell

GameCell

This method will return the GameCell object that at the index specified by the index parameter.  If there is no GameCell object at that location (or if that slot is out-of-bounds), then this will return null.

Note that this is a GameCell object, and not an index (unlike the setPlayerCellByIndex method)

Parameters:

  1. int index: The array slot that the GameBoardGUI object wants to inspect.

The return value and parameter say it all.

getTotalGoldOnBoard

int

The total number of gold points that are on the entire board.

Parameters: None

This method should return the total number of points, from all the cells that contain gold, on the board.  While it is possible to 'cache' this answer, instead you should traverse the array each time, in order to get practice writing code that traverses an array of object references.

createRandomSnakeOrLadder

int

This method will return the index of the destination of the snake/ladder.  If this method decides to NOT create a new snake/ladder, then this method should return the integer INVALID_DESTINATION, which is defined for you near the top of the GameBoard.cs file.

Parameters: None

When this method is called, the GameBoard will attempt to randomly pick a destination for a new snake or ladder.  The destination must be any cell within the bounds of the array of GameCells.  It is ok for multiple snakes/ladders to all go to the same destination cell. 

However, since each slot in the GameBoard array can only hold 1 GameCell, each cell can only have 1 ladder (or snake).  You should be aware that this method may be called on an array slot that already has a snake or ladder.  If this happens, you will need to return INVALID_DESTINATION, in order to indicate that you didn't create any new snakes/ladders. 

Also, you should never create a snake/ladder that leads back to the same cell (i.e., if the player is in cell #3, don't randomly create a link to cell #3)

Make sure that you properly encapsulate this class -
data fields should private, and unless methods are intended to be used by another class, they should be marked private, too.

 

   
Other requirements: Modular Design (Functional Decomposition)
    There are several aspects of this assignment that can be put into a separate function/method, and reused from different points.  You should design your program so that it exhibits good modularity (good functional decomposition), rather than duplicating code.  For example, the user might elect to create new element from the main menu, OR when attempting to edit a non-existent element - you should be able to find a way to create a common method that executes the actions that those two tasks have in common.

    Similarly, before writing your own code, you should look and see if there is already a method that does what you need, so that you don't duplicate code that has been provided to you.

 

Extra Challenge:
    If you're looking for something extra to do, feel free to do the following.  Please note that this is in no way required for this assignment, and that you won't lose points for leaving this part out.  Conversely, you won't get extra points for doing this, either.

    First, clearly state under what conditions it is possible for the game to get stuck in an infinite loop, based on the above assignment.  The objective here is to be clear about the problem you're solving, so you can reason about it clearly, and so you can know that your fix for the problem actually works.

    Second, outline a strategy that will prevent this infinite loop from occurring.  There are at least two relatively simple ways to solve this, and at least one more complicated way to solve this - you should be able to suggest a couple of different ways to fix this, even if you're not able to write the code for all of your solutions.

    Note to instructors:

You may notice that in the GameBoardUI.cs file, in the UpdatePlayStatus method, near line 95, there's an if statement that reads:
 

    int skip = m_GameBoard.getCellContainingPlayer().getCellsToSkip();

    if (skip != 0 && false)  {

       int destCell = m_GameBoard.getPlayerCellIndex() + skip;

       GoToCell(destCell, stat);

       once = true;

       PlayCue(skip);

     }

 

This rather odd code is here to demonstrate how to something that's fun, but will cause a (logical) problem. Let's say that the player randomly creates a new snake (or ladder), and that snake/ladder's destination is a cell that contains the STARTING POINT for another snake/ladder.  If you wanted to set things up so that the player will follow the snake/ladder they just created, and end up in the destination cell, and IMMEDIATELY follow the snake/ladder in that cell, you should remove the && false from the above line.  We've left this odd if statement in the code to demonstrate how to do this fun thing :)

    Allowing the user to do this is fun, but also creates a problem - there may be a cycle (a loop) in the chain of snakes and ladders. If the player lands on one of the spaces in cycle, they'll automatically be moved to the next cell, where they'll land on the next snake/ladder (and be moved to the next cell), etc, until they're automatically moved back to the first cell, and then the whole thing begins again.  You can get this to happen with the solution file by pressing the 'make a snake/ladder' button over and over until you just happen to make a snake/ladder to a place you've already been before.  It'll take a while, and some (bad) luck, but it will happen.

    There are a number of different ways one can solve this problem.  The simplest solution is to prevent the 'chaining' from happening - if a player lands on a square with a snake/ladder, they're taken the to the cell it connects to, and then left there, even if that cell has another snake/ladder in it, which is what we've done by putting in the && false clause.  Another pretty simple solution is to not generate snake/ladders to a cell that already has one in it.  I.e., in the 'randomly place snake/ladder' routine, check if the destination cell has a snake/ladder leaving it, and if so, do NOT generate a snake/ladder to that cell, thus preventing chains (and therefore cycles) from occuring at all.  The easiest way to pick a new destination would be to simply re-generate a new random number (this is easy, but inefficient); a better way would be to count the squares that don't have snakes/ladders in them, randomly generate a number in that range, then traverse the board to find the empty cell that corresponds to that random number (this is less easy, but guaranteed to finish in a known finite time).  The more complex solution is that when the snakes/ladders are randomly being generated, a routine to check for cycles can be used to determine if the new snake/ladder is part of a cycle.  The implementation wouldn't be too bad - keep track of the current cell, then repeat the following as many times as there are cells: follow the current snake/ladder, and see if it leads to the same place as where we started (if so, there's a cycle & we're done).  If not, and there is no snake/ladder at the place we ended up, then there's no cycle, and we're done.  If the place we ended up has a snake/ladder, then it's now the current snake/ladder, and go back to the start of the loop.

 

How To Play The Game:

 

How To Play The Game:
Game/Program Controls: XBox
When running the game/program, you can control it using the following Gamepad controls:
 

§     'A' Button move forwards a randomly generated distance

§     'B' Button to create a snake (or a ladder) to a random location on the board

Game/Program Controls: PC
When running the game/program, you can control it using the following keyboard controls:

Here is the keyboard to controller mapping.

 

Group Work, Commenting:

 

            You are not allowed to work in groups for this assignment.  You should start, finish, and do all the work on your own.  If you have questions, please contact the instructor.

 

            Additionally, you should aggressively comment your code, paying particular attention to areas that are difficult to understand.  If you found something to be tricky when you wrote it, make sure to comment it so that the next person (the instructor, who's grading you) understands what your code is doing.  It is not necessary to comment every single line.

 

The purpose of new requirement is to both help you understand, and have you demonstrate, a thorough understanding of exactly how your program works.

 

Every file that you turn in should have:

·        At the top of each file that you normally edit, you should put your name (first and last), the name of this class (“BIT 142”), and the year and quarter, and the assignment number, including the revision number, which starts at 0 (“A2.0”).  If you’re handing this in again for a regrade, make sure to increase the minor version number by one (from “A2.0”, to “A2.1").
You normally edit the C# source code files (.CS files), and any Word documents that you're handing in (if any).
You do not normally edit the .SLN or .CSPROJ files, and so you should not try to put this identifying information in those files.

 

In general, you should make sure to do the following before handing in your project:

·        All variables used should have meaningful names.

·        The code should be formatted consistently, and in an easy to read format.   

 

What to turn in:

 

·        A single electronic folder (a directory).  This folder should contain:

o       The source code for the program – all the .CS files in your project.
I would prefer that you include the project files – stuff ending in .SLN and .VCPROJ, so I can build your project more easily.  If you can save these files (the .SLN / . VCPROJ) into a file format that can be opened by VS.Net 2003, that would be great.

o       You have to name the folder with your last name, then first name, then the assignment number (both the major version – 2, and the minor (revision) number – 0).  Example: "Panitz, Mike, A2.0"

 

·        You should not include the Debug directory, or anything from it.  I will dock you a couple points if you do.  Also, you don't need to include your .NCB file, if it's present.

 

How to electronically submit your homework:

 

There's a link on the homework page to the document that guides you through handing in your work, using the SourceGear Vault program.


This document and the related materials are developed with support from Microsoft Research Computer Gaming Initiative under the Computer Gaming Curriculum in Computer Science RFP, Award Number 15871.