import java.io.*;
/**
* Traffic Jam Application.
* Traffic Jam is a simple brain teaser style puzzle game.
*
* Software Architecure: Sequential
*
* Design Overview:
* This version uses a classic functional decomposition.
* The main module controls the overall game logic. It is
* essentially a loop which repeats taking turns until the player
* wins the game.
*
*
while puzzle not solved
* make a move
* display updated board
* end while
*
*
* Design Issues:
* The choice of an array for the data structure was obvious, since we
* needed a linear structure which allowed access to any element.
* The only tradeoff we made was whether or not to keep track of the spot
* on the board that is empty.
* Cons: Requires a "state" variable to record the empty position.
* Pros: Avoids having to search the array each time to find where
* the current empty spot is.
* We decided that keeping an extra "state" variable was worth the
* reduction in algorithm complexity we would gain by not having to
* search the array at each move.
*
* Tools: JDK 1.4
*
* Libraries: none
*
* External References: http://www.csc.calpoly.edu/~jdalbey/205/TrafficJam/
*
* @author John Dalbey
* @version 4.0 Java 11/2003
*/
public class TrafficJam_SD
{
/**
*
* Traffic Jam Puzzle Board
*
* Description:
* A traffic puzzle board is an abstraction of the playing board in the
* traffic jam game. It is a linear arrangement of 11 "stones" on which two
* groups of five people are trying to pass each other.
*
* Structure:
* The board has a linear structure.
*
* Elements:
* There are 11 elements (stones) on the board, numbered 1 - 11, that can be
* either occupied or empty. If occupied, the rock contains a person facing
* either left or right.
*
* Implementation:
* An array of 11 spots.
* Note: Java requires arrays be zero-based so we declare an array one larger
* than needed and we never use the zeroth spot.
*
*/
private final int kBoardSize = 11;
private int[] Puzzle = new int[kBoardSize+1];
// Values that can be assigned to a spot on the board.
/** A person facing to the Left */
public final static int L = 1;
/** A person facing Right */
public final static int R = 3;
/** An Empty spot on the board */
public final static int E = 2;
/** the starting board configuration */
private int[] startPuzzle = {0,R,R,R,R,R,E,L,L,L,L,L};
/** the winning board configuration */
private int[] Solution = {0,L,L,L,L,L,E,R,R,R,R,R};
/** almost solved configuration, to be used for testing */
private int[] Almost = {0,L,L,L,L,L,R,E,R,R,R,R};
/** the location of the empty spot on the board */
private int emptyPosition;
/** Entry point for this application */
public static void main(String[] args)
{
TrafficJam_SD myApp = new TrafficJam_SD();
myApp.runGame();
}
/**
* Creates the initial board position.
*/
public void resetBoard()
{
System.arraycopy(startPuzzle,0,Puzzle,0,startPuzzle.length);
emptyPosition = 6; // Initially the empty spot is in the middle
// optional statements for testing end of game
//System.arraycopy(Almost,0,Puzzle,0,Almost.length);
//emptyPosition = 7; // use 7 for testing, use 6 for real game
}
/** Run the game by controlling the high level game logic. */
public void runGame()
{
showHelp();
resetBoard();
displayBoard();
// while puzzle not solved
while (! isSolved() )
{
makeMove();
displayBoard();
}
System.out.println();
System.out.println(" *** Hurray, you won! ***");
}
/** Allow the player to make a move in the game. */
public void makeMove()
{
BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));
int userMove = 99; // initialize usermove to an illegal value
// repeat until legal move
do
{ // Prompt for move
System.out.println("Your move? ");
try
{
userMove = getMove(consoleIn);
}
// Handle I/O errors
catch (IOException ex)
{
ex.printStackTrace();
}
// IF nonumeric character entered THEN
catch (NumberFormatException ex)
{
// Quit the game
System.out.println("Game terminated.");
System.exit(0);
}
// IF user wants to reset the board (userMove = 0) THEN
if ( userMove == 0 )
{
resetBoard();
displayBoard();
}
}
while (! isLegal (userMove) );
//System.out.println("Echo: " + userMove);
// Apply the move to the board (call updateBoard with userMove)
updateBoard (userMove);
}
/**
* Get the user's move from the console.
* @param consoleIn an open BufferedReader to read from.
* @return int an integer representing which stone is occupied by
* the person to be moved.
*/
public int getMove(BufferedReader consoleIn) throws IOException, NumberFormatException
{
// Read a line from the console
String inputLine = consoleIn.readLine();
// Convert user input to an integer
return Integer.parseInt(inputLine);
}
/**
* Update the board by moving a person to the empty spot.
* @param position integer indicating the position on the board from which a person
* is to be moved.
*
Pre: 1 <= Position <= 11
*/
public void updateBoard(int position)
{
// Swap the person with the empty spot
Puzzle[emptyPosition] = Puzzle[position];
Puzzle[position] = E;
// Indicate where the new empty spot is.
emptyPosition = position;
}
/**
* Check if the move follows the rules of the game.
* @param theMove integer indicating the position on the board to be checked.
* @return true if the move is legal, false otherwise.
*/
public boolean isLegal(int theMove)
{
// IF theMove is not negative THEN
if (theMove > 0)
{
try
{
// Evaluate each direction the piece is facing
switch (Puzzle[theMove])
{
case E:
return false; // can't move from empty spot
case R: // facing right can move if
return (Puzzle[theMove+1] == E) // adjacent to empty
|| // or else
(Puzzle[theMove+1]==L && // could leapfrog
Puzzle[theMove+2]==E);
case L: // facing right can move if
return (Puzzle[theMove-1] == E) // adjacent to empty
|| // or else
(Puzzle[theMove-1]==R && // could leapfrog
Puzzle[theMove-2]==E);
}// end switch
return true; // dummy return - compiler insists on it
}
// IF index out of bounds THEN
catch (ArrayIndexOutOfBoundsException exception)
{
// the move is illegal
return false;
}
}
return false;
} // END isLegal
/**
* See if the board is in the winning configuration.
* @return true if the board is in the winning configuration, false otherwise.
*/
public boolean isSolved()
{
// FOR each position on the board
for (int i=1; i<=kBoardSize; i++)
{
// IF the current board doesn't match solution THEN
if (Puzzle[i] != Solution[i])
{
return false;
}
} // END FOR
return true;
}
/**
* Display the current board configuration.
*/
public void displayBoard()
{
// FOR each position on the board
for (int i=1; i<=kBoardSize; i++)
{
// Determine the printable symbol for the position
switch (Puzzle[i])
{
case E:
System.out.print(" . ");
break;
case R:
System.out.print(" > ");
break;
case L:
System.out.print(" < ");
break;
}// END CASE
} // END FOR
System.out.println();
System.out.println("--- --- --- --- --- --- --- --- --- --- ---");
System.out.println(" 1 2 3 4 5 6 7 8 9 10 11");
}
/** Display directions for how to play the game. */
public void showHelp()
{
System.out.println (" TRAFFIC JAM");
System.out.println ("Two groups of 5 people (shown as arrows) are crossing a river in opposite ");
System.out.println ("directions by hopping on rocks. There are eleven rocks and in the starting ");
System.out.println ("configuration, the empty rock (.) is in between the two groups.");
System.out.println ("> > > > > . < < < < < ");
System.out.println ("GOAL: The objective is for the two groups to exchange sides, that is,");
System.out.println ("to pass each other. Thus, the winning configuration is:");
System.out.println ("< < < < < . > > > > > ");
System.out.println ("RULES: 1. People can only move forward in the direction they are facing. ");
System.out.println ("No backstepping or turning around. 2. Only one person may move at a time.");
System.out.println ("3. There are two kinds of legal moves:");
System.out.println (" A) A person may move into an adjacent empty space immediately");
System.out.println (" in front of them. ");
System.out.println (" B) A person may move around someone (or leapfrog over them)");
System.out.println (" into an empty space behind them, if they are adjacent");
System.out.println (" and FACING each other.");
System.out.println ("MOVING: Enter the number of the person you desire to move. Enter 0 to ");
System.out.println ("start over, any alphabetic key to quit.");
System.out.println ();
}
} // end class