Labyrinth
A labyrinth game assignment
Board.java
Go to the documentation of this file.
1 
13 package host.labyrinth;
14 
15 import java.util.ArrayList;
16 import java.util.function.IntFunction;
17 
25 class Board {
32  Board() {
33  this.N = 0;
34  this.S = 0;
35  this.W = 0;
36  tiles = null;
37  supplies =null;
38  walls = new ArrayList<Edge>();
39  }
40 
46  Board(int N, int S) {
47  assert (N%2 != 0) : "Board's size has to be an odd number.";
48  assert (S <= (N*N-2)) : "At least 2 tiles has to be without supplies.";
49  this.N = Session.boardSize = N;
50  this.S = S;
51  this.W = 0;
52  tiles = new Tile[N*N];
53  supplies = new Supply[S];
54  walls = new ArrayList<Edge>();
55  }
56 
70  Board(Board b) {
71  // Copy primitives
72  this.N = b.N;
73  this.S = b.S;
74  this.W = b.W;
75  // Clone arrays
76  this.tiles = b.tiles.clone();
77  this.supplies = b.supplies.clone();
78  this.walls = b.walls;
79  }
91  void createBoard(int theseusTile, int minotaurTile) {
92  createTiles();
93  createSupplies(theseusTile, minotaurTile);
94  }
95 
110  String[][] getStringRepresentation(int theseusTile, int minotaurTile) {
111  String[][] frame = new String[2*N+1][N];
112 
113  for (int row=0 ; row<N ; ++row) {
114  int col;
115  for (col =0 ; col<N-1 ; ++col)
116  renderTile(frame, row, col, theseusTile, minotaurTile);
117  renderSentinelTile(frame, row, col, theseusTile, minotaurTile);
118  }
119  return frame;
120  }
121 
131  void printBoard (String[][] sBoard) {
132  for (int i=sBoard.length-1 ; i>=0 ; --i) {
133  for (String it : sBoard[i])
134  System.out.print(it);
135  System.out.println();
136  }
137  }
138 
152  boolean isWalkable(int tileId, int direction) {
153  return !tiles[tileId].hasWall(direction)
154  && !(tileId == 0 && direction == Direction.DOWN);
155  }
156 
171  boolean isWalkable(int row, int col, int direction) {
172  return !tiles[Position.toID(row, col)].hasWall(direction)
173  && !(Position.toID(row, col) == 0 && direction == Direction.DOWN);
174  }
175 
185  int tryPickSupply(int tileId) {
186  int supplyId = tiles[tileId].hasSupply(supplies);
187  if (supplyId != Const.noSupply) {
188  tiles[tileId].pickSupply(supplies, supplyId);
189  }
190  return supplyId;
191  }
192 
197  int dice () {
199  return d.get();
200  }
201 
203  int size () { return N; }
212  int getN() { return N; }
213  int getS() { return S; }
214  int getW() { return W; }
220  Tile[] getTiles() { return tiles; }
226  Supply[] getSupplies() { return supplies; }
227 
233  ArrayList<Edge> getWalls() { return walls; }
234 
235  void setN(int N) { this.N = N; }
236  void setS(int S) { this.S = S; }
237  void setW(int W) { this.W = W; }
238 
244  void setTiles(Tile[] tiles) { this.tiles = tiles; }
250  void setSupplies(Supply[] supplies) { this.supplies= supplies; }
251 
257  void setWalls (ArrayList<Edge> walls) { this.walls= walls; }
258 
264  private boolean isLeftSentinel (int tileId) { return (Position.toCol(tileId) == 0); }
265  private boolean isRightSentinel (int tileId) { return (Position.toCol(tileId) == N-1); }
266  private boolean isUpSentinel (int tileId) { return (Position.toRow(tileId) == N-1); }
267  private boolean isDownSentinel (int tileId) { return (Position.toRow(tileId) == 0); }
278  private void createTiles() {
279  int wallCount;
280  wallCount = createBasicTileWalls (); // First create tiles with outer walls
281  wallCount += createInnerWalls(); // Greedy create as many inner walls we can
282  W = wallCount;
283  }
284 
293  private void createSupplies(int theseusTile, int minotaurTile) {
294  ShuffledRange rand = new ShuffledRange(0, N*N); // Make a shuffled range of all tiles
295  for (int tileId, i=0 ; i<supplies.length ; ++i) {
296  // Pick a tile as long as there is no player in it
297  do
298  tileId = rand.get();
299  while (tileId == theseusTile || tileId == minotaurTile);
300  supplies[i] = new Supply(i, tileId);
301  }
302  }
303 
315  private boolean isRoomCreator (int tileId, int direction) {
316  // Clone the list of all the walls locally.
317  ArrayList<Edge> w = new ArrayList<Edge>();
318  for (Edge it : walls)
319  w.add(new Edge(it));
320  // Create the largest possible coherent graph from the list of walls(edges)
321  Graph g = new Graph(new Edge(tileId, direction));
322  int size;
323  do {
324  size = w.size(); // mark the size (before the pass)
325  for (int i =0, S=w.size() ; i<S ; ++i) // for each edge(wall) on the local wall list
326  if (g.attach(w.get(i))) { // can we attach the edge(wall) to the graph ?
327  w.remove(i); // if yes remove it from the local wall list
328  --i; --S; // decrease iterator and size to match ArrayList's new values
329  }
330  } while (size != w.size()); // If the size hasn't change(no new graph leafs) exit
331 
332  // Search if a vertex is attached to the graph more than once.
333  // This means that there is at least 2 links to the same node
334  // so the graph has a closed loop
335  for (Edge it : walls) {
336  if (g.count(it.getV1()) > 1) return true;
337  if (g.count(it.getV2()) > 1) return true;
338  }
339  return false;
340  }
341 
360  private boolean isWallableDir (int tileId, int direction) {
361  // Check list
362  if (!isWalkable(tileId, direction))
363  return false;
364  switch (direction) {
365  case Direction.UP:
366  if (tiles[upTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
367  break;
368  case Direction.DOWN:
369  if (tiles[downTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
370  break;
371  case Direction.LEFT:
372  if (tiles[leftTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
373  break;
374  case Direction.RIGHT:
375  if (tiles[rightTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
376  break;
377  }
378  if (Session.loopGuard && isRoomCreator(tileId, direction))
379  return false;
380  return true;
381  }
382 
394  private boolean isWallable (int tileId) {
395  // Check list
396  if (tileId == Const.noTileId)
397  return false;
398  if (tiles[tileId].hasWalls() >= Const.maxTileWalls)
399  return false;
401  for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get())
402  if (isWallableDir(tileId, dir))
403  return true;
404  return false;
405  }
406 
407 
414  private int createBasicTileWalls () {
415  int wallCount =0;
416  for (int i =0 ; i< tiles.length ; ++i) {
417  boolean up = isUpSentinel(i);
418  boolean down = isDownSentinel(i) && (i != 0);
419  boolean left = isLeftSentinel(i);
420  boolean right = isRightSentinel(i);
421  wallCount += ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0));
422  tiles[i] = new Tile (i, up, down, left, right);
423  // If we have loopGuard enable we populate walls also.
424  if (Session.loopGuard) {
425  if (up) walls.add(new Edge(i, Direction.UP));
426  if (down) walls.add(new Edge(i, Direction.DOWN));
427  if (left) walls.add(new Edge(i, Direction.LEFT));
428  if (right) walls.add(new Edge(i, Direction.RIGHT));
429  }
430  }
431  return wallCount;
432  }
433 
438  private void createInnerWall(int tileId) {
439  // Randomly pick a wallable direction in that tile.
441  int dir;
442  do
443  dir = randDirections.get();
444  while (!isWallableDir(tileId, dir));
445  // Add wall to tileId and the adjacent tileId
446  Position neighbor = new Position(Position.toRow(tileId), Position.toCol(tileId), dir);
447  tiles[tileId].setWall(dir);
448  tiles[neighbor.getId()].setWall(Direction.opposite(dir));
449  // If we have loopGuard enable we populate walls also.
450  if (Session.loopGuard)
451  walls.add(new Edge(tileId, dir));
452  }
453 
459  private int createInnerWalls () {
460  ShuffledRange randTiles = new ShuffledRange(0, N*N);
461  for (int tileId, i =0, walls =0, shuffleMark =0 ; true ; ) {
462  // randomly pick a wallable tile.
463  do {
464  if ((tileId = randTiles.get())== Const.EOR) {
465  if (i == shuffleMark) // Wallable tiles exhausted.
466  return walls;
467  else { // Re-shuffle and continue.
468  randTiles = new ShuffledRange(0, N*N);
469  shuffleMark =i;
470  }
471  }
472  } while (!isWallable(tileId));
473  ++walls;
474  createInnerWall(tileId);
475  }
476  }
477 
487  private String getTileBody (int row, int col, int theseusTile, int minotaurTile) {
488  int tileId = Position.toID(row, col);
489  boolean T = (tileId == theseusTile) ? true : false;
490  boolean M = (tileId == minotaurTile) ? true : false;
491  int S = tiles[tileId].hasSupply(supplies);
492 
493  if (T && !M) return " T ";
494  else if (T && M) return "T+M";
495  else if (M) {
496  if (S == Const.noSupply) return " M ";
497  else return "M+s";
498  }
499  else if (S != Const.noSupply)
500  return String.format("s%02d", S+1);
501  else return " ";
502  }
503 
513  private void renderTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile) {
514  IntFunction<Integer> toframe = (r)->{ return 2*r+1; };
515 
516  int tileId = Position.toID(row, col);
517  frame[toframe.apply(row)+1][col] = tiles[tileId].hasWall(Direction.UP) ? "+---" : "+ ";
518  frame[toframe.apply(row) ][col] = (tiles[tileId].hasWall(Direction.LEFT)? "|" : " ")
519  + getTileBody(row, col, theseusTile, minotaurTile);
520  frame[toframe.apply(row)-1][col] = tiles[tileId].hasWall(Direction.DOWN) ? "+---" : "+ ";
521  }
522 
533  private void renderSentinelTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile ) {
534  IntFunction<Integer> toframe = (r)->{ return 2*r+1; };
535 
536  int tileId = Position.toID(row, col);
537  frame[toframe.apply(row)+1][col] = tiles[tileId].hasWall(Direction.UP) ? "+---+" : "+ +";
538  frame[toframe.apply(row) ][col] = (tiles[tileId].hasWall(Direction.LEFT)? "|" : " ")
539  + getTileBody(row, col, theseusTile, minotaurTile)
540  + (tiles[tileId].hasWall(Direction.RIGHT)? "|" : " ");
541  frame[toframe.apply(row)-1][col] = tiles[tileId].hasWall(Direction.DOWN) ? "+---+" : "+ +";
542  }
547  private IntFunction<Integer> leftTileId = (id) -> { return Position.toID(Position.toRow(id), Position.toCol(id)-1); };
548  private IntFunction<Integer> rightTileId = (id) -> { return Position.toID(Position.toRow(id), Position.toCol(id)+1); };
549  private IntFunction<Integer> upTileId = (id) -> { return Position.toID(Position.toRow(id)+1, Position.toCol(id) ); };
550  private IntFunction<Integer> downTileId = (id) -> { return Position.toID(Position.toRow(id)-1, Position.toCol(id) ); };
555  private int N;
556  private int S;
557  private int W;
558  private Tile[] tiles;
559  private Supply[] supplies;
560  private ArrayList<Edge> walls;
565 }
host.labyrinth.DirRange.Step
static final int Step
Step for iterator style direction.
Definition: Common.java:69
host.labyrinth.Position.toCol
static int toCol(int id)
Takes Id coordinate and return the corresponding column coordinate.
Definition: Common.java:150
host.labyrinth.Direction.LEFT
static final int LEFT
West direction.
Definition: Common.java:44
host.labyrinth.Const
Class to hold constant values for entire application.
Definition: Common.java:20
host.labyrinth.Tile.pickSupply
void pickSupply(Supply[] supplies, int supplyId)
Utility to find a supply in the supplies array and removes it.
Definition: Tile.java:204
host.labyrinth.Board.createInnerWall
void createInnerWall(int tileId)
Create randomly a wall in the wallable selected tile.
Definition: Board.java:438
host.labyrinth.Board.createInnerWalls
int createInnerWalls()
This utility creates the inner walls of the board.
Definition: Board.java:459
host.labyrinth.Board.leftTileId
IntFunction< Integer > leftTileId
Definition: Board.java:547
host.labyrinth.Board.isUpSentinel
boolean isUpSentinel(int tileId)
Definition: Board.java:266
host.labyrinth.Tile.hasWall
boolean hasWall(int direction)
Checks if the tile has wall in the requested direction.
Definition: Tile.java:169
host.labyrinth.Board.getStringRepresentation
String[][] getStringRepresentation(int theseusTile, int minotaurTile)
Returns a 2-D array with the string representation of the board.
Definition: Board.java:110
host.labyrinth.Board.setTiles
void setTiles(Tile[] tiles)
Definition: Board.java:244
host.labyrinth.Board.supplies
Supply[] supplies
Array to hold all the supplies on the board.
Definition: Board.java:559
host.labyrinth.Range.get
int get()
Extract and return the first item from the range.
Definition: Common.java:197
host.labyrinth.Board.setS
void setS(int S)
Definition: Board.java:236
host.labyrinth.Board.tryPickSupply
int tryPickSupply(int tileId)
Try to pick supply from a tile.
Definition: Board.java:185
host.labyrinth.Board.downTileId
IntFunction< Integer > downTileId
Definition: Board.java:550
host.labyrinth.Board.createBasicTileWalls
int createBasicTileWalls()
This utility function create/allocate the tiles of the board and create the outer walls at the same t...
Definition: Board.java:414
host.labyrinth.ShuffledRange
Class to create shuffled ranges of numbers.
Definition: Common.java:212
host.labyrinth.Board.setW
void setW(int W)
Definition: Board.java:237
host.labyrinth.Supply
This class is the representation of the supplies in the game.
Definition: Supply.java:23
host.labyrinth.Board.renderSentinelTile
void renderSentinelTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile)
Utility to render the 3 strings of the tile in the representation frame in the case the tile lies in ...
Definition: Board.java:533
host.labyrinth.Board.S
int S
The number of the supplies on the board.
Definition: Board.java:556
host.labyrinth.Board.walls
ArrayList< Edge > walls
Array to hold all the walls using the edge representation required by the closed room preventing algo...
Definition: Board.java:560
host.labyrinth.Board.W
int W
The number of walls on the board.
Definition: Board.java:557
host.labyrinth.Session
Application wide object to hold settings like values for the session.
Definition: Common.java:29
host.labyrinth.Board.upTileId
IntFunction< Integer > upTileId
Definition: Board.java:549
host.labyrinth.Graph.attach
boolean attach(Edge e)
Attach an edge into a graph IFF the graph already has a vertex with the same value as one of the vert...
Definition: Common.java:362
host.labyrinth.Direction.DOWN
static final int DOWN
South direction.
Definition: Common.java:43
host.labyrinth.Board.createBoard
void createBoard(int theseusTile, int minotaurTile)
Creates the board with all the requested walls and supplies.
Definition: Board.java:91
host.labyrinth.Tile.hasSupply
int hasSupply(Supply[] supplies)
Utility to check if the tile has a supply.
Definition: Tile.java:192
host.labyrinth.Board.Board
Board(int N, int S)
The main constructor for the application.
Definition: Board.java:46
host.labyrinth.Board.createTiles
void createTiles()
This function creates randomly all the tiles of the board.
Definition: Board.java:278
host.labyrinth.Direction.RIGHT
static final int RIGHT
East direction.
Definition: Common.java:42
host.labyrinth.Board.size
int size()
Definition: Board.java:203
host.labyrinth.Board.setSupplies
void setSupplies(Supply[] supplies)
Definition: Board.java:250
host.labyrinth.Graph.count
int count(int v)
Counts the number of vertices on the graph with the value of v
Definition: Common.java:371
host.labyrinth.Board.dice
int dice()
A plain fair dice functionality provided by the board.
Definition: Board.java:197
host.labyrinth.Board.getS
int getS()
Definition: Board.java:213
host.labyrinth.Board.isLeftSentinel
boolean isLeftSentinel(int tileId)
Definition: Board.java:264
host.labyrinth.Board.renderTile
void renderTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile)
Utility to render the 3 strings of the tile in the representation frame.
Definition: Board.java:513
host.labyrinth.Board.setN
void setN(int N)
Definition: Board.java:235
host.labyrinth.Tile.hasWalls
int hasWalls()
Checks if the tile has walls and return the number of them.
Definition: Tile.java:183
host.labyrinth.Direction.UP
static final int UP
North direction.
Definition: Common.java:41
host.labyrinth.Board.createSupplies
void createSupplies(int theseusTile, int minotaurTile)
This function create randomly the board's supplies.
Definition: Board.java:293
host.labyrinth.Tile
This class is the representation of the board's tile.
Definition: Tile.java:22
host.labyrinth.Session.boardSize
static int boardSize
Default board's size (if no one set it via command line)
Definition: Common.java:30
host.labyrinth.Position.toRow
static int toRow(int id)
Takes Id coordinate and return the corresponding row coordinate.
Definition: Common.java:142
host.labyrinth.Board.getWalls
ArrayList< Edge > getWalls()
Definition: Board.java:233
host.labyrinth.Tile.setWall
void setWall(int direction)
Sets the tile's wall in the requested direction.
Definition: Tile.java:142
host.labyrinth.Board.isWalkable
boolean isWalkable(int tileId, int direction)
Predicate to check if a direction is Walkable.
Definition: Board.java:152
host.labyrinth.Position
An Application wide board position implementation holding just the id coordinate.
Definition: Common.java:81
host.labyrinth.DirRange
Helper C++ like enumerator class for direction ranged loops.
Definition: Common.java:66
host.labyrinth.Board.getSupplies
Supply[] getSupplies()
Definition: Board.java:226
host.labyrinth.Board
This class is the representation of the games's board.
Definition: Board.java:25
host.labyrinth.Board.isWallable
boolean isWallable(int tileId)
Predicate to check if a tile is Wallable.
Definition: Board.java:394
host.labyrinth.Edge
A utility class used for room prevent algorithm.
Definition: Common.java:267
host.labyrinth.DirRange.Begin
static final int Begin
Iterator style begin of range direction (starting north)
Definition: Common.java:67
host.labyrinth.DirRange.End
static final int End
Iterator style end of range direction (one place after the last)
Definition: Common.java:68
host.labyrinth.Board.isWallableDir
boolean isWallableDir(int tileId, int direction)
Predicate to check if a tile direction is Wallable.
Definition: Board.java:360
host.labyrinth.Board.isRightSentinel
boolean isRightSentinel(int tileId)
Definition: Board.java:265
host.labyrinth.Board.N
int N
The size of each edge of the board.
Definition: Board.java:555
host.labyrinth.Board.Board
Board(Board b)
Deep copy constructor.
Definition: Board.java:70
host.labyrinth.Direction
Helper C++-like enumerator class to hold direction.
Definition: Common.java:40
host.labyrinth.Const.noTileId
static final int noTileId
Number to indicate wrong tileId.
Definition: Common.java:23
host.labyrinth.Board.getTileBody
String getTileBody(int row, int col, int theseusTile, int minotaurTile)
Utility to get the body (center line) of the string representation of the tile.
Definition: Board.java:487
host.labyrinth.Board.setWalls
void setWalls(ArrayList< Edge > walls)
Definition: Board.java:257
host.labyrinth.Board.Board
Board()
The empty constructor for default initialization.
Definition: Board.java:32
host.labyrinth.Board.isDownSentinel
boolean isDownSentinel(int tileId)
Definition: Board.java:267
host.labyrinth.Range
Class to create ranges of numbers.
Definition: Common.java:164
host.labyrinth.Const.noSupply
static final int noSupply
Number to indicate the absent of supply.
Definition: Common.java:22
host.labyrinth.Direction.opposite
static int opposite(int direction)
Utility to get the opposite direction.
Definition: Common.java:51
host.labyrinth.Position.getId
int getId()
Read access to id coordinate.
Definition: Common.java:122
host.labyrinth.Board.isRoomCreator
boolean isRoomCreator(int tileId, int direction)
Predicate to check if a wall creates a closed room.
Definition: Board.java:315
host.labyrinth.Const.EOR
static final int EOR
Number to indicate the End Of Range.
Definition: Common.java:24
host.labyrinth.Graph
Provides a graph functionality for the room preventing algorithm.
Definition: Common.java:330
host.labyrinth.Session.loopGuard
static boolean loopGuard
When true a wall creation guard is added to prevent closed rooms inside the board.
Definition: Common.java:33
host.labyrinth.Board.getN
int getN()
Definition: Board.java:212
host.labyrinth.Board.printBoard
void printBoard(String[][] sBoard)
Print board utility.
Definition: Board.java:131
host.labyrinth.Board.getTiles
Tile[] getTiles()
Definition: Board.java:220
host.labyrinth.Board.tiles
Tile[] tiles
Array to hold all the tiles for the board.
Definition: Board.java:558
host.labyrinth.Board.rightTileId
IntFunction< Integer > rightTileId
Definition: Board.java:548
host.labyrinth.Position.toID
static int toID(int row, int col)
Takes row and column coordinates and return the calculated Id coordinate.
Definition: Common.java:133
host.labyrinth.Board.isWalkable
boolean isWalkable(int row, int col, int direction)
Predicate to check if a direction is Walkable.
Definition: Board.java:171
host.labyrinth.Const.maxTileWalls
static final int maxTileWalls
Number of maximum walls for each tile on the board.
Definition: Common.java:21
host.labyrinth.Board.getW
int getW()
Definition: Board.java:214