import java.util.ArrayList;
import java.lang.annotation.*;
import java.applet.Applet;
import java.awt.Graphics;
import java.util.ArrayList;
import java.awt.Color;
import java.awt.*;
import java.awt.event.*;

public class JaDEN_OXO extends JaDEN implements emDependent{
	@EDEN_DESCRIPTION(definition = "new Board(0, 0)")
	private emBoard bord = new emBoard(new Board(0, 0).registerDependent(this));
	@EDEN_DESCRIPTION(definition = "(mouseX / 50)")
	private int mouseColumn = (mouseX / 50);
	@EDEN_DESCRIPTION(definition = "(mouseY / 50)")
	private int mouseRow = (mouseY / 50);
	private Board nextBoard;
	@EDEN_DESCRIPTION(definition = "new Board(250, 0)")
	private emBoard nextMode = new emBoard(new Board(250, 0));
	@EDEN_DESCRIPTION(definition = "new Text(35, 170, \"Current Board\")")
	private emText headerCurrent = new emText(new Text(35, 170, "Current Board"));
	@EDEN_DESCRIPTION(definition = "new Text(290, 170, \"Best Move\")")
	private emText headerBest = new emText(new Text(290, 170, "Best Move"));
	@EDEN_DESCRIPTION(definition = "new Text(10, 200, (\"Status: \" + (bord.item.getPlayerWin() ? (\"Winner is \" + bord.item.getOtherPlayer()) : \"N/A\")))")
	private emText currentStatus = new emText(new Text(10, 200, ("Status: " + (bord.item.getPlayerWin() ? ("Winner is " + bord.item.getOtherPlayer()) : "N/A"))));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public void init(){
		super.init();
		picture.add(bord);
		picture.add(nextMode);
		picture.add(headerBest);
		picture.add(headerCurrent);
		picture.add(currentStatus);
		bord.item.nextBestMove(nextMode.item);

	}

	private void mouseClickX_updated(){
		bord.item.movePiece(mouseColumn, mouseRow);
		nextMode.item.undoLastMove();
		nextMode.item.movePiece(mouseColumn, mouseRow);
		bord.item.nextBestMove(nextMode.item);

	}

	public JaDEN_OXO(){
		super();

	
		super.emAddDependent(this);
		Evaluator.addInstance(this);
}	


	public JaDEN_OXO registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("mouseX")){em_updateMouseColumn(); }
		else if(property.equals("mouseY")){em_updateMouseRow(); }
		else if(property.equals("mouseClickX")){mouseClickX_updated();}
		else if(property.equals("mouseClickY")){}
		else if(property.equals("mousePressed")){}
		else if(property.equals("picture")){}
		else if(property.equals("Board.playerWin") && bord.item == obj){em_updateCurrentStatus(); }
		else if(property.equals("Board.otherPlayer") && bord.item == obj){em_updateCurrentStatus(); }
		emTriggerUpdateJaDEN_OXO(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateJaDEN_OXO(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticJaDEN_OXO(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void em_updateBord(){
		try{
			emBoard new_bord = new emBoard(new Board(0, 0));
			setBord(new_bord.item);
		}catch(Exception e){
			bord.item = null;
		}
	}
	public void setBord(Board em_bord){
		if(bord.item == null || !bord.item.equals(em_bord)){
			bord.item = em_bord;
			em_updateCurrentStatus();
			emTriggerUpdateJaDEN_OXO("bord");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.bord");
		}
	}
	public Board getBord(){
		return bord.item;
	}
	private void em_updateMouseColumn(){
		try{
			int new_mouseColumn = (mouseX / 50);
			setMouseColumn(new_mouseColumn);
		}catch(Exception e){
			mouseColumn = 0;
		}
	}
	public void setMouseColumn(int em_mouseColumn){
		if(mouseColumn != em_mouseColumn){
			mouseColumn = em_mouseColumn;
			emTriggerUpdateJaDEN_OXO("mouseColumn");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.mouseColumn");
		}
	}
	public int getMouseColumn(){
		return mouseColumn;
	}
	private void em_updateMouseRow(){
		try{
			int new_mouseRow = (mouseY / 50);
			setMouseRow(new_mouseRow);
		}catch(Exception e){
			mouseRow = 0;
		}
	}
	public void setMouseRow(int em_mouseRow){
		if(mouseRow != em_mouseRow){
			mouseRow = em_mouseRow;
			emTriggerUpdateJaDEN_OXO("mouseRow");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.mouseRow");
		}
	}
	public int getMouseRow(){
		return mouseRow;
	}
	private void em_updateNextMode(){
		try{
			emBoard new_nextMode = new emBoard(new Board(250, 0));
			setNextMode(new_nextMode.item);
		}catch(Exception e){
			nextMode.item = null;
		}
	}
	private void setNextMode(Board em_nextMode){
		if(nextMode.item == null || !nextMode.item.equals(em_nextMode)){
			nextMode.item = em_nextMode;
			emTriggerUpdateJaDEN_OXO("nextMode");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.nextMode");
		}
	}
	private void em_updateHeaderCurrent(){
		try{
			emText new_headerCurrent = new emText(new Text(35, 170, "Current Board"));
			setHeaderCurrent(new_headerCurrent.item);
		}catch(Exception e){
			headerCurrent.item = null;
		}
	}
	public void setHeaderCurrent(Text em_headerCurrent){
		if(headerCurrent.item == null || !headerCurrent.item.equals(em_headerCurrent)){
			headerCurrent.item = em_headerCurrent;
			emTriggerUpdateJaDEN_OXO("headerCurrent");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.headerCurrent");
		}
	}
	public Text getHeaderCurrent(){
		return headerCurrent.item;
	}
	private void em_updateHeaderBest(){
		try{
			emText new_headerBest = new emText(new Text(290, 170, "Best Move"));
			setHeaderBest(new_headerBest.item);
		}catch(Exception e){
			headerBest.item = null;
		}
	}
	public void setHeaderBest(Text em_headerBest){
		if(headerBest.item == null || !headerBest.item.equals(em_headerBest)){
			headerBest.item = em_headerBest;
			emTriggerUpdateJaDEN_OXO("headerBest");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.headerBest");
		}
	}
	public Text getHeaderBest(){
		return headerBest.item;
	}
	private void em_updateCurrentStatus(){
		try{
			emText new_currentStatus = new emText(new Text(10, 200, ("Status: " + (bord.item.getPlayerWin() ? ("Winner is " + bord.item.getOtherPlayer()) : "N/A"))));
			setCurrentStatus(new_currentStatus.item);
		}catch(Exception e){
			currentStatus.item = null;
		}
	}
	public void setCurrentStatus(Text em_currentStatus){
		if(currentStatus.item == null || !currentStatus.item.equals(em_currentStatus)){
			currentStatus.item = em_currentStatus;
			emTriggerUpdateJaDEN_OXO("currentStatus");
			emTriggerUpdateJaDEN_OXO("JaDEN_OXO.currentStatus");
		}
	}
	public Text getCurrentStatus(){
		return currentStatus.item;
	}

}
class Board extends Group implements emDependent{
	public int x = 0;
	public int y = 0;
	public String[][] state = new String[3][3];
	public boolean playerX = true;
	@EDEN_DESCRIPTION(definition = "(playerX ? \"x\" : \"o\")")
	private String playerType = (playerX ? "x" : "o");
	@EDEN_DESCRIPTION(definition = "(playerX ? \"o\" : \"x\")")
	private String otherPlayer = (playerX ? "o" : "x");
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][0])) && otherPlayer.equals(state[2][0]))")
	private boolean lineWin1 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][0])) && otherPlayer.equals(state[2][0]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[0][1]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][1]))")
	private boolean lineWin2 = ((otherPlayer.equals(state[0][1]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][1]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[0][2]) && otherPlayer.equals(state[1][2])) && otherPlayer.equals(state[2][2]))")
	private boolean lineWin3 = ((otherPlayer.equals(state[0][2]) && otherPlayer.equals(state[1][2])) && otherPlayer.equals(state[2][2]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[0][1])) && otherPlayer.equals(state[0][2]))")
	private boolean lineWin4 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[0][1])) && otherPlayer.equals(state[0][2]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[1][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[1][2]))")
	private boolean lineWin5 = ((otherPlayer.equals(state[1][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[1][2]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[2][1])) && otherPlayer.equals(state[2][2]))")
	private boolean lineWin6 = ((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[2][1])) && otherPlayer.equals(state[2][2]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][2]))")
	private boolean lineWin7 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][2]));
	@EDEN_DESCRIPTION(definition = "((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[0][2]))")
	private boolean lineWin8 = ((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[0][2]));
	@EDEN_DESCRIPTION(definition = "((lineWin1 || (lineWin2 || (lineWin3 || (lineWin4 || (lineWin5 || (lineWin6 || lineWin7)))))) || lineWin8)")
	private boolean playerWin = ((lineWin1 || (lineWin2 || (lineWin3 || (lineWin4 || (lineWin5 || (lineWin6 || lineWin7)))))) || lineWin8);
	@EDEN_DESCRIPTION(definition = "(((state[0][0] != null) && ((state[1][0] != null) && ((state[2][0] != null) && ((state[0][1] != null) && ((state[1][1] != null) && ((state[2][1] != null) && ((state[0][2] != null) && (state[1][2] != null)))))))) && (state[2][2] != null))")
	private boolean isFull = (((state[0][0] != null) && ((state[1][0] != null) && ((state[2][0] != null) && ((state[0][1] != null) && ((state[1][1] != null) && ((state[2][1] != null) && ((state[0][2] != null) && (state[1][2] != null)))))))) && (state[2][2] != null));
	private int lastX = 0;
	private int lastY = 0;
	@EDEN_DESCRIPTION(definition = "new Rect(x, y, 150, 150)")
	private emRect border = new emRect(new Rect(x, y, 150, 150));
	@EDEN_DESCRIPTION(definition = "new Line((x + 50), (y + 0), (x + 50), (y + 150))")
	private emLine l1 = new emLine(new Line((x + 50), (y + 0), (x + 50), (y + 150)));
	@EDEN_DESCRIPTION(definition = "new Line((x + 100), (y + 0), (x + 100), (y + 150))")
	private emLine l2 = new emLine(new Line((x + 100), (y + 0), (x + 100), (y + 150)));
	@EDEN_DESCRIPTION(definition = "new Line((x + 0), (y + 50), (x + 150), (y + 50))")
	private emLine l3 = new emLine(new Line((x + 0), (y + 50), (x + 150), (y + 50)));
	@EDEN_DESCRIPTION(definition = "new Line((x + 0), (y + 100), (x + 150), (y + 100))")
	private emLine l4 = new emLine(new Line((x + 0), (y + 100), (x + 150), (y + 100)));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public Board(){
		super();

	
		Evaluator.addInstance(this);
}	

	public Board(int a, int b){
		super();
		picture.add(border);
		picture.add(l1);
		picture.add(l2);
		picture.add(l3);
		picture.add(l4);
		setX(a);
		setY(b);

	
		Evaluator.addInstance(this);
}	

	public Board movePiece(int x, int y){
		if(((x > 2) || (y > 2))) return this;
		if(playerX) {
			picture.add(new emPieceX(new PieceX(this, x, y)));

		}

		else {
			picture.add(new emPieceO(new PieceO(this, x, y)));

		}

		state[x][y] = playerType;setArrayState();
		setPlayerX(!playerX);
		lastX = x;
		lastY = y;
		return this;

	}

	public Board boardIfMove(int x, int y){
		Board b;
		b = this.clone();
		b.movePiece(x, y);
		return b;

	}

	public Board undoLastMove(){
		picture.remove((picture.size() - 1));
		state[lastX][lastY] = null;setArrayState();
		setPlayerX(!playerX);
		return this;

	}

	public Board nextBestMove(Board bb){
		if(isFull) return this;
		System.out.println("Find best move");
		System.out.println(bb);
		int value;
		value = (0 - 10);
		if(playerX) value = (0 - 10);
		int nextX;
		nextX = 0;
		int nextY;
		nextY = 0;
		for(int y = 0; (y < 3); y = (y + 1)){
			for(int x = 0; (x < 3); x = (x + 1)){
				if((bb.state[x][y] == null)) {
					Board b;
					b = bb.boardIfMove(x, y);
					int u;
					u = miniMaxAlgo(b, false);
					if((u > value)) {
						value = u;
						nextX = x;
						nextY = y;

					}


				}


			}


		}

		bb.movePiece(nextX, nextY);
		System.out.println(bb);
		return bb;

	}

	public int miniMaxAlgo(Board gs, boolean go){
		if(gs.playerWin) {
			if(go) return (0 - 1);
			else return 1;

		}

		else if(gs.isFull) {
				return 0;

			}

		int utility;
		utility = 10;
		if(go) utility = (0 - 10);
		for(int y = 0; (y < 3); y = (y + 1)){
			for(int x = 0; (x < 3); x = (x + 1)){
				if((gs.state[x][y] == null)) {
					int u;
					u = miniMaxAlgo(gs.boardIfMove(x, y), !go);
					if((go && (u > utility))) utility = u;
					else if((!go && (u < utility))) utility = u;

				}


			}


		}

		return utility;

	}

	public Board clone(){
		Board b;
		b = new emBoard(new Board(250, 0)).item;
		String[][] s;
		s = new String[3][3];
		for(int i = 0; (i < 3); i = (i + 1)){
			for(int j = 0; (j < 3); j = (j + 1)){
				if((state[i][j] == null)) continue;
				if(state[i][j].equals("x")) {
					b.getPicture().add(new emPieceX(new PieceX(b, i, j)));

				}

				else if(state[i][j].equals("o")) {
						b.getPicture().add(new emPieceO(new PieceO(b, i, j)));

					}

				s[i][j] = state[i][j];

			}


		}

		b.setState(s);
		b.setPlayerX(playerX);
		return b;

	}

	public String toString(){
		String res;
		res = "";
		for(int i = 0; (i < 3); i = (i + 1)){
			for(int j = 0; (j < 3); j = (j + 1)){
				if((state[j][i] == null)) res = (res + "-|");
				else res = ((res + state[j][i]) + "|");

			}

			res = (res + "\n");

		}

		return res;

	}

	public boolean equals(Board b){
		for(int i = 0; (i < 3); i = (i + 1)){
			for(int j = 0; (j < 3); j = (j + 1)){
				if((b.state[i][j] != state[i][j])) return false;

			}


		}

		return false;

	}


	public Board registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		emTriggerUpdateBoard(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdateBoard(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticBoard(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	public void setX(int em_x){
		if(x != em_x){
			x = em_x;
			em_updateBorder();
			em_updateL1();
			em_updateL2();
			em_updateL3();
			em_updateL4();
			emTriggerUpdateBoard("x");
			emTriggerUpdateBoard("Board.x");
		}
	}
	public int getX(){
		return x;
	}
	public void setY(int em_y){
		if(y != em_y){
			y = em_y;
			em_updateBorder();
			em_updateL1();
			em_updateL2();
			em_updateL3();
			em_updateL4();
			emTriggerUpdateBoard("y");
			emTriggerUpdateBoard("Board.y");
		}
	}
	public int getY(){
		return y;
	}
	public void setState(String[][] em_state){
		if(state == null || !state.equals(em_state)){
			state = em_state;
			em_updateLineWin1();
			em_updateLineWin2();
			em_updateLineWin3();
			em_updateLineWin4();
			em_updateLineWin5();
			em_updateLineWin6();
			em_updateLineWin7();
			em_updateLineWin8();
			em_updateIsFull();
			emTriggerUpdateBoard("state");
			emTriggerUpdateBoard("Board.state");
		}
	}
	public void setArrayState(){
			em_updateLineWin1();
			em_updateLineWin2();
			em_updateLineWin3();
			em_updateLineWin4();
			em_updateLineWin5();
			em_updateLineWin6();
			em_updateLineWin7();
			em_updateLineWin8();
			em_updateIsFull();
			emTriggerUpdateBoard("state");
			emTriggerUpdateBoard("Board.state");
	}
	public String[][] getState(){
		return state;
	}
	public void setPlayerX(boolean em_playerX){
		if(playerX != em_playerX){
			playerX = em_playerX;
			em_updatePlayerType();
			em_updateOtherPlayer();
			emTriggerUpdateBoard("playerX");
			emTriggerUpdateBoard("Board.playerX");
		}
	}
	public boolean getPlayerX(){
		return playerX;
	}
	private void em_updatePlayerType(){
		try{
			String new_playerType = (playerX ? "x" : "o");
			setPlayerType(new_playerType);
		}catch(Exception e){
			playerType = null;
		}
	}
	public void setPlayerType(String em_playerType){
		if(playerType == null || !playerType.equals(em_playerType)){
			playerType = em_playerType;
			emTriggerUpdateBoard("playerType");
			emTriggerUpdateBoard("Board.playerType");
		}
	}
	public String getPlayerType(){
		return playerType;
	}
	private void em_updateOtherPlayer(){
		try{
			String new_otherPlayer = (playerX ? "o" : "x");
			setOtherPlayer(new_otherPlayer);
		}catch(Exception e){
			otherPlayer = null;
		}
	}
	public void setOtherPlayer(String em_otherPlayer){
		if(otherPlayer == null || !otherPlayer.equals(em_otherPlayer)){
			otherPlayer = em_otherPlayer;
			em_updateLineWin1();
			em_updateLineWin2();
			em_updateLineWin3();
			em_updateLineWin4();
			em_updateLineWin5();
			em_updateLineWin6();
			em_updateLineWin7();
			em_updateLineWin8();
			emTriggerUpdateBoard("otherPlayer");
			emTriggerUpdateBoard("Board.otherPlayer");
		}
	}
	public String getOtherPlayer(){
		return otherPlayer;
	}
	private void em_updateLineWin1(){
		try{
			boolean new_lineWin1 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][0])) && otherPlayer.equals(state[2][0]));
			setLineWin1(new_lineWin1);
		}catch(Exception e){
			lineWin1 = false;
		}
	}
	private void setLineWin1(boolean em_lineWin1){
		if(lineWin1 != em_lineWin1){
			lineWin1 = em_lineWin1;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin1");
			emTriggerUpdateBoard("Board.lineWin1");
		}
	}
	private void em_updateLineWin2(){
		try{
			boolean new_lineWin2 = ((otherPlayer.equals(state[0][1]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][1]));
			setLineWin2(new_lineWin2);
		}catch(Exception e){
			lineWin2 = false;
		}
	}
	private void setLineWin2(boolean em_lineWin2){
		if(lineWin2 != em_lineWin2){
			lineWin2 = em_lineWin2;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin2");
			emTriggerUpdateBoard("Board.lineWin2");
		}
	}
	private void em_updateLineWin3(){
		try{
			boolean new_lineWin3 = ((otherPlayer.equals(state[0][2]) && otherPlayer.equals(state[1][2])) && otherPlayer.equals(state[2][2]));
			setLineWin3(new_lineWin3);
		}catch(Exception e){
			lineWin3 = false;
		}
	}
	private void setLineWin3(boolean em_lineWin3){
		if(lineWin3 != em_lineWin3){
			lineWin3 = em_lineWin3;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin3");
			emTriggerUpdateBoard("Board.lineWin3");
		}
	}
	private void em_updateLineWin4(){
		try{
			boolean new_lineWin4 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[0][1])) && otherPlayer.equals(state[0][2]));
			setLineWin4(new_lineWin4);
		}catch(Exception e){
			lineWin4 = false;
		}
	}
	private void setLineWin4(boolean em_lineWin4){
		if(lineWin4 != em_lineWin4){
			lineWin4 = em_lineWin4;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin4");
			emTriggerUpdateBoard("Board.lineWin4");
		}
	}
	private void em_updateLineWin5(){
		try{
			boolean new_lineWin5 = ((otherPlayer.equals(state[1][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[1][2]));
			setLineWin5(new_lineWin5);
		}catch(Exception e){
			lineWin5 = false;
		}
	}
	private void setLineWin5(boolean em_lineWin5){
		if(lineWin5 != em_lineWin5){
			lineWin5 = em_lineWin5;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin5");
			emTriggerUpdateBoard("Board.lineWin5");
		}
	}
	private void em_updateLineWin6(){
		try{
			boolean new_lineWin6 = ((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[2][1])) && otherPlayer.equals(state[2][2]));
			setLineWin6(new_lineWin6);
		}catch(Exception e){
			lineWin6 = false;
		}
	}
	private void setLineWin6(boolean em_lineWin6){
		if(lineWin6 != em_lineWin6){
			lineWin6 = em_lineWin6;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin6");
			emTriggerUpdateBoard("Board.lineWin6");
		}
	}
	private void em_updateLineWin7(){
		try{
			boolean new_lineWin7 = ((otherPlayer.equals(state[0][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[2][2]));
			setLineWin7(new_lineWin7);
		}catch(Exception e){
			lineWin7 = false;
		}
	}
	private void setLineWin7(boolean em_lineWin7){
		if(lineWin7 != em_lineWin7){
			lineWin7 = em_lineWin7;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin7");
			emTriggerUpdateBoard("Board.lineWin7");
		}
	}
	private void em_updateLineWin8(){
		try{
			boolean new_lineWin8 = ((otherPlayer.equals(state[2][0]) && otherPlayer.equals(state[1][1])) && otherPlayer.equals(state[0][2]));
			setLineWin8(new_lineWin8);
		}catch(Exception e){
			lineWin8 = false;
		}
	}
	private void setLineWin8(boolean em_lineWin8){
		if(lineWin8 != em_lineWin8){
			lineWin8 = em_lineWin8;
			em_updatePlayerWin();
			emTriggerUpdateBoard("lineWin8");
			emTriggerUpdateBoard("Board.lineWin8");
		}
	}
	private void em_updatePlayerWin(){
		try{
			boolean new_playerWin = ((lineWin1 || (lineWin2 || (lineWin3 || (lineWin4 || (lineWin5 || (lineWin6 || lineWin7)))))) || lineWin8);
			setPlayerWin(new_playerWin);
		}catch(Exception e){
			playerWin = false;
		}
	}
	public void setPlayerWin(boolean em_playerWin){
		if(playerWin != em_playerWin){
			playerWin = em_playerWin;
			emTriggerUpdateBoard("playerWin");
			emTriggerUpdateBoard("Board.playerWin");
		}
	}
	public boolean getPlayerWin(){
		return playerWin;
	}
	private void em_updateIsFull(){
		try{
			boolean new_isFull = (((state[0][0] != null) && ((state[1][0] != null) && ((state[2][0] != null) && ((state[0][1] != null) && ((state[1][1] != null) && ((state[2][1] != null) && ((state[0][2] != null) && (state[1][2] != null)))))))) && (state[2][2] != null));
			setIsFull(new_isFull);
		}catch(Exception e){
			isFull = false;
		}
	}
	public void setIsFull(boolean em_isFull){
		if(isFull != em_isFull){
			isFull = em_isFull;
			emTriggerUpdateBoard("isFull");
			emTriggerUpdateBoard("Board.isFull");
		}
	}
	public boolean getIsFull(){
		return isFull;
	}
	private void em_updateBorder(){
		try{
			emRect new_border = new emRect(new Rect(x, y, 150, 150));
			setBorder(new_border.item);
		}catch(Exception e){
			border.item = null;
		}
	}
	private void setBorder(Rect em_border){
		if(border.item == null || !border.item.equals(em_border)){
			border.item = em_border;
			emTriggerUpdateBoard("border");
			emTriggerUpdateBoard("Board.border");
		}
	}
	private void em_updateL1(){
		try{
			emLine new_l1 = new emLine(new Line((x + 50), (y + 0), (x + 50), (y + 150)));
			setL1(new_l1.item);
		}catch(Exception e){
			l1.item = null;
		}
	}
	private void setL1(Line em_l1){
		if(l1.item == null || !l1.item.equals(em_l1)){
			l1.item = em_l1;
			emTriggerUpdateBoard("l1");
			emTriggerUpdateBoard("Board.l1");
		}
	}
	private void em_updateL2(){
		try{
			emLine new_l2 = new emLine(new Line((x + 100), (y + 0), (x + 100), (y + 150)));
			setL2(new_l2.item);
		}catch(Exception e){
			l2.item = null;
		}
	}
	private void setL2(Line em_l2){
		if(l2.item == null || !l2.item.equals(em_l2)){
			l2.item = em_l2;
			emTriggerUpdateBoard("l2");
			emTriggerUpdateBoard("Board.l2");
		}
	}
	private void em_updateL3(){
		try{
			emLine new_l3 = new emLine(new Line((x + 0), (y + 50), (x + 150), (y + 50)));
			setL3(new_l3.item);
		}catch(Exception e){
			l3.item = null;
		}
	}
	private void setL3(Line em_l3){
		if(l3.item == null || !l3.item.equals(em_l3)){
			l3.item = em_l3;
			emTriggerUpdateBoard("l3");
			emTriggerUpdateBoard("Board.l3");
		}
	}
	private void em_updateL4(){
		try{
			emLine new_l4 = new emLine(new Line((x + 0), (y + 100), (x + 150), (y + 100)));
			setL4(new_l4.item);
		}catch(Exception e){
			l4.item = null;
		}
	}
	private void setL4(Line em_l4){
		if(l4.item == null || !l4.item.equals(em_l4)){
			l4.item = em_l4;
			emTriggerUpdateBoard("l4");
			emTriggerUpdateBoard("Board.l4");
		}
	}

}
class PieceX extends Group implements emDependent{
	private Board board = new emBoard(new Board()).item;
	private int posX = 0;
	private int posY = 0;
	private int size = 50;
	@EDEN_DESCRIPTION(definition = "(board.getX() + (posX * size))")
	private int offsetX = (board.getX() + (posX * size));
	@EDEN_DESCRIPTION(definition = "(board.getY() + (posY * size))")
	private int offsetY = (board.getY() + (posY * size));
	@EDEN_DESCRIPTION(definition = "new Line((0 + offsetX), (0 + offsetY), (size + offsetX), (size + offsetY))")
	private emLine l1 = new emLine(new Line((0 + offsetX), (0 + offsetY), (size + offsetX), (size + offsetY)));
	@EDEN_DESCRIPTION(definition = "new Line((size + offsetX), (0 + offsetY), (0 + offsetX), (size + offsetY))")
	private emLine l2 = new emLine(new Line((size + offsetX), (0 + offsetY), (0 + offsetX), (size + offsetY)));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public PieceX(){
		super();

	
		Evaluator.addInstance(this);
}	

	public PieceX(Board b, int x, int y){
		super();
		picture.add(l1);
		picture.add(l2);
		setBoard(b);
		setPosX(x);
		setPosY(y);

	
		Evaluator.addInstance(this);
}	

	public String toString(){
		return "x";

	}


	public PieceX registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		else if(property.equals("Board.x") && board == obj){em_updateOffsetX(); }
		else if(property.equals("Board.y") && board == obj){em_updateOffsetY(); }
		emTriggerUpdatePieceX(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdatePieceX(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticPieceX(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void setBoard(Board em_board){
		if(board == null || !board.equals(em_board)){
			board = em_board;
			em_updateOffsetX();
			em_updateOffsetY();
			emTriggerUpdatePieceX("board");
			emTriggerUpdatePieceX("PieceX.board");
		}
	}
	private void setPosX(int em_posX){
		if(posX != em_posX){
			posX = em_posX;
			em_updateOffsetX();
			emTriggerUpdatePieceX("posX");
			emTriggerUpdatePieceX("PieceX.posX");
		}
	}
	private void setPosY(int em_posY){
		if(posY != em_posY){
			posY = em_posY;
			em_updateOffsetY();
			emTriggerUpdatePieceX("posY");
			emTriggerUpdatePieceX("PieceX.posY");
		}
	}
	private void setSize(int em_size){
		if(size != em_size){
			size = em_size;
			em_updateOffsetX();
			em_updateOffsetY();
			em_updateL1();
			em_updateL2();
			emTriggerUpdatePieceX("size");
			emTriggerUpdatePieceX("PieceX.size");
		}
	}
	private void em_updateOffsetX(){
		try{
			int new_offsetX = (board.getX() + (posX * size));
			setOffsetX(new_offsetX);
		}catch(Exception e){
			offsetX = 0;
		}
	}
	private void setOffsetX(int em_offsetX){
		if(offsetX != em_offsetX){
			offsetX = em_offsetX;
			em_updateL1();
			em_updateL2();
			emTriggerUpdatePieceX("offsetX");
			emTriggerUpdatePieceX("PieceX.offsetX");
		}
	}
	private void em_updateOffsetY(){
		try{
			int new_offsetY = (board.getY() + (posY * size));
			setOffsetY(new_offsetY);
		}catch(Exception e){
			offsetY = 0;
		}
	}
	private void setOffsetY(int em_offsetY){
		if(offsetY != em_offsetY){
			offsetY = em_offsetY;
			em_updateL1();
			em_updateL2();
			emTriggerUpdatePieceX("offsetY");
			emTriggerUpdatePieceX("PieceX.offsetY");
		}
	}
	private void em_updateL1(){
		try{
			emLine new_l1 = new emLine(new Line((0 + offsetX), (0 + offsetY), (size + offsetX), (size + offsetY)));
			setL1(new_l1.item);
		}catch(Exception e){
			l1.item = null;
		}
	}
	private void setL1(Line em_l1){
		if(l1.item == null || !l1.item.equals(em_l1)){
			l1.item = em_l1;
			emTriggerUpdatePieceX("l1");
			emTriggerUpdatePieceX("PieceX.l1");
		}
	}
	private void em_updateL2(){
		try{
			emLine new_l2 = new emLine(new Line((size + offsetX), (0 + offsetY), (0 + offsetX), (size + offsetY)));
			setL2(new_l2.item);
		}catch(Exception e){
			l2.item = null;
		}
	}
	private void setL2(Line em_l2){
		if(l2.item == null || !l2.item.equals(em_l2)){
			l2.item = em_l2;
			emTriggerUpdatePieceX("l2");
			emTriggerUpdatePieceX("PieceX.l2");
		}
	}

}
class PieceO extends Group implements emDependent{
	private Board board = new emBoard(new Board()).item;
	private int posX = 0;
	public int posY = 0;
	private int size = 50;
	@EDEN_DESCRIPTION(definition = "(board.getX() + (posX * size))")
	private int offsetX = (board.getX() + (posX * size));
	@EDEN_DESCRIPTION(definition = "(board.getY() + (posY * size))")
	private int offsetY = (board.getY() + (posY * size));
	@EDEN_DESCRIPTION(definition = "new Arc(offsetX, offsetY, size, size, 0, 360)")
	private emArc a1 = new emArc(new Arc(offsetX, offsetY, size, size, 0, 360));
	private ArrayList<emDependent> emDependents = new ArrayList<emDependent>();
	private static ArrayList<emDependent> emDependentsStatic = new ArrayList<emDependent>();

	public PieceO(){
		super();

	
		Evaluator.addInstance(this);
}	

	public PieceO(Board b, int x, int y){
		super();
		picture.add(a1);
		setBoard(b);
		setPosX(x);
		setPosY(y);

	
		Evaluator.addInstance(this);
}	

	public String toString(){
		return "o";

	}


	public PieceO registerDependent(emDependent depend){
		emDependents.add(depend);
		return this;
	}

	public void emAddDependent(emDependent depend){
		emDependents.add(depend);
	}

	public void emUpdate(Object obj, String property) {
		if(property.equals("picture")){}
		else if(property.equals("Board.x") && board == obj){em_updateOffsetX(); }
		else if(property.equals("Board.y") && board == obj){em_updateOffsetY(); }
		emTriggerUpdatePieceO(property);
	}

	public void emUpdate(String property) {
	}

	private void emTriggerUpdatePieceO(String property){
		for(int i = 0; i < emDependents.size(); i++){
			emDependents.get(i).emUpdate(this, property);
		}
	}

	public static void emTriggerUpdateStaticPieceO(String property){
		for(int i = 0; i < emDependentsStatic.size(); i++){
			emDependentsStatic.get(i).emUpdate(property);
		}
	}
	private void setBoard(Board em_board){
		if(board == null || !board.equals(em_board)){
			board = em_board;
			em_updateOffsetX();
			em_updateOffsetY();
			emTriggerUpdatePieceO("board");
			emTriggerUpdatePieceO("PieceO.board");
		}
	}
	private void setPosX(int em_posX){
		if(posX != em_posX){
			posX = em_posX;
			em_updateOffsetX();
			emTriggerUpdatePieceO("posX");
			emTriggerUpdatePieceO("PieceO.posX");
		}
	}
	public void setPosY(int em_posY){
		if(posY != em_posY){
			posY = em_posY;
			em_updateOffsetY();
			emTriggerUpdatePieceO("posY");
			emTriggerUpdatePieceO("PieceO.posY");
		}
	}
	public int getPosY(){
		return posY;
	}
	private void setSize(int em_size){
		if(size != em_size){
			size = em_size;
			em_updateOffsetX();
			em_updateOffsetY();
			em_updateA1();
			emTriggerUpdatePieceO("size");
			emTriggerUpdatePieceO("PieceO.size");
		}
	}
	private void em_updateOffsetX(){
		try{
			int new_offsetX = (board.getX() + (posX * size));
			setOffsetX(new_offsetX);
		}catch(Exception e){
			offsetX = 0;
		}
	}
	private void setOffsetX(int em_offsetX){
		if(offsetX != em_offsetX){
			offsetX = em_offsetX;
			em_updateA1();
			emTriggerUpdatePieceO("offsetX");
			emTriggerUpdatePieceO("PieceO.offsetX");
		}
	}
	private void em_updateOffsetY(){
		try{
			int new_offsetY = (board.getY() + (posY * size));
			setOffsetY(new_offsetY);
		}catch(Exception e){
			offsetY = 0;
		}
	}
	private void setOffsetY(int em_offsetY){
		if(offsetY != em_offsetY){
			offsetY = em_offsetY;
			em_updateA1();
			emTriggerUpdatePieceO("offsetY");
			emTriggerUpdatePieceO("PieceO.offsetY");
		}
	}
	private void em_updateA1(){
		try{
			emArc new_a1 = new emArc(new Arc(offsetX, offsetY, size, size, 0, 360));
			setA1(new_a1.item);
		}catch(Exception e){
			a1.item = null;
		}
	}
	private void setA1(Arc em_a1){
		if(a1.item == null || !a1.item.equals(em_a1)){
			a1.item = em_a1;
			emTriggerUpdatePieceO("a1");
			emTriggerUpdatePieceO("PieceO.a1");
		}
	}

}

//Interface for classes to send / receive variable update events
interface emDependent{
	public void emUpdate(String property);
	public void emUpdate(Object obj, String property);
}

//Wrapper classes for all objects who are the results of dependencies
class emBoard extends emGroup{
	public Board item;

	public emBoard (Board obj){
		 super(obj);
		 item = obj;
	}

	public emBoard (){}
	public Board movePiece(int x, int y){return item.movePiece(x, y);}
	public Board boardIfMove(int x, int y){return item.boardIfMove(x, y);}
	public Board undoLastMove(){return item.undoLastMove();}
	public Board nextBestMove(Board bb){return item.nextBestMove(bb);}
	public int miniMaxAlgo(Board gs, boolean go){return item.miniMaxAlgo(gs, go);}
	public Board clone(){return item.clone();}
	public String toString(){return item.toString();}
	public boolean equals(Board b){return item.equals(b);}
	public  void  setX(int obj){item.setX(obj);}
	public int getX(){return item.getX();}
	public  void  setY(int obj){item.setY(obj);}
	public int getY(){return item.getY();}
	public  void  setState(String[][] obj){item.setState(obj);}
	public String[][] getState(){return item.getState();}
	public  void  setPlayerX(boolean obj){item.setPlayerX(obj);}
	public boolean getPlayerX(){return item.getPlayerX();}
	public  void  setPlayerType(String obj){item.setPlayerType(obj);}
	public String getPlayerType(){return item.getPlayerType();}
	public  void  setOtherPlayer(String obj){item.setOtherPlayer(obj);}
	public String getOtherPlayer(){return item.getOtherPlayer();}
	public  void  setPlayerWin(boolean obj){item.setPlayerWin(obj);}
	public boolean getPlayerWin(){return item.getPlayerWin();}
	public  void  setIsFull(boolean obj){item.setIsFull(obj);}
	public boolean getIsFull(){return item.getIsFull();}
}
class emGroup extends emShape{
	public Group item;

	public emGroup (Group obj){
		 super(obj);
		 item = obj;
	}

	public emGroup (){}
	public void draw(Graphics g){item.draw(g);}
	public ArrayList getShapes(){return item.getShapes();}
	public  void  setPicture(ArrayList obj){item.setPicture(obj);}
	public ArrayList getPicture(){return item.getPicture();}
}
class emShape extends Object{
	public Shape item;

	public emShape (Shape obj){
		 super();
		 item = obj;
	}

	public emShape (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setX1(int obj){item.setX1(obj);}
	public int getX1(){return item.getX1();}
	public  void  setX2(int obj){item.setX2(obj);}
	public int getX2(){return item.getX2();}
	public  void  setY1(int obj){item.setY1(obj);}
	public int getY1(){return item.getY1();}
	public  void  setY2(int obj){item.setY2(obj);}
	public int getY2(){return item.getY2();}
	public  void  setColor(Color obj){item.setColor(obj);}
	public Color getColor(){return item.getColor();}
}
class emPieceX extends emGroup{
	public PieceX item;

	public emPieceX (PieceX obj){
		 super(obj);
		 item = obj;
	}

	public emPieceX (){}
	public String toString(){return item.toString();}
}
class emPieceO extends emGroup{
	public PieceO item;

	public emPieceO (PieceO obj){
		 super(obj);
		 item = obj;
	}

	public emPieceO (){}
	public String toString(){return item.toString();}
	public  void  setPosY(int obj){item.setPosY(obj);}
	public int getPosY(){return item.getPosY();}
}
class emText extends emShape{
	public Text item;

	public emText (Text obj){
		 super(obj);
		 item = obj;
	}

	public emText (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setLabel(String obj){item.setLabel(obj);}
	public String getLabel(){return item.getLabel();}
}
class emRect extends emShape{
	public Rect item;

	public emRect (Rect obj){
		 super(obj);
		 item = obj;
	}

	public emRect (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
}
class emLine extends emShape{
	public Line item;

	public emLine (Line obj){
		 super(obj);
		 item = obj;
	}

	public emLine (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
}
class emArc extends emShape{
	public Arc item;

	public emArc (Arc obj){
		 super(obj);
		 item = obj;
	}

	public emArc (){}
	public void draw(Graphics g){item.draw(g);}
	public String toString(){return item.toString();}
	public  void  setStartAngle(int obj){item.setStartAngle(obj);}
	public int getStartAngle(){return item.getStartAngle();}
	public  void  setEndAngle(int obj){item.setEndAngle(obj);}
	public int getEndAngle(){return item.getEndAngle();}
}

//Annotation interface for dependency labelling
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface EDEN_DESCRIPTION {
	String definition();
}
