Compare commits

..

3 Commits

5 changed files with 380 additions and 86 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
bin/ bin/
doc/ doc/
out/
deliverable/ deliverable/
.classpath .classpath
.project .project

View File

@ -7,6 +7,7 @@
package net.hoo2.auth.labyrinth; package net.hoo2.auth.labyrinth;
import java.util.ArrayList;
import java.util.function.IntFunction; import java.util.function.IntFunction;
/** /**
@ -24,26 +25,27 @@ class Board {
* The empty constructor for default initialization * The empty constructor for default initialization
*/ */
Board() { Board() {
this.N = this.S = this.W = 0; this.N = 0;
this.tiles = null; this.S = 0;
this.supplies =null; this.W = 0;
tiles = null;
supplies =null;
walls = new ArrayList<Edge>();
} }
/** /**
* The main constructor for the application * The main constructor for the application
* @param N The size of each edge of the board * @param N The size of each edge of the board
* @param S The number of supplies on the board * @param S The number of supplies on the board
* @param W The number of walls on the board
*/ */
Board(int N, int S, int W) { Board(int N, int S) {
assert (W>= 4*N-1 && W<=(3*N*N+1)/2 ) assert (N%2 != 0) : "Board's size has to be an odd number.";
: "Boards walls has to be in the range [4N-1, (3N^2+1)/2]";
this.N = Session.boardSize = N; this.N = Session.boardSize = N;
this.S = S; this.S = S;
this.W = W; this.W = 0;
tiles = new Tile[N*N]; tiles = new Tile[N*N];
supplies = new Supply[S]; supplies = new Supply[S];
walls = new ArrayList<Edge>();
} }
/** /**
@ -67,6 +69,7 @@ class Board {
// Clone arrays // Clone arrays
this.tiles = b.tiles.clone(); this.tiles = b.tiles.clone();
this.supplies = b.supplies.clone(); this.supplies = b.supplies.clone();
this.walls = b.walls;
} }
/** @} */ /** @} */
@ -79,7 +82,7 @@ class Board {
* @param theseusTile * @param theseusTile
* @param minotaurTile * @param minotaurTile
*/ */
void createBoard(int theseusTile, int minotaurTile) throws Exception { void createBoard(int theseusTile, int minotaurTile) {
createTiles(); createTiles();
createSupplies(theseusTile, minotaurTile); createSupplies(theseusTile, minotaurTile);
} }
@ -220,6 +223,15 @@ class Board {
void setSupplies(Supply[] supplies) { this.supplies= supplies; } void setSupplies(Supply[] supplies) { this.supplies= supplies; }
/** @} */ /** @} */
/** @name Sentinel predicates */
/** @{ */
private boolean isLeftSentinel (int tileId) { return (Position.toCol(tileId) == 0); }
private boolean isRightSentinel (int tileId) { return (Position.toCol(tileId) == N-1); }
private boolean isUpSentinel (int tileId) { return (Position.toRow(tileId) == N-1); }
private boolean isDownSentinel (int tileId) { return (Position.toRow(tileId) == 0); }
/** @} */
/** /**
* @name private functionality of the object * @name private functionality of the object
*/ */
@ -228,11 +240,11 @@ class Board {
/** /**
* This function creates randomly all the tiles of the board * This function creates randomly all the tiles of the board
*/ */
private void createTiles() throws Exception { private void createTiles() {
int wallPool = W; int wallCount;
wallPool -= createBasicTileWalls (); // First create tiles with outer walls wallCount = createBasicTileWalls (); // First create tiles with outer walls
if (createInnerWalls(wallPool) > 0) // Create inner walls with the rest of the requested walls wallCount += createInnerWalls(); // Greedy create as many inner walls we can
throw new Exception("Can not create the requested number of walls"); W = wallCount;
} }
/** /**
@ -254,13 +266,43 @@ class Board {
} }
} }
/** @name Sentinel predicates */ /**
/** @{ */ * Predicate to check if a wall creates a closed room.
private boolean isLeftSentinel (int tileId) { return (Position.toCol(tileId) == 0); } *
private boolean isRightSentinel (int tileId) { return (Position.toCol(tileId) == N-1); } * This algorithm has a complexity of O(N^2) where N represents the total
private boolean isUpSentinel (int tileId) { return (Position.toRow(tileId) == N-1); } * number of tiles it should be used with care.
private boolean isDownSentinel (int tileId) { return (Position.toRow(tileId) == 0); } *
/** @} */ * @param tileId The tileId of the wall where the wall is.
* @param direction The wall's relative direction from the tile.
* @return True if the wall creates a closed room, false otherwise.
*/
private boolean createsClosedRoom (int tileId, int direction) {
// Get a snapshot of the current walls
ArrayList<Edge> w = new ArrayList<Edge>();
for (Edge it : walls)
w.add(new Edge(it));
// Create a graph from the current wall(edge)
// and populate the graph with all the edges we can attach.
Graph g = new Graph(new Edge(tileId, direction));
int size;
do {
size = w.size();
for (int i =0, S=w.size() ; i<S ; ++i)
if (g.attach(w.get(i))) {
w.remove(i);
--i; --S;
}
} while (size != w.size());
// Search if a vertex is attached more than once.
// This means that there is at least 2 links to the same node
// so the graph has a closed loop
for (Edge it : walls) {
if (g.count(it.getV1()) > 1) return true;
if (g.count(it.getV2()) > 1) return true;
}
return false;
}
/** /**
* Predicate to check if a tile direction is `Wallable`. * Predicate to check if a tile direction is `Wallable`.
@ -270,6 +312,7 @@ class Board {
* <li>The wall is not the DOWN wall from tile (0, 0). * <li>The wall is not the DOWN wall from tile (0, 0).
* <li>There is not already a wall in the desired direction. (Implies no sentinel tile). * <li>There is not already a wall in the desired direction. (Implies no sentinel tile).
* <li>The neighbor in this direction has at most `Const.maxTileWalls -1` walls. * <li>The neighbor in this direction has at most `Const.maxTileWalls -1` walls.
* <li>The wall does not create a closed room (Optional requirement).
* </ul> * </ul>
* *
* @note * @note
@ -286,12 +329,22 @@ class Board {
if (tiles[tileId].hasWall(direction)) if (tiles[tileId].hasWall(direction))
return false; return false;
switch (direction) { switch (direction) {
case Direction.UP: return (tiles[upTileId.apply(tileId)].hasWalls() < Const.maxTileWalls); case Direction.UP:
case Direction.DOWN: return (tiles[downTileId.apply(tileId)].hasWalls() < Const.maxTileWalls); if (tiles[upTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
case Direction.LEFT: return (tiles[leftTileId.apply(tileId)].hasWalls() < Const.maxTileWalls); break;
case Direction.RIGHT:return (tiles[rightTileId.apply(tileId)].hasWalls() < Const.maxTileWalls); case Direction.DOWN:
if (tiles[downTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
break;
case Direction.LEFT:
if (tiles[leftTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
break;
case Direction.RIGHT:
if (tiles[rightTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
break;
} }
return false; if (Session.loopGuard && createsClosedRoom(tileId, direction))
return false;
return true;
} }
/** /**
@ -326,16 +379,22 @@ class Board {
* @return The number of walls created from the utility. * @return The number of walls created from the utility.
*/ */
private int createBasicTileWalls () { private int createBasicTileWalls () {
int tileCount =0; int wallCount =0;
for (int i =0 ; i< tiles.length ; ++i) { for (int i =0 ; i< tiles.length ; ++i) {
boolean up = isUpSentinel(i); boolean up = isUpSentinel(i);
boolean down = isDownSentinel(i) && (i != 0); boolean down = isDownSentinel(i) && (i != 0);
boolean left = isLeftSentinel(i); boolean left = isLeftSentinel(i);
boolean right = isRightSentinel(i); boolean right = isRightSentinel(i);
tileCount += ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0)); wallCount += ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0));
tiles[i] = new Tile (i, up, down, left, right); tiles[i] = new Tile (i, up, down, left, right);
if (Session.loopGuard) {
if (up) walls.add(new Edge(i, Direction.UP));
if (down) walls.add(new Edge(i, Direction.DOWN));
if (left) walls.add(new Edge(i, Direction.LEFT));
if (right) walls.add(new Edge(i, Direction.RIGHT));
}
} }
return tileCount; return wallCount;
} }
/** /**
@ -352,6 +411,8 @@ class Board {
Position neighbor = new Position(Position.toRow(tileId), Position.toCol(tileId), dir); Position neighbor = new Position(Position.toRow(tileId), Position.toCol(tileId), dir);
tiles[tileId].setWall(dir); tiles[tileId].setWall(dir);
tiles[neighbor.getId()].setWall(Direction.opposite(dir)); tiles[neighbor.getId()].setWall(Direction.opposite(dir));
if (Session.loopGuard)
walls.add(new Edge(tileId, dir));
} }
/** /**
@ -360,23 +421,23 @@ class Board {
* @param walls The number of walls to create * @param walls The number of walls to create
* @return The number of walls failed to create. * @return The number of walls failed to create.
*/ */
private int createInnerWalls (int walls) { private int createInnerWalls () {
ShuffledRange randTiles = new ShuffledRange(0, N*N); ShuffledRange randTiles = new ShuffledRange(0, N*N);
for (int tileId, i =0, shuffleMark =0 ; i<walls ; ++i) { for (int tileId, i =0, walls =0, shuffleMark =0 ; true ; ) {
// randomly pick a wallable tile. // randomly pick a wallable tile.
do { do {
if ((tileId = randTiles.get())== Const.noTileId) { if ((tileId = randTiles.get())== Const.noTileId) {
if (i == shuffleMark) // Wallable tiles exhausted. if (i == shuffleMark) // Wallable tiles exhausted.
return walls - i; return walls;
else { // Re-shuffle and continue. else { // Re-shuffle and continue.
randTiles = new ShuffledRange(0, N*N); randTiles = new ShuffledRange(0, N*N);
shuffleMark =i; shuffleMark =i;
} }
} }
} while (!isWallable(tileId)); } while (!isWallable(tileId));
++walls;
createInnerWall(tileId); createInnerWall(tileId);
} }
return 0;
} }
/** /**
@ -395,8 +456,11 @@ class Board {
int S = tiles[tileId].hasSupply(supplies); int S = tiles[tileId].hasSupply(supplies);
if (T && !M) return " T "; if (T && !M) return " T ";
else if (M && !T) return " M ";
else if (T && M) return "T+M"; else if (T && M) return "T+M";
else if (M) {
if (S == Const.noSupply) return " M ";
else return "M+s";
}
else if (S != Const.noSupply) else if (S != Const.noSupply)
return String.format("s%02d", S+1); return String.format("s%02d", S+1);
else return " "; else return " ";
@ -453,10 +517,14 @@ class Board {
/** @name Class data */ /** @name Class data */
/** @{ */ /** @{ */
private int N; /**< The size of each edge of the board */ private int N; /**< The size of each edge of the board */
private int S; /**< The number of the supplies on the board */ private int S; /**< The number of the supplies on the board */
private int W; /**< The number of walls on the board */ private int W; /**< The number of walls on the board */
private Tile[] tiles; /**< Array to hold all the tiles for the board */ private Tile[] tiles; /**< Array to hold all the tiles for the board */
private Supply[] supplies; /**< Array to hold all the supplies on the board */ private Supply[] supplies; /**< Array to hold all the supplies on the board */
private ArrayList<Edge> walls; /**<
* Array to hold all the walls using the edge representation
* required by the closed room preventing algorithm.
*/
/** @} */ /** @} */
} }

View File

@ -21,9 +21,11 @@ class Const {
* Application wide object to hold settings like values for the session. * Application wide object to hold settings like values for the session.
*/ */
class Session { class Session {
static int boardSize = 15; /**< Default board's size (if no one set it via command line) */ static int boardSize = 15; /**< Default board's size (if no one set it via command line) */
static int supplySize = 4; /**< Default board's supply size (if no one set it via command line) */ static int supplySize = 4; /**< Default board's supply size (if no one set it via command line) */
static int wallSize = 4*15-1; /**< Default board's wall size (if no one set it via command line) */ static int maxRounds = 100; /**< Default number of rounds per game (if no one set it via command line) */
static boolean loopGuard = false; /**< When true a wall creation guard is added to prevent closed rooms inside the board */
static boolean interactive = false; /**< When true each round of the game requires user input */
} }
/** /**
@ -172,12 +174,9 @@ class Range {
* @return The first item of the range or Const.noTileId if there is none. * @return The first item of the range or Const.noTileId if there is none.
*/ */
int get () { int get () {
try { if (!numbers.isEmpty())
return numbers.remove(0); return numbers.remove(0);
} return Const.noTileId;
catch (IndexOutOfBoundsException e) {
return Const.noTileId;
}
} }
/** @name protected data types */ /** @name protected data types */
@ -212,3 +211,179 @@ class ShuffledRange extends Range {
Collections.shuffle(numbers); Collections.shuffle(numbers);
} }
} }
/**
* @brief
* A utility class used for room prevent algorithm.
*
* This class is the wall representation we use in the room preventing algorithm.
* In this algorithm we represent the crosses between tiles as nodes (V) of a graph and the
* walls as edges. So for example:
*
* _ V = 15
* /
* +---+---+---+ We have a 4x4=16 vertices board(nodes) and 14 edges(walls).
* | | To represent the vertices on the board we use the
* + +---+ + same trick as the tileId.
* | | | The edges are represented as vertices pairs.
* + + + + <.
* | | | \_ V = 7
* + +---+---+
* ^ ^
* V = 0 V = 3
*
* @note
* Beside the fact that we prefer this kind of representation of the walls in
* the application we use the one that is suggested from the assignment. This is
* used only in room preventing algorithm.
* @note
* Using this kind of representation we don't have any more the "problem"
* of setting the wall in both neighbor tiles.
*/
class Edge {
/**
* This constructor as as the interface between the application's wall
* representation and the one based on graph.
* @param tileId The tile id of the wall.
* @param direction The direction of the tile where the wall should be.
*/
Edge(int tileId, int direction) {
int N = Session.boardSize +1;
switch (direction) {
case Direction.UP:
v1= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) + 1;
break;
case Direction.DOWN:
v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
v2= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
break;
case Direction.LEFT:
v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
break;
case Direction.RIGHT:
v1= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) +1;
break;
}
}
/** A deep copy contructor */
Edge(Edge e) {
v1 = e.getV1();
v2 = e.getV2();
}
/** Access of the first node of the edge */
int getV1() { return v1; }
/** Access of the second node of the edge */
int getV2() { return v2; }
private int v1; /**< First vertex of the edge */
private int v2; /**< Second vertex of the edge */
}
/**
* @brief
* Provides a graph functionality for the room preventing algorithm.
* We use a graph to represent the wall structure of the walls. This way
* is easy to find any closed loops. Using graph we transform the problem
* of the closed room in the problem of finding a non simple graph.
*
* If the board has non connected wall structure then we need more than
* one graph to represent it.
*
* An example graph from a board, starting from V=1 is:
* <pre>
* 6---7 8 (1)
* | | / \
* 3 4 5 (4) (2)
* | | | \
* 0 1---2 (5)--(8)
* </pre>
*/
class Graph {
/**
* Constructs a node of the graph using the value of a vertex(node).
* @param v The verteg to attach.
*/
Graph (int v) {
V = v;
E = new ArrayList<Graph>();
}
/**
* Constructor that transform an edge into graph.
* @param e The edge to transform.
*/
Graph (Edge e) {
V = e.getV1();
E = new ArrayList<Graph>();
E.add(new Graph(e.getV2()));
}
/** Access to the current vertex */
int getV() { return V; }
/** Access to the links of the current vertex */
ArrayList<Graph> getE() { return E; }
/**
* Attach an edge into a graph IFF the graph already has a vertex
* with the same value of one of the vertices of the edge.
* @param e The edge to attach.
* @return The status of the operation.
* @arg True on success
* @arg False on failure
*/
boolean attach (Edge e) {
return tryAttach(e, 0) > 0;
}
/**
* Counts the number of vertices on the graph with the value of `v`
* @param v The vertex to count
* @return The number of vertices with value `v`
*/
int count (int v) {
return tryCount (v, 0);
}
/**
* Recursive algorithm that tries to attach an edge into a graph
* IFF the graph already has a vertex.
* with the same value of one of the vertices of the edge.
* @param e The edge to attach.
* @param count An initial count value to feed to the algorithm.
* @return The status of the operation.
* @arg True on success
* @arg False on failure
*/
private int tryAttach (Edge e, int count) {
for (Graph n: E)
count += n.tryAttach (e, count);
if (V == e.getV1()) {
E.add(new Graph(e.getV2()));
++count;
}
if (V == e.getV2()) {
E.add(new Graph(e.getV1()));
++count;
}
return count;
}
/**
* Recursive algorithm that tries to count the number of vertices
* on the graph with the value of `v`
* @param v The vertex to count
* @param count An initial count value to feed to the algorithm.
* @return The number of vertices with value `v`
*/
private int tryCount (int v, int count) {
for (Graph n: E)
count = n.tryCount (v, count);
if (V == v)
return ++count;
return count;
}
private int V; /**< The value of the current vertex/node */
private ArrayList<Graph> E; /**< A list of all the child nodes */
}

View File

@ -7,17 +7,38 @@
package net.hoo2.auth.labyrinth; package net.hoo2.auth.labyrinth;
import java.util.Scanner;
/** /**
* Main application class. This class is the only public interface of * Main application class. This class is the only public interface of
* the entire game. * the entire game.
*/ */
public class Game { public class Game {
Game() {} /**< An empty constructor */ /**< An empty constructor */
Game() {
scan = new Scanner(System.in);
}
/** @name Player main application interface */
/** @{ */
/** Utility to get current round of the game */
int round () { return round; } int round () { return round; }
/** Utility to increase and get the increased round of the game */
int nextRound() { return ++round; } int nextRound() { return ++round; }
/**
* Utility to hold the execution of the program waiting for user input.
* This is true only if the user passed the interactive flag.
*/
void waitUser () {
if(Session.interactive) {
System.out.println("Press enter to continue...");
scan.nextLine();
}
}
/** @{ */
/** /**
* @name Accessor/Mutator interface * @name Accessor/Mutator interface
* @note * @note
@ -31,15 +52,14 @@ public class Game {
/** @name Game's data */ /** @name Game's data */
/** @{ */ /** @{ */
private int round; private int round; /**< Holds the round of the game */
private Scanner scan; /**< Input handle used in interactive mode */
/** @} */ /** @} */
/** /**
* Main game loop * Command line argument handler
*/ */
static boolean getArguments (String[] args) { static boolean getArguments (String[] args) {
boolean ret = true;
for (int i =0 ; i<args.length ; ++i) { for (int i =0 ; i<args.length ; ++i) {
switch (args[i]) { switch (args[i]) {
case "-b": case "-b":
@ -48,59 +68,80 @@ public class Game {
Session.boardSize = Integer.parseInt(args[++i]); Session.boardSize = Integer.parseInt(args[++i]);
break; break;
case "-w":
case "--walls":
if (i+1 < args.length)
Session.wallSize = Integer.parseInt(args[++i]);
break;
case "-s": case "-s":
case "--suplies": case "--suplies":
if (i+1 < args.length) if (i+1 < args.length)
Session.supplySize = Integer.parseInt(args[++i]); Session.supplySize = Integer.parseInt(args[++i]);
break; break;
case "-r":
case "--rounds":
if (i+1 < args.length)
Session.maxRounds = Integer.parseInt(args[++i]);
break;
case "--norooms":
Session.loopGuard = true;
break;
case "-i":
case "--interactive":
Session.interactive = true;
break;
default: default:
ret = false;
case "-h": case "-h":
case "--help": case "--help":
System.out.println("Labyrinth Game"); System.out.println("Labyrinth Game");
System.out.println(""); System.out.println("");
System.out.println("Usage:"); System.out.println("Usage:");
System.out.println("labyrinth [-b|--board <Num>] [-w|--walls <Num>] [-s|--supplies <Num>]"); System.out.println("labyrinth [-b|--board <Num>] [-s|--supplies <Num>] [-r|--rounds <Num>] [--norooms] [-i|--interactive]");
System.out.println("or"); System.out.println("or");
System.out.println("labyrinth -h|--help"); System.out.println("labyrinth -h|--help");
System.out.println(""); System.out.println("\nOptions\n");
System.out.println("\t-b | --board: Sets the size of board's edge."); System.out.println("-b | --board:\n Sets the size of board's edge.\n");
System.out.println("\t-w | --walls: Sets the number of walls on the board."); System.out.println("-s | --supplies:\n Sets the number of supplies on the board.\n");
System.out.println("\t-s | --supplies: Sets the number of supplies on the board."); System.out.println("-r | --rounds:\n Sets the maximum number of rounds of the game.\n");
System.out.println("\t-h | --help: Print this and exit"); System.out.println("--norooms:\n Prevents the creation of closed rooms inside the board.\n");
break; System.out.println("-i | --interactive:\n Each round requires user input in order to continue.\n");
System.out.println("-h | --help:\n Print this and exits.");
return false;
} }
} }
return ret; return true;
} }
/**
* Main game loop
*/
public static void main(String[] args) { public static void main(String[] args) {
try { try {
// Get command line options // Get command line options
Game.getArguments(args); if (!Game.getArguments(args)) throw new Exception("");
// Create a game, a board and 2 players. // Create a game, a board and 2 players.
Game game = new Game(); Game game = new Game();
Board board = new Board(Session.boardSize, Session.supplySize, Session.wallSize); Board board = new Board(Session.boardSize, Session.supplySize);
Player T = new Player(1, "Theseus", board, 0); Player T = new Player(1, "Theseus", true, board, 0);
Player M = new Player(2, "Minotaur", board, Position.toID(Session.boardSize/2, Session.boardSize/2)); Player M = new Player(2, "Minotaur", false, board, Position.toID(Session.boardSize/2, Session.boardSize/2));
// Populate data to the board // Populate data to the board
board.createBoard(T.playerTileId(), M.playerTileId()); board.createBoard(T.playerTileId(), M.playerTileId());
// The game // Initial board printout
System.out.println("Initial board: " + (game.round()));
board.printBoard(
board.getStringRepresentation(T.playerTileId(), M.playerTileId())
);
game.waitUser ();
// Main game loop
while (true) { while (true) {
int[] m; int[] m;
System.out.println(); System.out.println();
System.out.println("Round: " + (game.round()+1)); System.out.println("State after round: " + (game.round()+1));
// Player moves
m = T.move(T.playerTileId()); m = T.move(T.playerTileId());
System.out.println(T.getName() + ":\t tileId =" + m[0] + " (" + m[1] + ", " + m[2] + ")"); System.out.println(T.getName() + ":\t tileId =" + m[0] + " (" + m[1] + ", " + m[2] + ")");
m = M.move(M.playerTileId()); m = M.move(M.playerTileId());
@ -109,7 +150,7 @@ public class Game {
board.getStringRepresentation(T.playerTileId(), M.playerTileId()) board.getStringRepresentation(T.playerTileId(), M.playerTileId())
); );
// Termination cases // Loop termination cases
if (T.getScore() == 4) { if (T.getScore() == 4) {
System.out.println(T.getName() + " Wins!!! Score =" + T.getScore()); System.out.println(T.getName() + " Wins!!! Score =" + T.getScore());
System.exit(0); System.exit(0);
@ -118,13 +159,15 @@ public class Game {
System.out.println(M.getName() + " Wins!!! Score =" + M.getScore()); System.out.println(M.getName() + " Wins!!! Score =" + M.getScore());
System.exit(0); System.exit(0);
} }
if (!(game.nextRound() < 100)) { if (!(game.nextRound() < Session.maxRounds)) {
System.out.println("New day has come... Tie!!!"); System.out.println("New day has come... Tie!!!");
System.exit(0); System.exit(0);
} }
game.waitUser ();
} }
} }
catch (Exception e) { catch (Exception e) {
// We don't handle exceptions. Print error and exit with error status.
System.out.println(e.getMessage()); System.out.println(e.getMessage());
System.exit(1); System.exit(1);
} }

View File

@ -6,7 +6,7 @@ package net.hoo2.auth.labyrinth;
* This class represents the game's player * This class represents the game's player
*/ */
class Player { class Player {
/** @name Contructors */ /** @name Constructors */
/** @{ */ /** @{ */
/** /**
@ -15,13 +15,14 @@ class Player {
* @param name The name of the player * @param name The name of the player
* @param board Reference to the board of the game * @param board Reference to the board of the game
*/ */
Player(int id, String name, Board board, int row, int column) { Player(int id, String name, boolean champion, Board board, int row, int column) {
this.playerId = id; this.playerId = id;
this.name = name; this.name = name;
this.board = board; this.board = board;
this.score = 0; this.score = 0;
this.x = column; this.x = column;
this.y = row; this.y = row;
this.champion = champion;
} }
/** /**
@ -30,13 +31,14 @@ class Player {
* @param name The name of the player * @param name The name of the player
* @param board Reference to the board of the game * @param board Reference to the board of the game
*/ */
Player(int id, String name, Board board, int tileId) { Player(int id, String name, boolean champion, Board board, int tileId) {
this.playerId = id; this.playerId = id;
this.name = name; this.name = name;
this.board = board; this.board = board;
this.score = 0; this.score = 0;
this.x = Position.toCol(tileId); this.x = Position.toCol(tileId);
this.y = Position.toRow(tileId); this.y = Position.toRow(tileId);
this.champion = champion;
} }
/** @} */ /** @} */
@ -46,9 +48,9 @@ class Player {
/** /**
* Player's move. * Player's move.
* *
* A player first throw a dice to get a random direction. Then checks if the direction * A player first throws a dice to get a random direction. Then checks if the direction
* is walkable. If it is, then goes to that tile, pick up a possible supply on the tile * is walkable. If it is, then goes to that tile and update player's data.
* and update player's data. * If the player is a champion then he also picks up a possible supply from the tile.
* *
* @param id The id of the starting tile. * @param id The id of the starting tile.
* @return An array containing player's final position and possible supply of that position. * @return An array containing player's final position and possible supply of that position.
@ -61,7 +63,7 @@ class Player {
* </ul> * </ul>
*/ */
int[] move(int id) { int[] move(int id) {
// Init return array with the current data // Initialize return array with the current data
int[] ret = {id, Position.toRow(id), Position.toCol(id), Const.noSupply}; int[] ret = {id, Position.toRow(id), Position.toCol(id), Const.noSupply};
int diceDirection = board.dice(); // throw the dice int diceDirection = board.dice(); // throw the dice
@ -71,8 +73,9 @@ class Player {
ret[0] = next.getId(); // Update player's and return data ret[0] = next.getId(); // Update player's and return data
ret[1] = y = next.getRow(); ret[1] = y = next.getRow();
ret[2] = x = next.getCol(); ret[2] = x = next.getCol();
if ((ret[3] = board.tryPickSupply(next.getId())) != Const.noSupply) { // In case of a champion player, try also to pick a supply
++score; // keep score if (champion && (ret[3] = board.tryPickSupply(next.getId())) != Const.noSupply) {
++score; // keep score
System.out.println(name + ":\t*Found a supply. [score: " + score + "]"); System.out.println(name + ":\t*Found a supply. [score: " + score + "]");
} }
} }
@ -81,8 +84,11 @@ class Player {
return ret; return ret;
} }
/** Utility to access player's tileID */
int playerTileId() { return Position.toID(y, x); } int playerTileId() { return Position.toID(y, x); }
/** Utility to access player's row position (row coordinate) */
int playerRow() { return y; } int playerRow() { return y; }
/** Utility to access player's column position (column coordinate) */
int playerCol() { return x; } int playerCol() { return x; }
/** @} */ /** @} */
@ -122,5 +128,6 @@ class Player {
private int score; /**< The current score of the player */ private int score; /**< The current score of the player */
private int x; /**< The column coordinate of the player on the board */ private int x; /**< The column coordinate of the player on the board */
private int y; /**< The row coordinate of the player on the board */ private int y; /**< The row coordinate of the player on the board */
private boolean champion; /**< Champion indicate a player who plays against the Minotaur */
/** @} */ /** @} */
} }