/*
* This AI works with a combination of minimizing losses, 
* evaluating and pruning a minimax-tree and square-value avaluation.
*
* All features can be tuned with the parameters in the beginning of the file.
*/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "board.h"
#include "game.h"
#include "player.h"
#include "util.h"

//#define float float_t

/* 
* Tune these for performance
* INITIAL_GAME_TREE_DEPTH must be >= 2
*/
// -------- Game Tree building --------
// - normal parameters -
#define INITIAL_GAME_TREE_DEPTH 4
#define BRANCHING_FACTOR 3

// Game tree extension:
#define EXTEND_GT_TIMES 2
#define EXTEND_DEPTH 1
#define EXTEND_BRANCHING_FACTOR 2

// - end-game parameters -
#define END_GAME_THRESHOLD 10

#define EG_INITIAL_GAME_TREE_DEPTH 10
#define EG_BRANCHING_FACTOR 3

// Game tree extension:
#define EG_EXTEND_GT_TIMES 0
#define EG_EXTEND_DEPTH 1
#define EG_EXTEND_BRANCHING_FACTOR 2

// -------- Desicion making coefficients --------
// worst case from initial game tree
#define WC_CE 5.0
// Minimax average from extended game tree
#define MM_CE 10.0
// Mobility factor out of two levels of initial game tree
#define MO_CE 1.5

// Same for end-game
#define EG_WC_CE 1.0
#define EG_MM_CE 0.0

// A smaller MOBILITY_COEFFICIENT gives mobility a bigger effect (~4)
#define MOBILITY_COEFFICIENT 4

// -------- Values for different square types --------
#define DEFAULT_SQUARE_VALUE 1
#define EDGE_CENTER_VALUE 2
#define CENTER_VALUE 0.5
#define CORNER_VALUE 35
#define X_SQUARE_VALUE -10
#define C_SQUARE_VALUE -2
#define EDGE_CONTROL_VALUE 5
// because some squares have nagative values, there must an offset to
// avoid false value ratios. e.g. 10/-5 == -10/5
// SCORE_OFFSET makes all scores positive
#define SCORE_OFFSET 50
// maximum value for any board ratio
#define MAX_POINTS 300

/* --------- Game State ------------- */
typedef struct GameState_s {
	struct Game *game;
	float value;
} *GameState;

/** Construct new gamestate from game **/
GameState gameStateConstruct(struct Game* game);

/** Destruct gameState **/
void gameStateDestruct(GameState state);

/** Free resources used by Game-pointer in gamestate **/
void gameStateFreeGame(GameState state);

/** calculate disc-square table **/
float** getSquareValues(struct Game const* game, int player);

/** destruct disc-square table **/
void squareValuesDestruct(float** values);

/** tell if game is starting to end **/
int isEndGame(struct Game const* game);

/** calculate value for current game state in tree according to disc-square table **/
void gameStateCalculateValue(GameState state, int player);

/** calculate value for current game state in tree according to raw score ratio **/
void gameStateCalculateValueRaw(GameState state, int player);

/* ------------- (Game) Tree: ------------- */
// Data abstraction
typedef GameState Data;
#define dataDestruct gameStateDestruct

typedef struct Tree_s {
	Data data;
	struct Tree_s* parent;
	struct Tree_s** children;
	unsigned int num_children; // number of children
	unsigned int num_child;    // tree is num_child:st child of parent
} *Tree;

/** construct new tree with data in it **/
Tree treeConstruct(Data data);

/**  add child to tree **/
void treeAddChild(Tree tree, Tree child);

/** Remove (and destruct) tree **/
void treeRemove(Tree tree);

/** Detach tree from parent **/
void treeDetach(Tree tree);

/** Destruct tree **/
void treeDestruct(Tree tree);

/** get last child at far left **/
Tree treeGetFirstLeaf(Tree tree);

/** get next leaf **/
Tree treeGetNextLeaf(Tree tree);

/** Get first child of tree **/
Tree treeGetFirstChild(Tree tree);

/** get next sibling **/
Tree treeGetNextSibling(Tree tree);

/** return 1 if tree is descendant of ancestor, else 0 **/
int treeIsDescendantOf(Tree tree, Tree ancestor);

/** return 1 if parent has child child, else 0 **/
int treeHasChild(Tree parent, Tree child);

/*  ------------- Initial moves ------------------- */
typedef struct InitialMove_s {
	int elements; // number of elements
	Tree *trees; // trees corrensponding to moves
	struct Coord *moves; // coordinates of moves
	float *wc_values; // worst-case-values
	float *mm_values; // minimax-pruned values
	float *mobility_factors;
} *InitialMove;

/** Construct new set of initial moves **/
InitialMove initialMoveConstruct(void);

/** add a new move **/
void initialMoveAdd(InitialMove im, Tree tree, struct Coord move);

/** remove all "dead" trees from initial move -sets **/
void initialMoveUpdate(InitialMove im, Tree root);

/** evaluate worst case values for initial moves **/
void initialMoveEvaluateWC(InitialMove im);

/** evaluate minimax values for initial moves (worst case) **/
void initialMoveEvaluateMM(InitialMove im);

/** evaluate mobility coefficient **/
void initialMoveEvaluateMobility(InitialMove im);

/** Destruct set of moves **/
void initialMoveDestruct(InitialMove im);

/* ----------Game tree buildining & pruning   ----------------- **/
/** build a game tree depth high, scores corresponding to player.
*   Save initial moves into moves if moves != NULL
**/
void buildGameTree(Tree tree, int depth, int player, InitialMove im, int endgame);

/** Extend game tree. New game trees are built downwars from leaves of tree.
*   New trees are depth deep and have branching factor of brancing_factor.
*   current_depth is depth in whole game tree (current state depth = 0)
**/
void extendGameTree(Tree tree, int current_depth, int depth, int branching_factor, int player, int endgame);

/** Populate game-tree node with children representing all valid moves.
*   Save initial moves into moves if moves != NULL
**/
int treePopulateNode(Tree tree, InitialMove moves);

/** Prune game tree using minimax method **/
void pruneMinimax(Tree tree, unsigned int branching_factor, int invert);
void pruneMin(Tree tree, unsigned int branching_factor);
void pruneMax(Tree tree, unsigned int branching_factor);

/** calculate tree values according to worst case from children (recursive) **/
float treeUpdateValues(Tree root);

/*
* "Main" functions.
*/
/** Get best possible move from inital move structure **/
struct Coord getBestMove(InitialMove im);

/** Get best possible move from inital move structure for end game **/
struct Coord getBestMoveEG(InitialMove im);

/** Play as player, using artificial intelligence. Returns the player's move. **/
struct Coord aiPlay(struct Game const* game) {
	struct Coord best_move_coords;
	InitialMove im;
	int player = gameCurrentPlayer(game);
	
	Data data = gameStateConstruct(gameCopy(game));
	Tree root = treeConstruct(data);
	im = initialMoveConstruct();
	
	if (!isEndGame(game)) {
		// Build & prune initial game tree
		buildGameTree(root, INITIAL_GAME_TREE_DEPTH, player, im, 0);
		
		// evaluate worst case and mobility
		initialMoveEvaluateWC(im);
		initialMoveEvaluateMobility(im);
		
		// prune initial game tree
		pruneMinimax(root, BRANCHING_FACTOR, 0);
		initialMoveUpdate(im, root);
		
		// Extend while pruning
		int depth = INITIAL_GAME_TREE_DEPTH;
		for (int i = 0; i < EXTEND_GT_TIMES; i++) {
			extendGameTree(root, depth, EXTEND_DEPTH, EXTEND_BRANCHING_FACTOR, player, 0);
			depth += EXTEND_DEPTH;
		}
		
		// evaluate minimax-value
		initialMoveEvaluateMM(im);
		
		best_move_coords = getBestMove(im);
	} else {
		// Build & prune initial game tree
		buildGameTree(root, EG_INITIAL_GAME_TREE_DEPTH, player, im, 1);
		
		// evaluate worst case and mobility
		initialMoveEvaluateWC(im);
		
		// prune initial game tree
		pruneMinimax(root, EG_BRANCHING_FACTOR, 0);
		initialMoveUpdate(im, root);
		
		// Extend while pruning
		int depth = INITIAL_GAME_TREE_DEPTH;
		for (int i = 0; i < EG_EXTEND_GT_TIMES; i++) {
			extendGameTree(root, depth, EG_EXTEND_DEPTH, EG_EXTEND_BRANCHING_FACTOR, player, 1);
			depth += EG_EXTEND_DEPTH;
		}
		
		// evaluate minimax-value
		initialMoveEvaluateMM(im);
		
		best_move_coords = getBestMoveEG(im);
	}
	
	// Clean up
	initialMoveDestruct(im);
	treeDestruct(root);
	
	return best_move_coords;
}

struct Coord getBestMove(InitialMove im) {
	float best_value = 0, value;
	struct Coord best_move;

	for(int i = 0; i < im->elements; i++) {
		value = (WC_CE * im->wc_values[i] +
			MM_CE * im->wc_values[i] +
			MO_CE * im->mobility_factors[i])
			/ (WC_CE + MM_CE + MO_CE);
		if (value > best_value) {
			best_value = value;
			best_move = im->moves[i];
		}
	}
	
	return best_move;
}

struct Coord getBestMoveEG(InitialMove im) {
	float best_value = 0, value;
	struct Coord best_move;

	for(int i = 0; i < im->elements; i++) {
		value = (EG_WC_CE * im->wc_values[i] +
			 EG_MM_CE * im->wc_values[i])
			/ (EG_WC_CE + EG_MM_CE);
		if (value > best_value) {
			best_value = value;
			best_move = im->moves[i];
		}
	}
	
	return best_move;
}

/*
* Game tree pruning and building
*/
void buildGameTree(Tree tree, int depth, int player, InitialMove im, int endgame) {
	int game_end = 0;
	Tree root = tree;
	
	// first moves
	game_end = treePopulateNode(tree, im);
	
	for (int i = 0; i < depth && !game_end; i++) {
		tree = treeGetFirstLeaf(root);
		do {
			game_end = treePopulateNode(tree, NULL);
		} while((tree = treeGetNextLeaf(tree)) && treeIsDescendantOf(tree, root));
	}
	
	// Calulate values for leaves
	tree = treeGetFirstLeaf(root);
	do {
		if (endgame) {
			gameStateCalculateValueRaw(tree->data, player);
		} else {
			gameStateCalculateValue(tree->data, player);
		}
	} while((tree = treeGetNextLeaf(tree)) && treeIsDescendantOf(tree, root));
	
	// Calculate in-tree-values for nodes to correspond to worst possible case
	treeUpdateValues(root);
}

void extendGameTree(Tree tree, int current_depth, int depth, int branching_factor, int player, int endgame) {
	Tree root = tree;
	int invert = current_depth % 2;

	tree = treeGetFirstLeaf(tree);
	do {
		buildGameTree(tree, depth, player, NULL, endgame);
		treeUpdateValues(tree);
		pruneMinimax(tree, branching_factor, invert);
		
	} while((tree = treeGetNextLeaf(tree)) && treeIsDescendantOf(tree, root));
	
}

int treePopulateNode(Tree tree, InitialMove moves) {
	unsigned int x, y;
	struct Coord move;
	int game_end = 0;
	int flips;
	
	if(!gameCurrentPlayer(tree->data->game)) return -1;
	
	// Go through each square
	for (x = 0; x < 8; x++) {
		for (y = 0; y < 8; y++) {
			move = coord(x, y);
			if((flips = gameNumFlips(tree->data->game, move)) == 0) {
				continue; // Move not valid
			}
			
			struct Game *new_game = gameCopy(tree->data->game);
			game_end = gamePlayCurrent(new_game, move);
			Data data = gameStateConstruct(new_game);
			Tree child = treeConstruct(data);
			treeAddChild(tree, child);
			
			if (moves) initialMoveAdd(moves, child, move);	
			
			// If one player wins, the minimax is worst in any case...
			if (game_end) break;
		}
		if (game_end) break;
	}
	
	// Destruct game to save memory...
	gameStateFreeGame(tree->data);
	return game_end;
}

void pruneMinimax(Tree tree, unsigned int branching_factor, int invert) {
	if (tree->num_children == 0) return;
	
	Tree child;
	
	// prune
	if(!invert) {
		pruneMin(tree, branching_factor);
	} else {
		pruneMax(tree, branching_factor);
	}
	
	// invert 'invert'
	invert = (invert + 1) % 2;
	child = tree->children[0];
	do {
		pruneMinimax(child, branching_factor, invert);
	} while ((child = treeGetNextSibling(child)));
}

void pruneMin(Tree tree, unsigned int branching_factor) {
	if (tree->num_children == 0) return;
	
	Tree child, min_child = NULL;
	float min_value, value;
	while (tree->num_children > branching_factor) {
		min_value = INFINITY;
		child = tree->children[0];
		do {
			value = child->data->value;
			if (value < min_value) {
				min_value = value;
				min_child = child;
			} else if( value == min_value) { // Pseudo-random replace
				if(((unsigned int)((7 +  2 * tree->num_child) * value)) % 2) {
					min_child = child;
				}
			}
		} while ((child = treeGetNextSibling(child)));
		
		treeRemove(min_child);
	}
}

void pruneMax(Tree tree, unsigned int branching_factor) {
	if (tree->num_children == 0) return;
	
	Tree child, max_child = NULL;
	float max_value, value;
	while (tree->num_children > branching_factor) {
		max_value = 0;
		child = tree->children[0];
		do {
			value = child->data->value;
			if (value > max_value) {
				max_value = value;
				max_child = child;
			} else if( value == max_value) { // Pseudo-random replace
				if(((unsigned int)((7 +  2 * tree->num_child) * value)) % 2) {
					max_child = child;
				}
			}
		} while ((child = treeGetNextSibling(child)));
		
		treeRemove(max_child);
	}	
}

float treeUpdateValues(Tree root) {
	float min_value = INFINITY, child_value;
	
	for (unsigned int i = 0; i < root->num_children; i++) {
		child_value = treeUpdateValues(root->children[i]);
		if (child_value < min_value) {
			min_value = child_value;
		}
	}
	if (min_value < INFINITY) {
		root->data->value = min_value;
	}
	return root->data->value;
}


/* Game state functions:
* struct GameState_s {
*	struct Game *game;
*	float value;
* };
*/
GameState gameStateConstruct(struct Game* game) {
	GameState game_state = (GameState) malloc(sizeof(struct GameState_s));
	game_state->game = game;
	game_state->value = -1;
	
	return game_state;
}

void gameStateDestruct(GameState state) {
	if (state->game != NULL) {
		gameDestruct(state->game);
	}
	free(state);
}

void gameStateFreeGame(GameState state) {
	if (state->game != NULL) {
		gameDestruct(state->game);
	}
	state->game = NULL;
}

void gameStateCalculateValue(GameState state, int player) {
	unsigned int x, y;
	int square_type;
	struct Coord coord;
	float my_points = 0, opponent_points = 0;
	
	float** my_matrix = getSquareValues(state->game, player);
	float** opponent_matrix = getSquareValues(state->game, (player % 2) + 1);
	
	for (x = 0; x < 8; x++) {
		for (y = 0; y < 8; y++) {
			coord.x = x;
			coord.y = y;
			square_type = gameSquareType(state->game, coord);
			if (square_type == player) {
				my_points += my_matrix[x][y];
			} else if (square_type != 0) {
				opponent_points += opponent_matrix[x][y];
			}
		}
	}
	
	squareValuesDestruct(my_matrix);
	squareValuesDestruct(opponent_matrix);
	
	// Apply offset to avoid negative ratios:
	my_points += SCORE_OFFSET;
	opponent_points += SCORE_OFFSET;
	
	if (opponent_points == 0) { // avoid div-by-zero
		state->value = MAX_POINTS;
		return;
	}
	
	state->value = my_points / opponent_points;
}

void gameStateCalculateValueRaw(GameState state, int player) {
	unsigned int x, y;
	int square_type;
	struct Coord coord;
	float my_points = 0, opponent_points = 0;
	
	for (x = 0; x < 8; x++) {
		for (y = 0; y < 8; y++) {
			coord.x = x;
			coord.y = y;
			square_type = gameSquareType(state->game, coord);
			if (square_type == player) {
				my_points++;
			} else if (square_type != 0) {
				opponent_points++;
			}
		}
	}
	
	if (opponent_points == 0) { // avoid div-by-zero
		state->value = MAX_POINTS;
		return;
	}
	
	state->value = my_points / opponent_points;
}

float** getSquareValues(struct Game const* game, int player) {
	int opponent = (player % 2) + 1;
	
	float **matrix = (float**) malloc(8 * sizeof(float*));
	for (int i = 0; i < 8; i++) {
		matrix[i] = (float*) malloc(8 * sizeof(float));
	}
	for(int x = 0; x < 8; x++) {
		for(int y = 0; y < 8; y++) {
			matrix[x][y] = DEFAULT_SQUARE_VALUE;
		}
	}
	
	// Give edge centers and center squares values
	matrix[0][3] = matrix[0][4] = matrix[7][3] = matrix[7][4] =
	matrix[3][0] = matrix[4][0] = matrix[3][7] = matrix[4][7] = EDGE_CENTER_VALUE;
	
	matrix[3][3] = matrix[3][4] = matrix[4][3] = matrix[4][4] = CENTER_VALUE;
	
	// Give corners a big value and 'corner give' locations small value
	// Also, if an edge is free of the opponent, give 'edge control'
	// squares big value
	matrix[0][0] = matrix[0][7] = matrix[7][0] = matrix[7][7] = CORNER_VALUE;
	if (gameSquareEmpty(game, coord(0,0))) {
		matrix[1][1] = X_SQUARE_VALUE;
		matrix[0][1] = matrix[1][0] = C_SQUARE_VALUE;
		if (gameSquareType(game, coord(0,1)) != opponent &&
		    gameSquareType(game, coord(0,2)) != opponent &&
		    gameSquareType(game, coord(0,3)) != opponent &&
		    gameSquareType(game, coord(0,4)) != opponent &&
		    gameSquareType(game, coord(0,5)) != opponent &&
		    gameSquareType(game, coord(0,6)) != opponent &&
		    gameSquareType(game, coord(0,7)) != opponent) {
			matrix[0][2] = matrix[0][5] = EDGE_CONTROL_VALUE;
		}
	}
	if (gameSquareEmpty(game, coord(0,7))) {
		matrix[1][6] = X_SQUARE_VALUE;
		matrix[0][6] = matrix[1][7] = C_SQUARE_VALUE;
		if (gameSquareType(game, coord(1,7)) != opponent &&
		    gameSquareType(game, coord(2,7)) != opponent &&
		    gameSquareType(game, coord(3,7)) != opponent &&
		    gameSquareType(game, coord(4,7)) != opponent &&
		    gameSquareType(game, coord(5,7)) != opponent &&
		    gameSquareType(game, coord(6,7)) != opponent &&
		    gameSquareType(game, coord(7,7)) != opponent) {
			matrix[2][7] = matrix[5][7] = EDGE_CONTROL_VALUE;
		}
	}
	if (gameSquareEmpty(game, coord(7,0))) {
		matrix[6][1] = X_SQUARE_VALUE;
		matrix[7][1] = matrix[6][0] = C_SQUARE_VALUE;
		if (gameSquareType(game, coord(0,0)) != opponent &&
		    gameSquareType(game, coord(1,0)) != opponent &&
		    gameSquareType(game, coord(2,0)) != opponent &&
		    gameSquareType(game, coord(3,0)) != opponent &&
		    gameSquareType(game, coord(4,0)) != opponent &&
		    gameSquareType(game, coord(5,0)) != opponent &&
		    gameSquareType(game, coord(6,0)) != opponent) {
			matrix[2][0] = matrix[5][0] = EDGE_CONTROL_VALUE;
		}
	}
	if (gameSquareEmpty(game, coord(7,7))) {
		matrix[6][6] = X_SQUARE_VALUE;
		matrix[6][7] = matrix[7][6] = C_SQUARE_VALUE;
		if (gameSquareType(game, coord(7, 0)) != opponent &&
		    gameSquareType(game, coord(7, 1)) != opponent &&
		    gameSquareType(game, coord(7, 2)) != opponent &&
		    gameSquareType(game, coord(7, 3)) != opponent &&
		    gameSquareType(game, coord(7, 4)) != opponent &&
		    gameSquareType(game, coord(7, 5)) != opponent &&
		    gameSquareType(game, coord(7, 6)) != opponent) {
			matrix[7][2] = matrix[7][5] = EDGE_CONTROL_VALUE;
		}
	}

	return matrix;
}

void squareValuesDestruct(float** values) {
	for (int i = 0; i < 8; i++) {
		free(values[i]);
	}
	free(values);
}

int isEndGame(struct Game const* game) {
	unsigned int empty_squares = 0;
	
	for (int x = 0; x < 8; x++) { 
	for (int y = 0; y < 8; y++) {
		if (!gameSquareType(game, coord(x, y))) empty_squares++;
	}}
	
	if(empty_squares <= END_GAME_THRESHOLD) return 1;
	return 0;
}

/* Tree functions 
* struct Tree_s {
*	Data data;
*	struct Tree_s* parent;
*	struct Tree_s** children;
*	unsigned int num_children;
*	unsigned int num_child;
* }
*/
Tree treeConstruct(Data data) {
	Tree tree = (Tree) malloc(sizeof(struct Tree_s));
	tree->data = data;
	tree->parent = NULL;
	tree->children = (Tree*) malloc(sizeof(Tree));
	tree->children[0] = NULL;
	tree->num_children = 0;
	tree->num_child = 0;
	
	return tree;
}

void treeRemove(Tree tree) {
	treeDetach(tree);    // Detach from parent
	treeDestruct(tree);  // Recursive destruct
}

void treeDestruct(Tree tree) {
	// Destruct children
	for (unsigned int i = 0; i < tree->num_children; i++) {
		treeDestruct(tree->children[i]);
	}
	
	// Ddestruct self
	dataDestruct(tree->data);
	free(tree->children);
	free(tree);
}

void treeAddChild(Tree tree, Tree child) {
	tree->num_children++;
	tree->children = (Tree*) realloc(tree->children, tree->num_children * sizeof(Tree));
	tree->children[tree->num_children - 1] = child;
	child->parent = tree;
	child->num_child = tree->num_children;
}

void treeDetach(Tree tree) {
	Tree parent = tree->parent;
	if(!parent) return;
	
	// Move and update num_child for siblings of tree
	for(unsigned int i = tree->num_child - 1; i < (parent->num_children - 1); i++) {
		parent->children[i] = parent->children[i + 1];
		parent->children[i]->num_child = i + 1;
	}
	parent->num_children--;
	parent->children = (Tree*) realloc(parent->children, parent->num_children * sizeof(Tree));
}

Tree treeGetFirstLeaf(Tree tree) {
	if(tree->num_children == 0) return tree;
	if(tree == NULL) return NULL;
	
	while(tree->num_children > 0) {
		tree = tree->children[0];
	}
	
	return tree;
}

Tree treeGetNextSibling(Tree tree) {
	if (tree->parent == NULL) return NULL; // Special case...
	if (tree->parent->num_children <= tree->num_child) return NULL;
	return tree->parent->children[tree->num_child];
}

Tree treeGetNextLeaf(Tree tree) {
	Tree temp;
	
	// Get next sibling if applicable
	if ((temp = treeGetNextSibling(tree))) return temp;
	
	// Go up in tree as long as node is the last child of its parent
	while(tree->parent && !treeGetNextSibling(tree)) {
		tree = tree->parent;
	}
	
	// Get next sibling or return null if end has been reached
	if (!(tree = treeGetNextSibling(tree))) return NULL;
	
	// Go back to bottom level
	return treeGetFirstLeaf(tree);
}

Tree treeGetFirstChild(Tree tree) {
	if (tree->num_children == 0) return NULL;
	return tree->children[0];
}

int treeIsDescendantOf(Tree tree, Tree ancestor) {
	if (tree == NULL) return 0;
	while ((tree = tree->parent)) {
		if (tree == ancestor) return 1;
	}
	return 0;
}

int treeHasChild(Tree parent, Tree child) {
	Tree test;
	for(test = treeGetFirstChild(parent); test; test = treeGetNextSibling(test)) {
		if (test == child) return 1;
	}
	return 0;
}
	
/* Initial moves

 * typedef struct InitialMove_s {
 *	int elements;
 *	Tree *trees;
 *	float *values;
 *	float *mobility_factors;
 *	float *mm_values;
 *	struct Coord *moves;
 * } *InitialMove;
 */

InitialMove initialMoveConstruct(void) {
	InitialMove im = (InitialMove) malloc(sizeof(struct InitialMove_s));
	im->elements = 0;
	im->trees = NULL;
	im->moves = NULL;
	im->wc_values = NULL;
	im->mm_values = NULL;
	im->mobility_factors = NULL;
	return im;
}

void initialMoveDestruct(InitialMove im) {
	free(im->trees);
	free(im->moves);
	free(im->wc_values);
	free(im->mm_values);
	free(im->mobility_factors);
	free(im);
}

void initialMoveAdd(InitialMove im, Tree tree, struct Coord move) {
	im->trees = (Tree*) realloc(im->trees, (im->elements + 1) * sizeof(Tree));
	im->trees[im->elements] = tree;
	
	im->wc_values = (float*) realloc(im->wc_values, (im->elements + 1) * sizeof(float));
	im->mm_values = (float*) realloc(im->mm_values, (im->elements + 1) * sizeof(float));
	im->mobility_factors = (float*) realloc(im->mobility_factors, (im->elements + 1) * sizeof(float));
	
	im->moves = (struct Coord*) realloc(im->moves, (im->elements + 1) * sizeof(struct Coord));
	im->moves[im->elements] = move;
	
	im->elements++;
}

void initialMoveEvaluateWC(InitialMove im) {
	for (int i = 0; i < im->elements; i++) {
		im->wc_values[i] = im->trees[i]->data->value;
	}
}

void initialMoveEvaluateMM(InitialMove im) {
	for (int i = 0; i < im->elements; i++) {
		im->mm_values[i] = im->trees[i]->data->value;
	}
}

void initialMoveEvaluateMobility(InitialMove im) {
	Tree tree;
	unsigned int opponent_mobility, my_mobility = (unsigned int) INFINITY;
	float mobility_coefficient, mc = MOBILITY_COEFFICIENT;
	
	for (int i = 0; i < im->elements; i++) {
		tree = im->trees[i];
		if(!tree || !(tree->num_children)) return;
		
		// get own mobility
		opponent_mobility = tree->num_children;
		
		// Get worst case own mobility after opponent moves
		for(unsigned int j = 0; j < tree->num_children; j++) {
			if (tree->children[j]->num_children < my_mobility) {
				my_mobility = tree->children[j]->num_children;
			}
		}
		
		mobility_coefficient = (float) my_mobility / (float) opponent_mobility;
		mobility_coefficient = (mc + mobility_coefficient) / (1.2 * mc);
		
		im->mobility_factors[i] = mobility_coefficient;
	}
}

void initialMoveUpdate(InitialMove im, Tree root) {
	for (int i = 0; i < im->elements; i++) {
		if (treeHasChild(root, im->trees[i])) continue;
		
		/* Tree has been removed -> remove corrensponding move */
		// move remaining elements backwards
		for (int index = i + 1; index < im->elements; index++) {
			im->trees[index - 1] = im->trees[index];
			im->moves[index - 1] = im->moves[index];
			im->wc_values[index - 1] = im->wc_values[index];
			im->mm_values[index - 1] = im->mm_values[index];
			im->mobility_factors[index - 1] = im->mobility_factors[index];
		}
		i--; // otherwise next tree wont be evaluated...
		im->elements--;
		
		// Realloc all members of InitialMove_s
		im->trees = (Tree*) realloc(im->trees, im->elements * sizeof(Tree));
		im->moves = (struct Coord*) realloc(im->moves, im->elements * sizeof(struct Coord));
		im->wc_values = (float*) realloc(im->wc_values, im->elements * sizeof(float));
		im->mm_values = (float*) realloc(im->mm_values, im->elements * sizeof(float));
		im->mobility_factors = (float*) realloc(im->mobility_factors, im->elements * sizeof(float));
	}
}

