Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

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