Labyrinth
A labyrinth game assignment
MinMaxPlayer.java
Go to the documentation of this file.
1 
13 package host.labyrinth;
14 
19 class MinMaxPlayer extends Player {
20 
32  public MinMaxPlayer(String name, boolean champion, Board board, int row, int column) throws Exception {
33  super(name, champion, board, row, column);
34  }
35 
43  public MinMaxPlayer(String name, boolean champion, Board board, int tileId) throws Exception {
44  super(name, champion, board, tileId);
45  }
58  int supplyInDirection(int currentPos, int direction, Board board) {
59  Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
60 
61  for (int i=0 ; i<=Const.viewDistance ; ++i) {
62  if (board.hasSupply(pos.getId()))
63  return i;
64  if (board.isWalkable(pos.getId(), direction))
65  pos = new Position(pos.getRow(), pos.getCol(), direction);
66  else
67  break;
68  }
69  return Const.noView;
70  }
71 
80  int opponetInDirection(int currentPos, int direction, Board board) {
81  Position pos = new Position(Position.toRow(currentPos), Position.toCol(currentPos));
82  int[] opp = board.getOpponentMove(playerId);
83 
84  for (int i=0 ; i<=Const.viewDistance ; ++i) {
85  if (opp[MOVE_TILE_ID] == pos.getId())
86  return i;
87  if (board.isWalkable(pos.getId(), direction))
88  pos = new Position(pos.getRow(), pos.getCol(), direction);
89  else
90  break;
91  }
92  return Const.noView;
93  }
94 
103  double evaluate (int currentPos, int direction, Board board) {
104  Position next = new Position (Position.toRow(currentPos), Position.toCol(currentPos), direction);
105 
106  int preOpDist = opponetInDirection (currentPos, direction, board);
107  int preSupDist = supplyInDirection(currentPos, direction, board);
108  int postOpDist = opponetInDirection (next.getId(), direction, board);
109  int postSupDist = supplyInDirection(next.getId(), direction, board);
110 
111  return ((preSupDist != Const.noView) ? Const.preMoveFactor *(1.0/(preSupDist+1) * Const.supplyFactor) : 0)
112  - ((preOpDist != Const.noView) ? Const.preMoveFactor *(1.0/(preOpDist+1) * Const.opponentFactor) : 0)
113  + ((postSupDist != Const.noView)? Const.postMoveFactor*(1.0/(preSupDist+1) * Const.supplyFactor) : 0)
114  - ((postOpDist != Const.noView) ? Const.postMoveFactor*(1.0/(preOpDist+1) * Const.opponentFactor) : 0);
115  }
116 
123  node.setNodeEvaluation(maxValue(node));
124  return node.getPath();
125  }
126 
135  int[] getNextMove(int currentPos) {
136  Node root = new Node (board);
137  int [] opp = board.getOpponentMove(playerId);
138 
139  createMySubtree(currentPos, opp[MOVE_TILE_ID], root, root.getNodeDepth()+1);
140 
141  return chooseMinMaxMove(root).getNodeMove();
142  }
143 
161  @Override
162  int[] move(int id) {
163  // Initialize return array with the current data
164  int[] ret = getNextMove(id);
165  y = Position.toRow(ret[MOVE_TILE_ID]);
166  x = Position.toCol(ret[MOVE_TILE_ID]);
167 
168  int supplyFlag =0, moveFlag =1;
169  // In case of a champion player, try also to pick a supply
170  if (champion && (board.tryPickSupply(ret[MOVE_TILE_ID]) != Const.noSupply)) {
171  ++score; // keep score
172  ++supplyFlag;
173  }
174  ++dirCounter[ret[MOVE_DICE]]; // update direction counters
175  board.updateMove(ret, playerId);
176 
177  // Update supply and opponent distance
178  int smin =Const.noView, omin =Const.noView;
179  for (int d = DirRange.Begin ; d<DirRange.End ; d += DirRange.Step) {
180  int s = supplyInDirection (ret[MOVE_TILE_ID], d, board);
181  int o = opponetInDirection(ret[MOVE_TILE_ID], d, board);
182  if (s < smin) smin = s;
183  if (o < omin) omin = o;
184  }
185  // update path
186  Integer[] p = {
187  ret[MOVE_TILE_ID], ret[MOVE_DICE], moveFlag, supplyFlag,
188  dirCounter[Direction.UP], dirCounter[Direction.RIGHT], dirCounter[Direction.DOWN], dirCounter[Direction.LEFT],
189  smin, omin
190  };
191  path.add(p);
192  return ret;
193  }
194 
198  void statistics() {
199  if (!path.isEmpty()) {
200  Integer[] last = path.get(path.size()-1);
201  String who = String.format("%12s", name);
202  System.out.print(who + ": score[" + score + "]" + ", dice =" + last[1] + ", tileId =" + last[0] + " (" + Position.toRow(last[0]) + ", " + Position.toCol(last[0]) + ")");
203  if (last[2] == 0)
204  System.out.println(" *Can not move.");
205  else if (last[3] != 0)
206  System.out.println(" *Found a supply.");
207  else
208  System.out.println("");
209  // extra prints for minimax player
210  if (last[8] != Const.noView) System.out.println(" supply =" + last[8]);
211  else System.out.println(" supply = blind");
212  if (last[9] != Const.noView) System.out.println(" opponent =" + last[9]);
213  else System.out.println(" opponent = blind");
214  }
215  }
216 
221  String who = String.format("%12s", name);
222  System.out.println();
223  System.out.println(who + ": score[" + score + "]");
224  System.out.println(" Moves up: " + dirCounter[Direction.UP]);
225  System.out.println(" Moves right: " + dirCounter[Direction.RIGHT]);
226  System.out.println(" Moves down: " + dirCounter[Direction.DOWN]);
227  System.out.println(" Moves left: " + dirCounter[Direction.LEFT]);
228  }
229 
240  private int prevDirection(Node parent) {
241  if (parent != null && parent.getParent() != null)
242  return parent.getParent().getNodeMove()[MOVE_DICE];
243  return Direction.NONE;
244  }
245 
255  private int[] dryMove (Board board, int currentPos, int dir, boolean champion) {
256  int[] ret = new int[MOVE_DATA_SIZE];
257  Position p = new Position(Position.toRow(currentPos), Position.toCol(currentPos), dir);
258  ret[MOVE_TILE_ID] = p.getId();
259  ret[MOVE_ROW] = p.getRow();
260  ret[MOVE_COLUMN] = p.getCol();
261  ret[MOVE_DICE] = dir;
262 
263  board.updateMove(ret, (champion) ? playerId : board.getOpponentId(playerId));
264  return ret;
265  }
266 
281  private void createMySubtree (int currentPos, int oppCurrentPos, Node parent, int depth) {
283  int [] nodeMove;
284 
285  for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get()) {
286  if ((dir != Direction.opposite(prevDirection(parent)))
287  && parent.getNodeBoard().isWalkable(currentPos, dir)) {
288  Board nodeBoard = new Board (parent.getNodeBoard()); // clone board
289  double eval = evaluate (currentPos, dir, nodeBoard); // evaluate the move
290  nodeMove = dryMove (nodeBoard, currentPos, dir, true); // simulate the move
291  // make child Node
292  Node child = new Node (parent, depth, nodeMove, nodeBoard, eval);
293  parent.addChild(child); // add child to tree
294  createOppSubtree (nodeMove[MOVE_TILE_ID], oppCurrentPos, child, depth+1);
295  }
296  }
297  }
298 
313  private void createOppSubtree (int currentPos, int oppCurrentPos, Node parent, int depth) {
315  int [] nodeMove;
316 
317  for (int dir = dirs.get() ; dir != Const.EOR ; dir = dirs.get()) {
318  if ((dir != Direction.opposite(prevDirection(parent)))
319  && parent.getNodeBoard().isWalkable(oppCurrentPos, dir)) {
320  Board nodeBoard = new Board(parent.getNodeBoard()); // clone board
321  nodeMove = dryMove (nodeBoard, oppCurrentPos, dir, false); // simulate move
322  Position init = new Position( // evaluate from "My" perspective the move
323  parent.getNodeMove()[MOVE_ROW],
324  parent.getNodeMove()[MOVE_COLUMN],
326  );
327  double eval = evaluate(init.getId(), parent.getNodeMove()[MOVE_DICE], nodeBoard);
328  // make child Node
329  Node child = new Node (parent, depth, nodeMove, nodeBoard, eval);
330  parent.addChild(child); // add child to tree
331  if (depth < Const.minimaxTreeDepth) {
332  createMySubtree (currentPos, nodeMove[MOVE_TILE_ID], child, depth+1);
333  }
334  }
335  }
336  }
337 
344  private double maxValue (Node node) {
345  if (node.getChildren() == null) {
346  //node.setPath(node);
347  return node.getNodeEvaluation();
348  }
349  else {
350  double M = Double.NEGATIVE_INFINITY;
351  for (Node n : node.getChildren()) {
352  n.setNodeEvaluation(minValue(n)); // evaluation propagation
353  if (M < n.getNodeEvaluation()) {
354  M = n.getNodeEvaluation();
355  node.setPath(n); // path propagation
356  }
357  }
358  return M;
359  }
360  }
361 
368  private double minValue (Node node) {
369  if (node.getChildren() == null) {
370  //node.setPath(node);
371  return node.getNodeEvaluation();
372  }
373  else {
374  double m = Double.POSITIVE_INFINITY;
375  for (Node n : node.getChildren()) {
376  n.setNodeEvaluation(maxValue(n)); // evaluation propagation
377  if (m > n.getNodeEvaluation()) {
378  m = n.getNodeEvaluation();
379  node.setPath(n); // path propagation
380  }
381  }
382  return m;
383  }
384  }
385 
388 }
static final int RIGHT
East direction.
Definition: Common.java:75
Node getPath()
get path
Definition: Node.java:64
static final int MOVE_DICE
The index of dice information.
Definition: Player.java:27
This class is the representation of the games&#39;s board.
Definition: Board.java:25
Class to hold constant values for entire application.
Definition: Common.java:21
static final double preMoveFactor
pre move distances factor
Definition: Common.java:35
void setPath(Node path)
set path
Definition: Node.java:89
int getOpponentId(int playerId)
Boards utility to give access to other player Id.
Definition: Board.java:251
ArrayList< Node > getChildren()
get children
Definition: Node.java:54
This class represents the game&#39;s minimax player.
Helper C++-like enumerator class to hold direction.
Definition: Common.java:73
boolean champion
Champion indicate a player who plays against the Minotaur.
Definition: Player.java:224
static final int End
Iterator style end of range direction (one place after the last)
Definition: Common.java:65
int [] getNextMove(int currentPos)
Selects the best possible move to return.
int x
The column coordinate of the player on the board.
Definition: Player.java:222
static final int minimaxTreeDepth
The maximum depth of the minimax tree.
Definition: Common.java:37
static final int Step
Step for iterator style direction.
Definition: Common.java:66
int [] dryMove(Board board, int currentPos, int dir, boolean champion)
A simulated move in a copy of the bard.
static final int MOVE_TILE_ID
Index of the tileId information of the move.
Definition: Player.java:24
This class represents the game&#39;s player.
Definition: Player.java:21
Board board
Reference to the session&#39;s boards.
Definition: Player.java:220
int [] getNodeMove()
get nodeMove
Definition: Node.java:58
void statistics()
Prints round information for the player.
Node chooseMinMaxMove(Node node)
Executes the minimax algorithm and return a reference to selected move.
int getNodeDepth()
get nodeDepth
Definition: Node.java:56
static final double postMoveFactor
post move distances factor
Definition: Common.java:36
static final double opponentFactor
Parameters to control move evaluation.
Definition: Common.java:33
double getNodeEvaluation()
get nodeEvluation
Definition: Node.java:62
static final int MOVE_DATA_SIZE
Helper variables to keep track of the move() return values.
Definition: Player.java:23
static final double supplyFactor
supply distance factor
Definition: Common.java:34
Helper C++ like enumerator class for direction ranged loops.
Definition: Common.java:63
void createOppSubtree(int currentPos, int oppCurrentPos, Node parent, int depth)
One of the 2 recursive functions for creating the minimax tree.
int getId()
Read access to id coordinate.
Definition: Common.java:154
static final int noView
Definition: Common.java:29
double maxValue(Node node)
The Minimax recursive function for the maximizing part.
static final int MOVE_ROW
The index of row information.
Definition: Player.java:25
static final int viewDistance
The max distance of the Heuristic player&#39;s ability to see.
Definition: Common.java:28
double minValue(Node node)
The Minimax recursive function for the minimizing part.
int getRow()
Read access to virtual row coordinate.
Definition: Common.java:152
int y
The row coordinate of the player on the board.
Definition: Player.java:223
int getCol()
Read access to virtual column coordinate.
Definition: Common.java:153
static int toRow(int id)
Takes Id coordinate and return the corresponding row coordinate.
Definition: Common.java:174
int score
The current score of the player.
Definition: Player.java:221
double evaluate(int currentPos, int direction, Board board)
This is the main move evaluation function.
void setNodeEvaluation(double nodeEvaluation)
set nodeEvaluation
Definition: Node.java:85
static final int EOR
Number to indicate the End Of Range.
Definition: Common.java:27
static int toCol(int id)
Takes Id coordinate and return the corresponding column coordinate.
Definition: Common.java:182
Node object for minimax tree.
Definition: Node.java:20
int supplyInDirection(int currentPos, int direction, Board board)
Utility to get the distance of a possible supply in some direction.
An Application wide board position implementation holding just the id coordinate. ...
Definition: Common.java:112
int opponetInDirection(int currentPos, int direction, Board board)
Utility to get the distance of a possible opponent in some direction.
int [] move(int id)
MinMaxPlayer&#39;s move.
static final int NONE
No direction.
Definition: Common.java:78
void createMySubtree(int currentPos, int oppCurrentPos, Node parent, int depth)
One of the 2 recursive functions for creating the minimax tree.
static final int noSupply
Number to indicate the absent of supply.
Definition: Common.java:24
MinMaxPlayer(String name, boolean champion, Board board, int tileId)
Create a new player and put him at the row-column coordinates.
boolean hasSupply(int tileId)
Utility function to check if there is a supply on the tile or not.
Definition: Board.java:200
boolean isWalkable(int tileId, int direction)
Predicate to check if a direction is Walkable.
Definition: Board.java:171
static final int LEFT
West direction.
Definition: Common.java:77
void final_statistics()
Prints final statistics for the player.
static final int UP
North direction.
Definition: Common.java:74
void updateMove(int[] m, int playerId)
Utility to update the moves of each player.
Definition: Board.java:275
String name
The name of the player.
Definition: Player.java:219
static int opposite(int direction)
Utility to get the opposite direction.
Definition: Common.java:85
MinMaxPlayer(String name, boolean champion, Board board, int row, int column)
Create a new player and put him at the row-column coordinates.
static final int DOWN
South direction.
Definition: Common.java:76
int prevDirection(Node parent)
Get the previous direction of the player.
static final int Begin
Iterator style begin of range direction (starting north)
Definition: Common.java:64
static final int MOVE_COLUMN
The index of column information.
Definition: Player.java:26
boolean addChild(Node child)
Add a child to the tree.
Definition: Node.java:102
ArrayList< Integer[]> path
our history.
Definition: Player.java:226
Node getParent()
Get parent.
Definition: Node.java:51
int [] getOpponentMove(int playerId)
Boards utility to give access to other player moves.
Definition: Board.java:261
int tryPickSupply(int tileId)
Try to pick supply from a tile.
Definition: Board.java:213
int playerId
The unique identifier of the player.
Definition: Player.java:218
Class to create shuffled ranges of numbers.
Definition: Common.java:251
Board getNodeBoard()
get nodeBoard
Definition: Node.java:60
int get()
Extract and return the first item from the range.
Definition: Common.java:229