Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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