|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /**
- * @file Common.java
- *
- * @author
- * Anastasia Foti AEM:8959
- * <anastaskf@ece.auth.gr>
- *
- * @author
- * Christos Choutouridis AEM:8997
- * <cchoutou@ece.auth.gr>
- */
- package host.labyrinth;
-
- import java.util.ArrayList;
- import java.util.Collections;
- //import java.util.function.IntFunction;
-
- /**
- * Class to hold constant values for entire application
- */
- class Const {
- static final int numOfPlayers = 2;
- static final int maxTileWalls = 2; /**< Number of maximum walls for each tile on the board */
- static final int noSupply =-1; /**< Number to indicate the absent of supply */
- static final int noOpponent =-1; /**< Number to indicate the absent of supply */
- static final int noTileId =-1; /**< Number to indicate wrong tileId */
- static final int EOR =-1; /**< Number to indicate the End Of Range */
- static final int viewDistance =3; /**< The max distance of the Heuristic player's ability to see */
- static final int noView = viewDistance+1;
-
- /** Parameters to control move evaluation */
- /** @{ */
- static final double opponentFactor = 1.0; /**< opponent distance factor */
- static final double supplyFactor = 0.65; /**< supply distance factor */
- static final double preMoveFactor = 0.65; /**< pre move distances factor */
- static final double postMoveFactor = 0.35; /**< post move distances factor */
- static final int minimaxTreeDepth = 4; /**< The maximum depth of the minimax tree */
- /** @} */
- }
- /**
- * Application wide object to hold settings like values for the session.
- */
- class Session {
- static int boardSize = 15; /**< Default board's size (if no one set it via command line) */
- static int supplySize = 4; /**< Default board's supply size (if no one set it via command line) */
- static int maxRounds = 100; /**< Default number of rounds per game (if no one set it via command line) */
- static boolean loopGuard = false; /**< When true a wall creation guard is added to prevent closed rooms inside the board */
- static boolean interactive = false; /**< When true each round of the game requires user input */
- }
-
- /**
- * Helper C++ like enumerator class for direction ranged loops.
- *
- * We can make use of this in loops like:
- * <pre>
- * for (int i=DirRange.Begin ; i<DirRange.End ; i += DirRange.Step) { }
- *
- * or
- *
- * Range directions = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
- * </pre>
- */
- class DirRange {
- static final int Begin =1; /**< Iterator style begin of range direction (starting north) */
- static final int End =8; /**< Iterator style end of range direction (one place after the last) */
- static final int Step =2; /**< Step for iterator style direction */
- static final int numOfDirections =4;
- }
-
- /**
- * Helper C++-like enumerator class to hold direction
- */
- class Direction {
- static final int UP =1; /**< North direction */
- static final int RIGHT =3; /**< East direction */
- static final int DOWN =5; /**< South direction */
- static final int LEFT =7; /**< West direction */
- static final int NONE =8; /**< No direction */
-
- /**
- * Utility to get the opposite direction.
- * @param direction Input direction
- * @return The opposite direction
- */
- static int opposite (int direction) {
- return (direction != NONE) ? (direction+4)%DirRange.End : NONE;
- }
-
- static int get (int fromId, int toId) {
- if (Position.toID(Position.toRow(fromId), Position.toCol(fromId)-1) == toId)
- return Direction.LEFT;
- else if (Position.toID(Position.toRow(fromId), Position.toCol(fromId)+1) == toId)
- return Direction.RIGHT;
- else if (Position.toID(Position.toRow(fromId)+1, Position.toCol(fromId) ) == toId)
- return Direction.UP;
- else if (Position.toID(Position.toRow(fromId)-1, Position.toCol(fromId) ) == toId)
- return Direction.DOWN;
- else
- return DirRange.End;
- }
- }
-
- /**
- * @brief
- * An Application wide board position implementation holding just the id coordinate.
- *
- * Position is a helper class to enable us cope with the redundant position data (id and coordinates).
- * This class provide both static conversion functionalities between id and coordinates
- * and data representation in the coordinates system.
- * For clarity we adopt a tileId convention.
- */
- class Position {
-
- /**
- * Basic constructor from row-column coordinates
- * @param row The row coordinate
- * @param col The column coordinate
- */
- Position(int row, int col) {
- this.id = toID(row, col);
- }
-
- /**
- * Basic constructor from Id
- * @param tileId The id of tile
- */
- Position(int tileId) {
- this.id = tileId;
- }
-
- /**
- * Constructor from row-column coordinates and a direction.
- *
- * This constructor creates a position relative to coordinates.
- *
- * @param row The row coordinate
- * @param col The column coordinate
- * @param direction The direction
- */
- Position(int row, int col, int direction) {
- switch (direction) {
- case Direction.UP: this.id = toID(row+1, col); break;
- case Direction.DOWN: this.id = toID(row-1, col); break;
- case Direction.LEFT: this.id = toID(row, col-1); break;
- case Direction.RIGHT:this.id = toID(row, col+1); break;
- case Direction.NONE: this.id = toID(row, col); break;
- }
- }
-
- /** @name non-static API */
- /** @{ */
- int getRow() { return toRow(id); } /**< Read access to virtual row coordinate */
- int getCol() { return toCol(id); } /**< Read access to virtual column coordinate */
- int getId() { return id; } /**< Read access to id coordinate */
- /** @} */
-
- /** @name Static convention utilities */
- /** @{ */
- /**
- * Takes row and column coordinates and return the calculated Id coordinate
- * @param row The row coordinate
- * @param col The column coordinate
- * @return The converted value
- */
- static int toID(int row, int col) {
- return row * Session.boardSize + col;
- }
-
- /**
- * Takes Id coordinate and return the corresponding row coordinate
- * @param id The id coordinate
- * @return The row coordinate
- */
- static int toRow(int id){
- return id / Session.boardSize;
- }
- /**
- * Takes Id coordinate and return the corresponding column coordinate
- * @param id The id coordinate
- * @return The column coordinate
- */
- static int toCol(int id) {
- return id % Session.boardSize;
- }
- /** @} */
-
- /** @name private data types */
- /** @{ */
- private int id; /**< The id coordinate of the constructed Position object */
- /** @} */
- }
-
- /**
- * Class to create ranges of numbers
- */
- class Range {
- /**
- * Create the range [begin, end)
- * @param begin The first item on the range
- * @param end The item after the last on the range
- */
- Range (int begin, int end) {
- numbers = new ArrayList<Integer>();
- init (begin, end, 1);
- }
- /**
- * Create the range [begin, end) using step as interval between items.
- * @param begin The first item on the range
- * @param end The item after the last on the range
- * @param step The interval between items
- */
- Range(int begin, int end, int step) {
- numbers = new ArrayList<Integer>();
- init (begin, end, step);
- }
-
- /**
- * Common utility to create the range for all constructors
- */
- private void init (int begin, int end, int step) {
- numbers.clear();
- for (int i=begin ; i<end ; i+=step)
- numbers.add(i);
- }
- /**
- * Extract and return the first item from the range.
- * @return The first item of the range or Const.noTileId if there is none.
- */
- int get () {
- if (!numbers.isEmpty())
- return numbers.remove(0);
- return Const.EOR;
- }
-
- /**
- * @return The size of the underline structure
- */
- int size () {
- return numbers.size();
- }
-
- /** @name protected data types */
- /** @{ */
- protected ArrayList<Integer> numbers; /**< handle to range */
- /** @} */
- }
-
- /**
- * Class to create shuffled ranges of numbers
- */
- class ShuffledRange extends Range {
- /**
- * Create a shuffled version of range [begin, end)
- * @param begin The first item on the range
- * @param end The item after the last on the range
- */
- ShuffledRange(int begin, int end) {
- super(begin, end); // Delegate
- Collections.shuffle(numbers);
- }
- /**
- * Create a shuffled version of the range [begin, end)
- * using step as interval between items.
- *
- * @param begin The first item on the range
- * @param end The item after the last on the range
- * @param step The interval between items
- */
- ShuffledRange(int begin, int end, int step) {
- super(begin, end, step); // Delegate
- Collections.shuffle(numbers);
- }
- }
-
- /**
- * @brief
- * A utility class used for room prevent algorithm.
- *
- * This class is the wall representation we use in the room preventing algorithm.
- * In this algorithm we represent the crosses between tiles as nodes (V) of a graph and the
- * walls as edges. So for example:
- * <pre>
- * 12--13--14---15
- * | |
- * 8 9--10 11
- * | | |
- * 4 5 6 7
- * | | |
- * 0 1---2---3
- * </pre>
- * In this example we have a 4x4=16 vertices board(nodes) and 14 edges(walls).
- * To represent the vertices on the board we use the same trick as the tileId
- *
- * V = Row*(N+1) + Column, where N is the board's tile size.
- *
- * The edges are represented as vertices pairs. For example (0, 4) or (13, 14).
- *
- * @note
- * Beside the fact that we prefer this kind of representation of the walls in
- * the application we use the one that is suggested from the assignment. This is
- * used only in room preventing algorithm.
- * @note
- * Using this kind of representation we don't have any more the "problem"
- * of setting the wall in both neighbor tiles.
- */
- class Edge {
- /**
- * This constructor acts as the interface between the application's wall
- * representation and the one based on graph.
- * @param tileId The tile id of the wall.
- * @param direction The direction of the tile where the wall should be.
- */
- Edge(int tileId, int direction) {
- int N = Session.boardSize +1;
- switch (direction) {
- case Direction.UP:
- v1= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
- v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) + 1;
- break;
- case Direction.DOWN:
- v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
- v2= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
- break;
- case Direction.LEFT:
- v1= (Position.toRow(tileId))*N + Position.toCol(tileId);
- v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId);
- break;
- case Direction.RIGHT:
- v1= (Position.toRow(tileId))*N + Position.toCol(tileId) + 1;
- v2= (Position.toRow(tileId) + 1)*N + Position.toCol(tileId) +1;
- break;
- }
- }
- /** A deep copy contructor */
- Edge(Edge e) {
- v1 = e.getV1();
- v2 = e.getV2();
- }
- /** Access of the first node of the edge */
- int getV1() { return v1; }
- /** Access of the second node of the edge */
- int getV2() { return v2; }
-
- private int v1; /**< First vertex of the edge */
- private int v2; /**< Second vertex of the edge */
- }
-
- /**
- * @brief
- * Provides a graph functionality for the room preventing algorithm.
- * We use a graph to represent the wall structure of the walls. This way
- * its easy to find any closed loops. Using graph we transform the problem
- * of the closed room into the problem of finding a non simple graph.
- *
- * If the board has non connected wall structure then we would need a non
- * coherent graph to represent it. This class provides constructors and
- * methods to create coherent graphs
- *
- * An example of the biggest coherent graph we can create from the board bellow,
- * starting from V=1 is:
- * <pre>
- * 6---7 8 (1)
- * | | / \
- * 3 4 5 (4) (2)
- * | | | \
- * 0 1---2 (5)--(8)
- * </pre>
- */
- class Graph {
- /**
- * Constructs a node of the graph using the value of a vertex(node).
- * @param v The vertex to attach.
- */
- Graph (int v) {
- V = v;
- E = new ArrayList<Graph>();
- }
- /**
- * Constructor that transform an edge into graph.
- * @param e The edge to transform.
- */
- Graph (Edge e) {
- V = e.getV1();
- E = new ArrayList<Graph>();
- E.add(new Graph(e.getV2()));
- }
-
- /** Access to the current vertex */
- int getV() { return V; }
- /** Access to the links of the current vertex */
- ArrayList<Graph> getE() { return E; }
-
- /**
- * Attach an edge into a graph IFF the graph already has a vertex
- * with the same value as one of the vertices of the edge.
- * @param e The edge to attach.
- * @return The status of the operation.
- * @arg True on success
- * @arg False on failure
- */
- boolean attach (Edge e) {
- return tryAttach(e, 0) > 0;
- }
-
- /**
- * Counts the number of vertices on the graph with the value of `v`
- * @param v The vertex to count
- * @return The number of vertices with value `v`
- */
- int count (int v) {
- return tryCount (v, 0);
- }
-
- /**
- * Recursive algorithm that tries to attach an edge into a graph
- * IFF the graph already has a vertex with the same value as one
- * of the vertices of the edge.
- *
- * @param e The edge to attach.
- * @param count An initial count value to feed the algorithm.
- * @return The status of the operation.
- * @arg True on success
- * @arg False on failure
- */
- private int tryAttach (Edge e, int count) {
- for (Graph n: E)
- count = n.tryAttach (e, count);
- if (V == e.getV1()) {
- E.add(new Graph(e.getV2()));
- ++count;
- }
- if (V == e.getV2()) {
- E.add(new Graph(e.getV1()));
- ++count;
- }
- return count;
- }
-
- /**
- * Recursive algorithm that tries to count the number of vertices
- * on the graph with the same value as `v`.
- *
- * @param v The vertex to count
- * @param count An initial count value to feed to the algorithm.
- * @return The number of vertices with value `v`
- */
- private int tryCount (int v, int count) {
- for (Graph n: E)
- count = n.tryCount (v, count);
- if (V == v)
- return ++count;
- return count;
- }
-
- private int V; /**< The value of the current vertex/node */
- private ArrayList<Graph> E; /**< A list of all the child nodes */
- }
|