private int minimax(char[][] board, int ply, boolean is_maximizer){
		
		//	Base case: out of plies!
		if (ply == 0) {
			return game.getFitness(board, fitness_mode, is_maximizer ? PolarTTT.PLAYER1 : PolarTTT.PLAYER2);
		}
		
		//	Find available moves
		Location[] options = findAvailableMoves(board);
		
		//	Base case: Out of moves!
		if (options.length == 0) {
			return 0;
		}
		
		if (is_maximizer) {
			int best = Integer.MIN_VALUE;
			for (Location choice : options) {
				//	Preview a move
				domove(board, choice, is_maximizer);
				
				int fitness = minimax(board, ply - 1, !is_maximizer);
				
				//	Undo the preview
				undomove(board, choice);
				
				//	Track a new best
				if (best < fitness) {
					best = fitness;
				}
			}
			return best;
		}
		else {
			int best = Integer.MAX_VALUE;
			for (Location choice : options) {
				//	Preview a move
				domove(board, choice, is_maximizer);
				
				int fitness = minimax(board, ply - 1, !is_maximizer);
				
				//	Undo the preview
				undomove(board, choice);
				
				// Track a new best
				if (best > fitness) {
					best = fitness;
				}
			}
			return best;
		}
	}