WIP: Report part 1
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* @file Common.java
|
||||
*
|
||||
* @author
|
||||
* Christos Choutouridis
|
||||
* <cchoutou@ece.auth.gr>
|
||||
* AEM:8997
|
||||
*/
|
||||
package host.labyrinth;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Class to hold constant values for entire application
|
||||
*/
|
||||
class Const {
|
||||
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 noTileId =-1; /**< Number to indicate wrong tileId */
|
||||
}
|
||||
/**
|
||||
* 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 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 */
|
||||
|
||||
/**
|
||||
* Utility to get the opposite direction.
|
||||
* @param direction Input direction
|
||||
* @return The opposite direction
|
||||
*/
|
||||
static int opposite (int direction) { return (direction+4)%DirRange.End; }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
/** @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.noTileId;
|
||||
}
|
||||
|
||||
/** @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 more than
|
||||
* one graph to represent it.
|
||||
*
|
||||
* An example 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 verteg 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 */
|
||||
}
|
||||
Reference in New Issue
Block a user