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>();
40  playerCount =0;
41  }
42 
48  Board(int N, int S) {
49  assert (N%2 != 0) : "Board's size has to be an odd number.";
50  assert (S <= (N*N-2)) : "At least 2 tiles has to be without supplies.";
51  this.N = Session.boardSize = N;
52  this.S = S;
53  this.W = 0;
54  tiles = new Tile[N*N];
55  supplies = new Supply[S];
56  walls = new ArrayList<Edge>();
58  playerCount =0;
59  }
60 
74  Board(Board b) {
75  // Copy primitives
76  this.N = b.N;
77  this.S = b.S;
78  this.W = b.W;
79  tiles = new Tile[b.tiles.length];
80  supplies = new Supply[b.supplies.length];
81  walls = new ArrayList<Edge>();
84 
85  // clone moves array of array of primitives
86  for (int i=0 ; i<b.moves.length ; ++i)
87  this.moves[i] = b.moves[i].clone();
88 
89  // Clone arrays of objects
90  for (int i=0 ; i<b.tiles.length ; ++i)
91  this.tiles[i] = new Tile(b.tiles[i]);
92  for (int i=0 ; i<b.supplies.length ; ++i)
93  this.supplies[i] = new Supply(b.supplies[i]);
94 
95  // clone vectors
96  for (Edge it: b.walls)
97  this.walls.add(new Edge(it));
98  }
110  void createBoard(int theseusTile, int minotaurTile) {
111  createTiles();
112  createSupplies(theseusTile, minotaurTile);
113  }
114 
129  String[][] getStringRepresentation(int theseusTile, int minotaurTile) {
130  String[][] frame = new String[2*N+1][N];
131 
132  for (int row=0 ; row<N ; ++row) {
133  int col;
134  for (col =0 ; col<N-1 ; ++col)
135  renderTile(frame, row, col, theseusTile, minotaurTile);
136  renderSentinelTile(frame, row, col, theseusTile, minotaurTile);
137  }
138  return frame;
139  }
140 
150  void printBoard (String[][] sBoard) {
151  for (int i=sBoard.length-1 ; i>=0 ; --i) {
152  for (String it : sBoard[i])
153  System.out.print(it);
154  System.out.println();
155  }
156  }
157 
171  boolean isWalkable(int tileId, int direction) {
172  return !tiles[tileId].hasWall(direction)
173  && !(tileId == 0 && direction == Direction.DOWN);
174  }
175 
190  boolean isWalkable(int row, int col, int direction) {
191  return !tiles[Position.toID(row, col)].hasWall(direction)
192  && !(Position.toID(row, col) == 0 && direction == Direction.DOWN);
193  }
194 
200  boolean hasSupply (int tileId) {
201  return (Const.noSupply != tiles[tileId].hasSupply(supplies)) ? true : false;
202  }
203 
213  int tryPickSupply(int tileId) {
214  int supplyId = tiles[tileId].hasSupply(supplies);
215  if (supplyId != Const.noSupply) {
216  tiles[tileId].pickSupply(supplies, supplyId);
217  }
218  return supplyId;
219  }
220 
221 
226  int dice () {
228  return d.get();
229  }
230 
232  int size () { return N; }
233 
238  int generatePlayerId () throws Exception {
240  return playerCount++;
241  else
242  throw new Exception("Maximum number of players exceeded");
243  }
244 
251  int getOpponentId(int playerId) {
252  return Const.numOfPlayers - (playerId +1);
253  }
254 
261  int[] getOpponentMove (int playerId) {
262  return moves[getOpponentId(playerId)];
263  }
264 
275  void updateMove(int[] m, int playerId) {
276  //moves.set(playerId, Arrays.stream(m).boxed().toArray(Integer[]::new));
277  moves[playerId] = m;
278  }
279 
288  int getN() { return N; }
289  int getS() { return S; }
290  int getW() { return W; }
296  Tile[] getTiles() { return tiles; }
302  Supply[] getSupplies() { return supplies; }
303 
309  ArrayList<Edge> getWalls() { return walls; }
310 
316  int[][] getMoves() { return moves; }
317 
318  void setN(int N) { this.N = N; }
319  void setS(int S) { this.S = S; }
320  void setW(int W) { this.W = W; }
321 
327  void setTiles(Tile[] tiles) { this.tiles = tiles; }
333  void setSupplies(Supply[] supplies) { this.supplies= supplies; }
334 
340  void setWalls (ArrayList<Edge> walls) { this.walls= walls; }
341 
347  void setMoves(int[][] moves) { this.moves =moves; }
348 
354  private boolean isLeftSentinel (int tileId) { return (Position.toCol(tileId) == 0); }
355  private boolean isRightSentinel (int tileId) { return (Position.toCol(tileId) == N-1); }
356  private boolean isUpSentinel (int tileId) { return (Position.toRow(tileId) == N-1); }
357  private boolean isDownSentinel (int tileId) { return (Position.toRow(tileId) == 0); }
368  private void createTiles() {
369  int wallCount;
370  wallCount = createBasicTileWalls (); // First create tiles with outer walls
371  wallCount += createInnerWalls(); // Greedy create as many inner walls we can
372  W = wallCount;
373  }
374 
383  private void createSupplies(int theseusTile, int minotaurTile) {
384  ShuffledRange rand = new ShuffledRange(0, N*N); // Make a shuffled range of all tiles
385  for (int tileId, i=0 ; i<supplies.length ; ++i) {
386  // Pick a tile as long as there is no player in it
387  do
388  tileId = rand.get();
389  while (tileId == theseusTile || tileId == minotaurTile);
390  supplies[i] = new Supply(i, tileId);
391  }
392  }
393 
405  private boolean isRoomCreator (int tileId, int direction) {
406  // Clone the list of all the walls locally.
407  ArrayList<Edge> w = new ArrayList<Edge>();
408  for (Edge it : walls)
409  w.add(new Edge(it));
410  // Create the largest possible coherent graph from the list of walls(edges)
411  Graph g = new Graph(new Edge(tileId, direction));
412  int size;
413  do {
414  size = w.size(); // mark the size (before the pass)
415  for (int i =0, S=w.size() ; i<S ; ++i) // for each edge(wall) on the local wall list
416  if (g.attach(w.get(i))) { // can we attach the edge(wall) to the graph ?
417  w.remove(i); // if yes remove it from the local wall list
418  --i; --S; // decrease iterator and size to match ArrayList's new values
419  }
420  } while (size != w.size()); // If the size hasn't change(no new graph leafs) exit
421 
422  // Search if a vertex is attached to the graph more than once.
423  // This means that there is at least 2 links to the same node
424  // so the graph has a closed loop
425  for (Edge it : walls) {
426  if (g.count(it.getV1()) > 1) return true;
427  if (g.count(it.getV2()) > 1) return true;
428  }
429  return false;
430  }
431 
450  private boolean isWallableDir (int tileId, int direction) {
451  // Check list
452  if (!isWalkable(tileId, direction))
453  return false;
454  switch (direction) {
455  case Direction.UP:
456  if (tiles[upTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
457  break;
458  case Direction.DOWN:
459  if (tiles[downTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
460  break;
461  case Direction.LEFT:
462  if (tiles[leftTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
463  break;
464  case Direction.RIGHT:
465  if (tiles[rightTileId.apply(tileId)].hasWalls() >= Const.maxTileWalls) return false;
466  break;
467  }
468  if (Session.loopGuard && isRoomCreator(tileId, direction))
469  return false;
470  return true;
471  }
472 
484  private boolean isWallable (int tileId) {
485  // Check list
486  if (tileId == Const.noTileId)
487  return false;
488  if (tiles[tileId].hasWalls() >= Const.maxTileWalls)
489  return false;
491  for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get())
492  if (isWallableDir(tileId, dir))
493  return true;
494  return false;
495  }
496 
497 
504  private int createBasicTileWalls () {
505  int wallCount =0;
506  for (int i =0 ; i< tiles.length ; ++i) {
507  boolean up = isUpSentinel(i);
508  boolean down = isDownSentinel(i) && (i != 0);
509  boolean left = isLeftSentinel(i);
510  boolean right = isRightSentinel(i);
511  wallCount += ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0));
512  tiles[i] = new Tile (i, up, down, left, right);
513  // If we have loopGuard enable we populate walls also.
514  if (Session.loopGuard) {
515  if (up) walls.add(new Edge(i, Direction.UP));
516  if (down) walls.add(new Edge(i, Direction.DOWN));
517  if (left) walls.add(new Edge(i, Direction.LEFT));
518  if (right) walls.add(new Edge(i, Direction.RIGHT));
519  }
520  }
521  return wallCount;
522  }
523 
528  private void createInnerWall(int tileId) {
529  // Randomly pick a wallable direction in that tile.
531  int dir;
532  do
533  dir = randDirections.get();
534  while (!isWallableDir(tileId, dir));
535  // Add wall to tileId and the adjacent tileId
536  Position neighbor = new Position(Position.toRow(tileId), Position.toCol(tileId), dir);
537  tiles[tileId].setWall(dir);
538  tiles[neighbor.getId()].setWall(Direction.opposite(dir));
539  // If we have loopGuard enable we populate walls also.
540  if (Session.loopGuard)
541  walls.add(new Edge(tileId, dir));
542  }
543 
549  private int createInnerWalls () {
550  ShuffledRange randTiles = new ShuffledRange(0, N*N);
551  for (int tileId, walls =0, shuffleMark =0 ; true ; ) {
552  // randomly pick a wallable tile.
553  do {
554  if ((tileId = randTiles.get())== Const.EOR) {
555  if (walls == shuffleMark) // Wallable tiles exhausted.
556  return walls;
557  else { // Re-shuffle and continue.
558  randTiles = new ShuffledRange(0, N*N);
559  shuffleMark =walls;
560  }
561  }
562  } while (!isWallable(tileId));
563  ++walls;
564  createInnerWall(tileId);
565  }
566  }
567 
577  private String getTileBody (int row, int col, int theseusTile, int minotaurTile) {
578  int tileId = Position.toID(row, col);
579  boolean T = (tileId == theseusTile) ? true : false;
580  boolean M = (tileId == minotaurTile) ? true : false;
581  int S = tiles[tileId].hasSupply(supplies);
582 
583  if (T && !M) return " T ";
584  else if (T && M) return "T+M";
585  else if (M) {
586  if (S == Const.noSupply) return " M ";
587  else return "M+s";
588  }
589  else if (S != Const.noSupply)
590  return String.format("s%02d", S+1);
591  else return " ";
592  }
593 
603  private void renderTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile) {
604  IntFunction<Integer> toframe = (r)->{ return 2*r+1; };
605 
606  int tileId = Position.toID(row, col);
607  frame[toframe.apply(row)+1][col] = tiles[tileId].hasWall(Direction.UP) ? "+---" : "+ ";
608  frame[toframe.apply(row) ][col] = (tiles[tileId].hasWall(Direction.LEFT)? "|" : " ")
609  + getTileBody(row, col, theseusTile, minotaurTile);
610  frame[toframe.apply(row)-1][col] = tiles[tileId].hasWall(Direction.DOWN) ? "+---" : "+ ";
611  }
612 
623  private void renderSentinelTile(String[][] frame, int row, int col, int theseusTile, int minotaurTile ) {
624  IntFunction<Integer> toframe = (r)->{ return 2*r+1; };
625 
626  int tileId = Position.toID(row, col);
627  frame[toframe.apply(row)+1][col] = tiles[tileId].hasWall(Direction.UP) ? "+---+" : "+ +";
628  frame[toframe.apply(row) ][col] = (tiles[tileId].hasWall(Direction.LEFT)? "|" : " ")
629  + getTileBody(row, col, theseusTile, minotaurTile)
630  + (tiles[tileId].hasWall(Direction.RIGHT)? "|" : " ");
631  frame[toframe.apply(row)-1][col] = tiles[tileId].hasWall(Direction.DOWN) ? "+---+" : "+ +";
632  }
637  private IntFunction<Integer> leftTileId = (id) -> { return Position.toID(Position.toRow(id), Position.toCol(id)-1); };
638  private IntFunction<Integer> rightTileId = (id) -> { return Position.toID(Position.toRow(id), Position.toCol(id)+1); };
639  private IntFunction<Integer> upTileId = (id) -> { return Position.toID(Position.toRow(id)+1, Position.toCol(id) ); };
640  private IntFunction<Integer> downTileId = (id) -> { return Position.toID(Position.toRow(id)-1, Position.toCol(id) ); };
645  private int N;
646  private int S;
647  private int W;
648  private Tile[] tiles;
649  private Supply[] supplies;
650  private ArrayList<Edge> walls;
654  private int[][] moves;
655  private int playerCount;
657 }
Board()
The empty constructor for default initialization.
Definition: Board.java:32
void setW(int W)
Definition: Board.java:320
This class is the representation of the supplies in the game.
Definition: Supply.java:23
boolean isWallable(int tileId)
Predicate to check if a tile is Wallable.
Definition: Board.java:484
IntFunction< Integer > upTileId
Definition: Board.java:639
static final int RIGHT
East direction.
Definition: Common.java:75
int hasWalls()
Checks if the tile has walls and return the number of them.
Definition: Tile.java:183
void createBoard(int theseusTile, int minotaurTile)
Creates the board with all the requested walls and supplies.
Definition: Board.java:110
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:623
This class is the representation of the games&#39;s board.
Definition: Board.java:25
Class to hold constant values for entire application.
Definition: Common.java:21
void pickSupply(Supply[] supplies, int supplyId)
Utility to find a supply in the supplies array and removes it.
Definition: Tile.java:204
Board(Board b)
Deep copy constructor.
Definition: Board.java:74
void setS(int S)
Definition: Board.java:319
int getOpponentId(int playerId)
Boards utility to give access to other player Id.
Definition: Board.java:251
int createBasicTileWalls()
This utility function create/allocate the tiles of the board and create the outer walls at the same t...
Definition: Board.java:504
void setSupplies(Supply[] supplies)
Definition: Board.java:333
int [][] getMoves()
Definition: Board.java:316
Helper C++-like enumerator class to hold direction.
Definition: Common.java:73
void createTiles()
This function creates randomly all the tiles of the board.
Definition: Board.java:368
int W
The number of walls on the board.
Definition: Board.java:647
static final int End
Iterator style end of range direction (one place after the last)
Definition: Common.java:65
boolean hasWall(int direction)
Checks if the tile has wall in the requested direction.
Definition: Tile.java:169
static final int Step
Step for iterator style direction.
Definition: Common.java:66
String [][] getStringRepresentation(int theseusTile, int minotaurTile)
Returns a 2-D array with the string representation of the board.
Definition: Board.java:129
Tile [] tiles
Array to hold all the tiles for the board.
Definition: Board.java:648
This class represents the game&#39;s player.
Definition: Player.java:21
IntFunction< Integer > rightTileId
Definition: Board.java:638
ArrayList< Edge > walls
Array to hold all the walls using the edge representation required by the closed room preventing algo...
Definition: Board.java:650
static final int numOfPlayers
Definition: Common.java:22
void setMoves(int[][] moves)
Definition: Board.java:347
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:577
int createInnerWalls()
This utility creates the inner walls of the board.
Definition: Board.java:549
static final int MOVE_DATA_SIZE
Helper variables to keep track of the move() return values.
Definition: Player.java:23
Tile [] getTiles()
Definition: Board.java:296
This class is the representation of the board&#39;s tile.
Definition: Tile.java:22
Provides a graph functionality for the room preventing algorithm.
Definition: Common.java:369
Helper C++ like enumerator class for direction ranged loops.
Definition: Common.java:63
Board(int N, int S)
The main constructor for the application.
Definition: Board.java:48
int getId()
Read access to id coordinate.
Definition: Common.java:154
int S
The number of the supplies on the board.
Definition: Board.java:646
int N
The size of each edge of the board.
Definition: Board.java:645
static int toRow(int id)
Takes Id coordinate and return the corresponding row coordinate.
Definition: Common.java:174
Supply [] supplies
Array to hold all the supplies on the board.
Definition: Board.java:649
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:603
boolean isRoomCreator(int tileId, int direction)
Predicate to check if a wall creates a closed room.
Definition: Board.java:405
boolean isWalkable(int row, int col, int direction)
Predicate to check if a direction is Walkable.
Definition: Board.java:190
ArrayList< Edge > getWalls()
Definition: Board.java:309
static final int EOR
Number to indicate the End Of Range.
Definition: Common.java:27
boolean isLeftSentinel(int tileId)
Definition: Board.java:354
static int toCol(int id)
Takes Id coordinate and return the corresponding column coordinate.
Definition: Common.java:182
IntFunction< Integer > leftTileId
Definition: Board.java:637
An Application wide board position implementation holding just the id coordinate. ...
Definition: Common.java:112
int hasSupply(Supply[] supplies)
Utility to check if the tile has a supply.
Definition: Tile.java:192
static final int maxTileWalls
Number of maximum walls for each tile on the board.
Definition: Common.java:23
static boolean loopGuard
When true a wall creation guard is added to prevent closed rooms inside the board.
Definition: Common.java:47
Supply [] getSupplies()
Definition: Board.java:302
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:401
boolean isUpSentinel(int tileId)
Definition: Board.java:356
void setWalls(ArrayList< Edge > walls)
Definition: Board.java:340
int generatePlayerId()
Utility function to create player IDs.
Definition: Board.java:238
boolean isWallableDir(int tileId, int direction)
Predicate to check if a tile direction is Wallable.
Definition: Board.java:450
void setWall(int direction)
Sets the tile&#39;s wall in the requested direction.
Definition: Tile.java:142
int dice()
A plain fair dice functionality provided by the board.
Definition: Board.java:226
static final int noSupply
Number to indicate the absent of supply.
Definition: Common.java:24
static int toID(int row, int col)
Takes row and column coordinates and return the calculated Id coordinate.
Definition: Common.java:165
void setTiles(Tile[] tiles)
Definition: Board.java:327
Application wide object to hold settings like values for the session.
Definition: Common.java:43
Class to create ranges of numbers.
Definition: Common.java:196
boolean hasSupply(int tileId)
Utility function to check if there is a supply on the tile or not.
Definition: Board.java:200
boolean isWalkable(int tileId, int direction)
Predicate to check if a direction is Walkable.
Definition: Board.java:171
static int boardSize
Default board&#39;s size (if no one set it via command line)
Definition: Common.java:44
static final int LEFT
West direction.
Definition: Common.java:77
static final int noTileId
Number to indicate wrong tileId.
Definition: Common.java:26
A utility class used for room prevent algorithm.
Definition: Common.java:306
int count(int v)
Counts the number of vertices on the graph with the value of v
Definition: Common.java:410
static final int UP
North direction.
Definition: Common.java:74
void updateMove(int[] m, int playerId)
Utility to update the moves of each player.
Definition: Board.java:275
static int opposite(int direction)
Utility to get the opposite direction.
Definition: Common.java:85
static final int DOWN
South direction.
Definition: Common.java:76
void createSupplies(int theseusTile, int minotaurTile)
This function create randomly the board&#39;s supplies.
Definition: Board.java:383
IntFunction< Integer > downTileId
Definition: Board.java:640
void createInnerWall(int tileId)
Create randomly a wall in the wallable selected tile.
Definition: Board.java:528
static final int Begin
Iterator style begin of range direction (starting north)
Definition: Common.java:64
void setN(int N)
Definition: Board.java:318
boolean isRightSentinel(int tileId)
Definition: Board.java:355
void printBoard(String[][] sBoard)
Print board utility.
Definition: Board.java:150
int [] getOpponentMove(int playerId)
Boards utility to give access to other player moves.
Definition: Board.java:261
int tryPickSupply(int tileId)
Try to pick supply from a tile.
Definition: Board.java:213
Class to create shuffled ranges of numbers.
Definition: Common.java:251
boolean isDownSentinel(int tileId)
Definition: Board.java:357
int get()
Extract and return the first item from the range.
Definition: Common.java:229