You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

416 lines
13 KiB

  1. /**
  2. * @file Common.java
  3. *
  4. * @author
  5. * Christos Choutouridis
  6. * <cchoutou@ece.auth.gr>
  7. * AEM:8997
  8. */
  9. package host.labyrinth;
  10. import java.util.ArrayList;
  11. import java.util.Collections;
  12. /**
  13. * Class to hold constant values for entire application
  14. */
  15. class Const {
  16. static final int maxTileWalls = 2; /**< Number of maximum walls for each tile on the board */
  17. static final int noSupply =-1; /**< Number to indicate the absent of supply */
  18. static final int noTileId =-1; /**< Number to indicate wrong tileId */
  19. static final int EOR =-1; /**< Number to indicate the End Of Range */
  20. }
  21. /**
  22. * Application wide object to hold settings like values for the session.
  23. */
  24. class Session {
  25. static int boardSize = 15; /**< Default board's size (if no one set it via command line) */
  26. static int supplySize = 4; /**< Default board's supply size (if no one set it via command line) */
  27. static int maxRounds = 100; /**< Default number of rounds per game (if no one set it via command line) */
  28. static boolean loopGuard = false; /**< When true a wall creation guard is added to prevent closed rooms inside the board */
  29. static boolean interactive = false; /**< When true each round of the game requires user input */
  30. }
  31. /**
  32. * Helper C++-like enumerator class to hold direction
  33. */
  34. class Direction {
  35. static final int UP =1; /**< North direction */
  36. static final int RIGHT =3; /**< East direction */
  37. static final int DOWN =5; /**< South direction */
  38. static final int LEFT =7; /**< West direction */
  39. /**
  40. * Utility to get the opposite direction.
  41. * @param direction Input direction
  42. * @return The opposite direction
  43. */
  44. static int opposite (int direction) { return (direction+4)%DirRange.End; }
  45. }
  46. /**
  47. * Helper C++ like enumerator class for direction ranged loops.
  48. *
  49. * We can make use of this in loops like:
  50. * <pre>
  51. * for (int i=DirRange.Begin ; i<DirRange.End ; i += DirRange.Step) { }
  52. *
  53. * or
  54. *
  55. * Range directions = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
  56. * </pre>
  57. */
  58. class DirRange {
  59. static final int Begin =1; /**< Iterator style begin of range direction (starting north) */
  60. static final int End =8; /**< Iterator style end of range direction (one place after the last) */
  61. static final int Step =2; /**< Step for iterator style direction */
  62. }
  63. /**
  64. * @brief
  65. * An Application wide board position implementation holding just the id coordinate.
  66. *
  67. * Position is a helper class to enable us cope with the redundant position data (id and coordinates).
  68. * This class provide both static conversion functionalities between id and coordinates
  69. * and data representation in the coordinates system.
  70. * For clarity we adopt a tileId convention.
  71. */
  72. class Position {
  73. /**
  74. * Basic constructor from row-column coordinates
  75. * @param row The row coordinate
  76. * @param col The column coordinate
  77. */
  78. Position(int row, int col) {
  79. this.id = toID(row, col);
  80. }
  81. /**
  82. * Basic constructor from Id
  83. * @param tileId The id of tile
  84. */
  85. Position(int tileId) {
  86. this.id = tileId;
  87. }
  88. /**
  89. * Constructor from row-column coordinates and a direction.
  90. *
  91. * This constructor creates a position relative to coordinates.
  92. *
  93. * @param row The row coordinate
  94. * @param col The column coordinate
  95. * @param direction The direction
  96. */
  97. Position(int row, int col, int direction) {
  98. switch (direction) {
  99. case Direction.UP: this.id = toID(row+1, col); break;
  100. case Direction.DOWN: this.id = toID(row-1, col); break;
  101. case Direction.LEFT: this.id = toID(row, col-1); break;
  102. case Direction.RIGHT:this.id = toID(row, col+1); break;
  103. }
  104. }
  105. /** @name non-static API */
  106. /** @{ */
  107. int getRow() { return toRow(id); } /**< Read access to virtual row coordinate */
  108. int getCol() { return toCol(id); } /**< Read access to virtual column coordinate */
  109. int getId() { return id; } /**< Read access to id coordinate */
  110. /** @} */
  111. /** @name Static convention utilities */
  112. /** @{ */
  113. /**
  114. * Takes row and column coordinates and return the calculated Id coordinate
  115. * @param row The row coordinate
  116. * @param col The column coordinate
  117. * @return The converted value
  118. */
  119. static int toID(int row, int col) {
  120. return row * Session.boardSize + col;
  121. }
  122. /**
  123. * Takes Id coordinate and return the corresponding row coordinate
  124. * @param id The id coordinate
  125. * @return The row coordinate
  126. */
  127. static int toRow(int id){
  128. return id / Session.boardSize;
  129. }
  130. /**
  131. * Takes Id coordinate and return the corresponding column coordinate
  132. * @param id The id coordinate
  133. * @return The column coordinate
  134. */
  135. static int toCol(int id) {
  136. return id % Session.boardSize;
  137. }
  138. /** @} */
  139. /** @name private data types */
  140. /** @{ */
  141. private int id; /**< The id coordinate of the constructed Position object */
  142. /** @} */
  143. }
  144. /**
  145. * Class to create ranges of numbers
  146. */
  147. class Range {
  148. /**
  149. * Create the range [begin, end)
  150. * @param begin The first item on the range
  151. * @param end The item after the last on the range
  152. */
  153. Range (int begin, int end) {
  154. numbers = new ArrayList<Integer>();
  155. init (begin, end, 1);
  156. }
  157. /**
  158. * Create the range [begin, end) using step as interval between items.
  159. * @param begin The first item on the range
  160. * @param end The item after the last on the range
  161. * @param step The interval between items
  162. */
  163. Range(int begin, int end, int step) {
  164. numbers = new ArrayList<Integer>();
  165. init (begin, end, step);
  166. }
  167. /**
  168. * Common utility to create the range for all constructors
  169. */
  170. private void init (int begin, int end, int step) {
  171. numbers.clear();
  172. for (int i=begin ; i<end ; i+=step)
  173. numbers.add(i);
  174. }
  175. /**
  176. * Extract and return the first item from the range.
  177. * @return The first item of the range or Const.noTileId if there is none.
  178. */
  179. int get () {
  180. if (!numbers.isEmpty())
  181. return numbers.remove(0);
  182. return Const.EOR;
  183. }
  184. /** @name protected data types */
  185. /** @{ */
  186. protected ArrayList<Integer> numbers; /**< handle to range */
  187. /** @} */
  188. }
  189. /**
  190. * Class to create shuffled ranges of numbers
  191. */
  192. class ShuffledRange extends Range {
  193. /**
  194. * Create a shuffled version of range [begin, end)
  195. * @param begin The first item on the range
  196. * @param end The item after the last on the range
  197. */
  198. ShuffledRange(int begin, int end) {
  199. super(begin, end); // Delegate
  200. Collections.shuffle(numbers);
  201. }
  202. /**
  203. * Create a shuffled version of the range [begin, end)
  204. * using step as interval between items.
  205. *
  206. * @param begin The first item on the range
  207. * @param end The item after the last on the range
  208. * @param step The interval between items
  209. */
  210. ShuffledRange(int begin, int end, int step) {
  211. super(begin, end, step); // Delegate
  212. Collections.shuffle(numbers);
  213. }
  214. }
  215. /**
  216. * @brief
  217. * A utility class used for room prevent algorithm.
  218. *
  219. * This class is the wall representation we use in the room preventing algorithm.
  220. * In this algorithm we represent the crosses between tiles as nodes (V) of a graph and the
  221. * walls as edges. So for example:
  222. * <pre>
  223. * 12--13--14---15
  224. * | |
  225. * 8 9--10 11
  226. * | | |
  227. * 4 5 6 7
  228. * | | |
  229. * 0 1---2---3
  230. * </pre>
  231. * In this example we have a 4x4=16 vertices board(nodes) and 14 edges(walls).
  232. * To represent the vertices on the board we use the same trick as the tileId
  233. *
  234. * V = Row*(N+1) + Column, where N is the board's tile size.
  235. *
  236. * The edges are represented as vertices pairs. For example (0, 4) or (13, 14).
  237. *
  238. * @note
  239. * Beside the fact that we prefer this kind of representation of the walls in
  240. * the application we use the one that is suggested from the assignment. This is
  241. * used only in room preventing algorithm.
  242. * @note
  243. * Using this kind of representation we don't have any more the "problem"
  244. * of setting the wall in both neighbor tiles.
  245. */
  246. class Edge {
  247. /**
  248. * This constructor acts as the interface between the application's wall
  249. * representation and the one based on graph.
  250. * @param tileId The tile id of the wall.
  251. * @param direction The direction of the tile where the wall should be.
  252. */
  253. Edge(int tileId, int direction) {
  254. int N = Session.boardSize +1;
  255. switch (direction) {
  256. case Direction.UP:
  257. v1= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
  258. v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) + 1;
  259. break;
  260. case Direction.DOWN:
  261. v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
  262. v2= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
  263. break;
  264. case Direction.LEFT:
  265. v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
  266. v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
  267. break;
  268. case Direction.RIGHT:
  269. v1= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
  270. v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) +1;
  271. break;
  272. }
  273. }
  274. /** A deep copy contructor */
  275. Edge(Edge e) {
  276. v1 = e.getV1();
  277. v2 = e.getV2();
  278. }
  279. /** Access of the first node of the edge */
  280. int getV1() { return v1; }
  281. /** Access of the second node of the edge */
  282. int getV2() { return v2; }
  283. private int v1; /**< First vertex of the edge */
  284. private int v2; /**< Second vertex of the edge */
  285. }
  286. /**
  287. * @brief
  288. * Provides a graph functionality for the room preventing algorithm.
  289. * We use a graph to represent the wall structure of the walls. This way
  290. * its easy to find any closed loops. Using graph we transform the problem
  291. * of the closed room into the problem of finding a non simple graph.
  292. *
  293. * If the board has non connected wall structure then we would need a non
  294. * coherent graph to represent it. This class provides constroctors and
  295. * methods to create coherent graphs
  296. *
  297. * An example of the biggest coherent graph we can create from the board bellow,
  298. * starting from V=1 is:
  299. * <pre>
  300. * 6---7 8 (1)
  301. * | | / \
  302. * 3 4 5 (4) (2)
  303. * | | | \
  304. * 0 1---2 (5)--(8)
  305. * </pre>
  306. */
  307. class Graph {
  308. /**
  309. * Constructs a node of the graph using the value of a vertex(node).
  310. * @param v The verteg to attach.
  311. */
  312. Graph (int v) {
  313. V = v;
  314. E = new ArrayList<Graph>();
  315. }
  316. /**
  317. * Constructor that transform an edge into graph.
  318. * @param e The edge to transform.
  319. */
  320. Graph (Edge e) {
  321. V = e.getV1();
  322. E = new ArrayList<Graph>();
  323. E.add(new Graph(e.getV2()));
  324. }
  325. /** Access to the current vertex */
  326. int getV() { return V; }
  327. /** Access to the links of the current vertex */
  328. ArrayList<Graph> getE() { return E; }
  329. /**
  330. * Attach an edge into a graph IFF the graph already has a vertex
  331. * with the same value as one of the vertices of the edge.
  332. * @param e The edge to attach.
  333. * @return The status of the operation.
  334. * @arg True on success
  335. * @arg False on failure
  336. */
  337. boolean attach (Edge e) {
  338. return tryAttach(e, 0) > 0;
  339. }
  340. /**
  341. * Counts the number of vertices on the graph with the value of `v`
  342. * @param v The vertex to count
  343. * @return The number of vertices with value `v`
  344. */
  345. int count (int v) {
  346. return tryCount (v, 0);
  347. }
  348. /**
  349. * Recursive algorithm that tries to attach an edge into a graph
  350. * IFF the graph already has a vertex with the same value as one
  351. * of the vertices of the edge.
  352. *
  353. * @param e The edge to attach.
  354. * @param count An initial count value to feed the algorithm.
  355. * @return The status of the operation.
  356. * @arg True on success
  357. * @arg False on failure
  358. */
  359. private int tryAttach (Edge e, int count) {
  360. for (Graph n: E)
  361. count = n.tryAttach (e, count);
  362. if (V == e.getV1()) {
  363. E.add(new Graph(e.getV2()));
  364. ++count;
  365. }
  366. if (V == e.getV2()) {
  367. E.add(new Graph(e.getV1()));
  368. ++count;
  369. }
  370. return count;
  371. }
  372. /**
  373. * Recursive algorithm that tries to count the number of vertices
  374. * on the graph with the same value as `v`.
  375. *
  376. * @param v The vertex to count
  377. * @param count An initial count value to feed to the algorithm.
  378. * @return The number of vertices with value `v`
  379. */
  380. private int tryCount (int v, int count) {
  381. for (Graph n: E)
  382. count = n.tryCount (v, count);
  383. if (V == v)
  384. return ++count;
  385. return count;
  386. }
  387. private int V; /**< The value of the current vertex/node */
  388. private ArrayList<Graph> E; /**< A list of all the child nodes */
  389. }