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.

419 lines
13 KiB

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