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.

390 lines
12 KiB

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