From a1e2f053d8c10c9013ef45414f11e08d2697f35a Mon Sep 17 00:00:00 2001
From: Francesco Bariatti <francesco.bariatti@insa-rennes.fr>
Date: Sat, 30 Apr 2016 20:35:30 +0200
Subject: [PATCH] Added selection of tiles to GUI

---
 gui/src/controller/Controller.java   | 62 ++++++++++++++++++++++++++--
 gui/src/controller/UpdateThread.java |  2 +-
 gui/src/model/GameState.java         | 56 ++++++++++++++++++++-----
 gui/src/view/TileView.java           | 36 ++++++++++++----
 4 files changed, 134 insertions(+), 22 deletions(-)

diff --git a/gui/src/controller/Controller.java b/gui/src/controller/Controller.java
index 865ceca..b5ef51a 100644
--- a/gui/src/controller/Controller.java
+++ b/gui/src/controller/Controller.java
@@ -19,6 +19,7 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.net.URL;
+import java.util.List;
 import java.util.ResourceBundle;
 
 public class Controller implements Initializable
@@ -30,6 +31,7 @@ public class Controller implements Initializable
 	private Tile[] board;
 	private TileView[] boardView;
 	private Player humanPlayer;
+	private int selectedTile;
 
 	@FXML
 	private Polygon tile0, tile1, tile2, tile3, tile4, tile5, tile6, tile7, tile8, tile9, tile10, tile11, tile12, tile13, tile14, tile15, tile16, tile17, tile18, tile19, tile20, tile21, tile22, tile23, tile24, tile25, tile26, tile27, tile28, tile29, tile30, tile31, tile32, tile33, tile34, tile35, tile36, tile37, tile38, tile39, tile40, tile41, tile42, tile43, tile44, tile45, tile46, tile47, tile48, tile49, tile50, tile51, tile52, tile53, tile54, tile55, tile56, tile57, tile58, tile59;
@@ -46,8 +48,10 @@ public class Controller implements Initializable
 		for (int i = 0; i < fxTiles.length; i++)
 		{
 			board[i] = new Tile(i, Tile.PenguinPresence.NO_PENGUIN);
+			fxTiles[i].setOnMouseClicked(new TileClickHandler(i));
 			boardView[i] = new TileView(fxTiles[i], board[i]);
 		}
+		this.selectedTile = -1;
 		this.gameState = new GameState();
 		try
 		{
@@ -91,14 +95,64 @@ public class Controller implements Initializable
 		}
 	}
 
-
-	private class MyClickHandler implements EventHandler<MouseEvent>
+	/**
+	 * Event handler that will listen for a click on a tile.
+	 * It is associated with a TileView
+	 */
+	private class TileClickHandler implements EventHandler<MouseEvent>
 	{
+		private int tileNumber;
+
+		public TileClickHandler(int tileNumber)
+		{
+			this.tileNumber = tileNumber;
+		}
+
+		/**
+		 * Change the tiles' highlighted values to the given value
+		 */
+		private void changeTilesHighlightState(List<Integer> tiles, boolean value)
+		{
+			for (int tile : tiles)
+			{
+				boardView[tile].setHighlighted(value);
+				boardView[tile].update();
+			}
+		}
+
 		@Override
 		public void handle(MouseEvent event)
 		{
-			Polygon poly = (Polygon) event.getSource();
-			poly.setFill(Color.GOLD);
+			if (!gameState.getCurrent_player().equals(humanPlayer))
+				return;
+
+			if (selectedTile == tileNumber) //If we clicked again on the selected tile
+			{
+				//UnSelect and un-highlight previously selected and highlighted tiles
+				boardView[selectedTile].setSelected(true);
+				boardView[selectedTile].update();
+				changeTilesHighlightState(gameState.getReachableTiles(humanPlayer, gameState.getPenguinOnTile(humanPlayer, selectedTile)), false);
+				selectedTile = -1;
+				return;
+			}
+
+			//We clicked on a tile that wasn't previously selected
+			int penguinNb = gameState.getPenguinOnTile(humanPlayer, tileNumber);
+			if (penguinNb == -1) //There is no penguin on this tile
+				return;
+
+			//There is a penguin on the tile: we want to select this tile
+			if (selectedTile != -1) //If there was a tile previously selected
+			{
+				boardView[selectedTile].setSelected(false);
+				boardView[selectedTile].update();
+				changeTilesHighlightState(gameState.getReachableTiles(humanPlayer, gameState.getPenguinOnTile(humanPlayer, selectedTile)), false);
+			}
+			boardView[tileNumber].setSelected(true);
+			boardView[tileNumber].update();
+			changeTilesHighlightState(gameState.getReachableTiles(humanPlayer, penguinNb), true);
+			selectedTile = tileNumber;
+			return;
 		}
 	}
 
diff --git a/gui/src/controller/UpdateThread.java b/gui/src/controller/UpdateThread.java
index 14f84ca..f3ed2a9 100644
--- a/gui/src/controller/UpdateThread.java
+++ b/gui/src/controller/UpdateThread.java
@@ -58,7 +58,7 @@ public class UpdateThread extends Thread
 
 					//UPDATE VIEW
 					for (int i = 0; i < boardView.length; i++)
-						boardView[i].updateFromModel();
+						boardView[i].update();
 				}
 			}
 			catch (IOException e)
diff --git a/gui/src/model/GameState.java b/gui/src/model/GameState.java
index ae3e8df..bab409a 100644
--- a/gui/src/model/GameState.java
+++ b/gui/src/model/GameState.java
@@ -3,7 +3,9 @@ package model;
 import org.json.JSONArray;
 import org.json.JSONObject;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class GameState
@@ -72,17 +74,12 @@ public class GameState
 
 	/**
 	 * @param player The penguin's owner
-	 * @param i The number of the penguin for this player
+	 * @param i      The number of the penguin for this player
 	 * @return the total moves that this penguin can do
 	 */
 	public int getPenguinTotalMoves(Player player, int i)
 	{ return ((penguins.get(player)[i] >>> 6) & 63); }
 
-	public enum Direction
-	{
-		A,B,C,D,E,F;
-	}
-
 	/**
 	 * Get maximum number of tiles that a penguin can do in one specific direction
 	 */
@@ -122,18 +119,52 @@ public class GameState
 	{
 		int[] peng = penguins.get(player);
 		int total = 0;
-		for(int i = 0; i < penguinNumber; i++) //We add the moves of all preceding penguins
+		for (int i = 0; i < penguinNumber; i++) //We add the moves of all preceding penguins
 			total += getPenguinTotalMoves(player, i);
-		for(Direction d : Direction.values())
+		for (Direction d : Direction.values())
 		{
-			if(d.equals(direction))
-				return total+nbSteps-1;
+			if (d.equals(direction))
+				return total + nbSteps - 1;
 			else
 				total += getNbMoves(player, penguinNumber, d);
 		}
 		return -1;
 	}
 
+	/**
+	 * @return The number of the penguin of this player that is on tile number tileNumber. Or -1 if there isn't any (note: there could be a penguin of the other player)
+	 */
+	public int getPenguinOnTile(Player player, int tileNumber)
+	{
+		for (int i = 0; i < penguins.get(player).length; i++)
+			if (getPenguinPos(player, i) == tileNumber)
+				return i;
+		return -1;
+	}
+
+	/**
+	 * @return The list of all tiles that could be reached by moving penguin penguinNb of player player
+	 */
+	public List<Integer> getReachableTiles(Player player, int penguinNb)
+	{
+		List<Integer> result = new ArrayList<>();
+		int startingTile = getPenguinPos(player, penguinNb);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.A); i++)
+			result.add(startingTile + i * 7);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.B); i++)
+			result.add(startingTile - i);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.C); i++)
+			result.add(startingTile - i * 8);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.D); i++)
+			result.add(startingTile - i * 7);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.E); i++)
+			result.add(startingTile + i);
+		for (int i = 1; i <= getNbMoves(player, penguinNb, Direction.F); i++)
+			result.add(startingTile + i * 8);
+
+		return result;
+	}
+
 	public boolean getCan_play_red()
 	{
 		return can_play_red;
@@ -154,4 +185,9 @@ public class GameState
 		return score.get(player);
 	}
 
+	public enum Direction
+	{
+		A, B, C, D, E, F;
+	}
+
 }
diff --git a/gui/src/view/TileView.java b/gui/src/view/TileView.java
index f95e80f..214de4b 100644
--- a/gui/src/view/TileView.java
+++ b/gui/src/view/TileView.java
@@ -11,9 +11,11 @@ public class TileView
 {
 	private Polygon fxTile;
 	private Tile modelTile;
+	private boolean selected, highlighted;
 
 	public TileView(Polygon fxTile, Tile modelTile)
 	{
+
 		this.fxTile = fxTile;
 		this.modelTile = modelTile;
 	}
@@ -21,30 +23,50 @@ public class TileView
 	/**
 	 * Tell the view to update according to the model
 	 */
-	public void updateFromModel()
+	public void update()
 	{
 		//TODO: Better tile representation
+		Color fillColor = null;
 		//FISH NUMBER
 		switch (modelTile.getNbFish())
 		{
 			case 0:
-				fxTile.setFill(Color.LIGHTBLUE);
+				fillColor = Color.LIGHTBLUE;
 				break;
 			case 1:
-				fxTile.setFill(Color.GREENYELLOW);
+				fillColor = Color.GREENYELLOW;
 				break;
 			case 2:
-				fxTile.setFill(Color.GREEN);
+				fillColor = Color.GREEN;
 				break;
 			case 3:
-				fxTile.setFill(Color.DARKGREEN);
+				fillColor = Color.DARKGREEN;
 				break;
 		}
 		//PENGUIN
 		if (modelTile.getPenguinPresence().equals(Tile.PenguinPresence.RED_PENGUIN))
-			fxTile.setFill(Color.RED);
+			fillColor = Color.RED;
 		else if (modelTile.getPenguinPresence().equals(Tile.PenguinPresence.BLUE_PENGUIN))
-			fxTile.setFill(Color.BLUE);
+			fillColor = Color.BLUE;
+
+		//SELECTION/HIGHLIGHT
+		if (selected)
+			fillColor = fillColor.deriveColor(0, 1, 0.5, 1);
+		if (highlighted)
+			fillColor = fillColor.deriveColor(0, 0.5, 1, 1);
+
+		fxTile.setFill(fillColor);
 
 	}
+
+	public Tile getModelTile() { return modelTile; }
+
+	public boolean isSelected() { return selected; }
+
+	public void setSelected(boolean selected) { this.selected = selected; }
+
+	public boolean isHighlighted() { return highlighted; }
+
+	public void setHighlighted(boolean highlighted) { this.highlighted = highlighted; }
+
 }
-- 
GitLab