import java.util.ArrayList;

public class Prologin extends Interface {

	// Les 4 cotes
	int[][] ways = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
	Position cible; // Pulsar que le pathfinder essaie d'obtenir
	// Fonction appelée au début de la partie.

	public void partie_init() {
		//System.out.println("Player " + API.moi() + ": Begin");
		API.init();
		// La classe API me permet de gerer le probleme de base en haut/gauche.
		// Ainsi, par defaut on se trouve a gauche et tout les appels
		// normalement fait
		// a la classe "Interface" sont fait a la classe API qui s'occupe de
		// faire les symmetries nescessaires
	}

	// Affiche la map actuelle
	public void printMap() {
		Position p = new Position();
		System.out.println("Printing");
		for (int y = 0; y < 39; y++) {
			for (int x = 0; x < 39; x++) {
				p.x = x;
				p.y = y;
				System.err.print(" " + (API.est_libre(p) ? 1 : 0));
			}
			System.err.println();
		}
	}

	// Permet de creer une instance de la classe position depuis 2 variables
	public Position position(int x, int y) {
		Position p = new Position();
		p.x = x;
		p.y = y;
		return p;
	}

	// Permet d'afficher un array de int quelquoncque (pour le debug)
	public void printArray(int[][] array) {
		for (int y = 0; y < array.length; y++) {
			for (int i = 0; i < array[y].length; i++) {
				if (array[y][i] == -3)
					System.out.print(" .");
				else
					System.out.print((array[y][i] < 0 ? "" : " ") + array[y][i]);
			}
			System.out.println();
		}
	}

	// Distance de mannhatan minimal pour aller jusqu'a une de mes abses
	public int distanceToRealBase(Position p) {
		int minDistToBase = -1;
		for (Position base : API.ma_base()) {
			int distance = Math.abs(p.x - base.x) + Math.abs(p.y - base.y);
			if (distance < minDistToBase || minDistToBase == -1) {
				minDistToBase = distance;
			}
		}
		return minDistToBase;
	}

	boolean fromBase = true; // Variable qui indique si le chemin que devras emprunter
						// le pathfinder est jusqu'au pipe le plus proche ou
						// jusqu'a
						// la base la plus proche.

	boolean fromBaseTmp = false;// Variables temporaires pour renvoyer 2
								// variables
	Position pipeNotBase;// Dans le cas ou fromBase == true alors c'est le pipe
							// ou
							// le pathfinder va essayer d'aller
	Position pipeNotBaseTmp; // variable temporaire contenant ce tuyau

	int[][] distanceCache; // Double tableau qui garde en cache la distance pour
							// aller
							// Jusqu'a n'importe quel pipe m'appartenant

	// Fonction permettant de trouver la distance jusqu'a la base en passsant
	// soit
	// par un tuyaux deja existant, ou en cnostruisant un novueau reseau.
	// Elle decide que si le chemin par les tuyaux est 10 de plus que le chemin
	// direct alors
	// elle prend le chemin direct.
	public float distanceToBase(Position p, int[][] pipes) {
		int minDistToBase = distanceToRealBase(p);

		float minDistToPipe = -1;
		for (int i = 0; i < pipes.length; i++) {
			for (int j = 0; j < pipes.length; j++) {
				if (pipes[i][j] == 1 && API.est_tuyau(position(j, i))) {
					float distance = Math.abs(p.x - j) + Math.abs(p.y - i);
					distance += distanceCache[i][j]*2f/3f;
					if (distance < minDistToPipe || minDistToPipe == -1) {
						minDistToPipe = distance;
						pipeNotBaseTmp = position(j, i);
					}
				}
			}
		}

		if (Math.abs(minDistToBase - minDistToPipe) > 10 || minDistToPipe == -1) {
			fromBaseTmp = true;
			return minDistToBase;
		}
		fromBaseTmp = false;

		return minDistToPipe;
	}

	// Regarde si un pulsar est entoure par des tuyaux
	public boolean isEntoure(Position pulsar) {
		boolean toReturn = true;
		Position toChange = new Position();
		toChange.x = pulsar.x - 1;
		toChange.y = pulsar.y - 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x;
		toChange.y = pulsar.y - 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x + 1;
		toChange.y = pulsar.y - 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x - 1;
		toChange.y = pulsar.y;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x - 1;
		toChange.y = pulsar.y + 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x;
		toChange.y = pulsar.y + 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x + 1;
		toChange.y = pulsar.y + 1;
		toReturn &= !API.est_libre(toChange);

		toChange.x = pulsar.x + 1;
		toChange.y = pulsar.y;
		toReturn &= !API.est_libre(toChange);

		return toReturn;
	}

	// Retourne le "meilleur" pulsar avec une fonction de score qui est :
	// (Puissance * pulsations_restantes_dans_4_ticks) / (distance/3)
	public Position getBestPulsar(int[][] pipes) {
		double max = 0.0000001;
		Position nearestPulsar = null;
		boolean fromBaseOrNot = false;
		Position pipeNotBaseOrNot = null;
		for (Position p : API.liste_pulsars()) {
			if (isEntoure(p))
				continue;
			float distance = distanceToBase(p, pipes);
			int future = 0;
			if(fromBaseTmp)
			{
				future = (int)distance;
			}
			else
			{
				future = (int)(distance-distanceCache[pipeNotBaseTmp.y][pipeNotBaseTmp.x]*2f/3f);
			}
			PulsarInfo info = API.info_pulsar(p);
			int modulo = API.tour_actuel() % info.periode;
			modulo = info.periode - modulo;
			
			int pulsationsMinus = (future>modulo)?1+(future-modulo)/info.periode:0;
			double score = info.puissance * Math.min(4, info.pulsations_restantes-pulsationsMinus);
			score /= (future+distance/2)/2;

			if (score > max) {
				pipeNotBaseOrNot = pipeNotBaseTmp;
				max = score;
				fromBaseOrNot = fromBaseTmp;
				nearestPulsar = p;
			}
		}
		fromBase = fromBaseOrNot;
		pipeNotBase = pipeNotBaseOrNot;
		return nearestPulsar;
	}

	// Construit une map basique contenant -3 pour du vide et 0 pour des tuyaux
	public int[][] buildInitMap() {
		int[][] pipes = new int[39][39];

		for (int y = 0; y < pipes.length; y++) {
			for (int x = 0; x < pipes.length; x++) {
				if (!API.est_tuyau(position(x, y)))
					pipes[y][x] = -3;
				else
					pipes[y][x] = 0;
			}
		}

		return pipes;
	}

	// Une des fonctions les plus importantes :
	// Cette fonction determine quel tuyaux "m'appartient".
	// Cela signifie qu'un plasma dans ce tuyau ira dans la direction de ma base
	// (si rien ne change)
	// Elle determine aussi les cas d'egalite et le cas ou les pipes sont ceux
	// de l'ennemi
	// En l'occurence, la map devient :
	// "1" pour un pipe qui m'appartient
	// "0" pour les cas d'egalites
	// "-1" pour les pipes ennemies
	// "-3" pour les cases autres (pulsars, vide, etc)
	public int[][] getPipesArray(int[][] initMap, boolean fullinit) {
		int[][] pipes = initMap;
		if(!fullinit)
		{
			for (Position p : API.ma_base()) {
				int puissance = API.puissance_aspiration(p);
				pipes[p.y][p.x] = 4;
				for (int k = puissance; k > 0; k--) {
					for (int y = 0; y < pipes.length; y++) {
						for (int x = 0; x < pipes.length; x++) {
							if (pipes[y][x] == 4) {
								pipes[y][x] = 3;
								for (int[] direction : ways) {
									int ycor = y + direction[0];
									int xcor = x + direction[1];
									if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
										if (pipes[ycor][xcor] == 0 || pipes[ycor][xcor] == 2) {
											pipes[ycor][xcor] = 5;
										}
									}
								}
							}
						}
					}
					for (int y = 0; y < pipes.length; y++) {
						for (int x = 0; x < pipes.length; x++) {
							if (pipes[y][x] == 5) {
								pipes[y][x] = 4;
							}
						}
					}
				}
				for (int y = 0; y < pipes.length; y++) {
					for (int x = 0; x < pipes.length; x++) {
						if (pipes[y][x] == 3 || pipes[y][x] == 4) {
							pipes[y][x] = 2;
						}
					}
				}
			}
	
			for (Position p : API.base_ennemie()) {
				int puissance = API.puissance_aspiration(p);
				pipes[p.y][p.x] = 4;
				for (int k = puissance; k > 0; k--) {
					for (int y = 0; y < pipes.length; y++) {
						for (int x = 0; x < pipes.length; x++) {
							if (pipes[y][x] == 4) {
								pipes[y][x] = 3;
								for (int[] direction : ways) {
									int ycor = y + direction[0];
									int xcor = x + direction[1];
									if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
										if (pipes[ycor][xcor] == 0 || pipes[ycor][xcor] == 2) {
											pipes[ycor][xcor] = 5;
										}
									}
								}
							}
						}
					}
					for (int y = 0; y < pipes.length; y++) {
						for (int x = 0; x < pipes.length; x++) {
							if (pipes[y][x] == 5) {
								pipes[y][x] = 4;
							}
						}
					}
				}
				for (int y = 0; y < pipes.length; y++) {
					for (int x = 0; x < pipes.length; x++) {
						if (pipes[y][x] == 3 || pipes[y][x] == 4) {
							pipes[y][x] = -2;
						}
					}
				}
			}
		}
		

		boolean continuer = true;
		while (continuer) {
			continuer = false;
			for (int y = 0; y < pipes.length; y++) {
				for (int x = 0; x < pipes.length; x++) {
					if (pipes[y][x] == 2) {
						continuer = true;
						pipes[y][x] = 1;
						for (int[] direction : ways) {
							int ycor = y + direction[0];
							int xcor = x + direction[1];
							if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
								if (pipes[ycor][xcor] == 0) {
									pipes[ycor][xcor] = 56;
								}
								if (pipes[ycor][xcor] == -92) {
									pipes[ycor][xcor] = -10;
								}
							}
						}
					}
					if (pipes[y][x] == -2) {
						continuer = true;
						pipes[y][x] = -1;
						for (int[] direction : ways) {
							int ycor = y + direction[0];
							int xcor = x + direction[1];
							if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
								if (pipes[ycor][xcor] == 0) {
									pipes[ycor][xcor] = -92;
								}
								if (pipes[ycor][xcor] == 56) {
									pipes[ycor][xcor] = -10;
								}
							}
						}
					}
				}
			}

			for (int y = 0; y < pipes.length; y++) {
				for (int x = 0; x < pipes.length; x++) {
					if (pipes[y][x] == 56)
						pipes[y][x] = 2;
					if (pipes[y][x] == -92)
						pipes[y][x] = -2;
				}
			}
		}

		for (int y = 0; y < pipes.length; y++) {
			for (int x = 0; x < pipes.length; x++) {
				if (pipes[y][x] == -10) {
					pipes[y][x] = 0;
				}
			}
		}
		return pipes;
	}

	// Cette fonction est le pathfinder du systeme
	// Elle va cnostruire un tuyau vers un pulsar donne
	// int[][] pipes correspond au resultat de getPipesArray()
	// action correspond au points d'actions restants
	public int buildPipeTo(Position pulsar, int[][] pipes, int action) {
		int[][] map = new int[39][39];

		for (int y = 0; y < map.length; y++) {
			for (int x = 0; x < map.length; x++) {
				if (API.est_libre(position(x, y)) || API.est_debris(position(x, y)) || API.est_tuyau(position(x, y)))
					map[y][x] = -1;
				else
					map[y][x] = -2;
			}
		}
		if (fromBase) {
			for (Position p2 : API.ma_base()) {
				map[p2.y][p2.x] = -3;
			}
		} else {
			map[pipeNotBase.y][pipeNotBase.x] = -3;
		}

		map[pulsar.y][pulsar.x] = 0;
		int k = 0;
		int startx = 0, starty = 0;
		mainloop: for (k = 0; k < 100; k++) {
			for (int y = 0; y < map.length; y++) {
				for (int x = 0; x < map.length; x++) {
					if (map[y][x] == k) {
						for (int[] direction : ways) {
							int ycor = y + direction[0];
							int xcor = x + direction[1];
							if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
								if (map[ycor][xcor] == -3) {
									startx = x;
									starty = y;
									break mainloop;
								}
								if (map[ycor][xcor] == -1) {
									map[ycor][xcor] = k + 1;
								}
							}
						}
					}
				}
			}
		}
		if (k == 100)
			return -1;

		while (k > 0 && action > 0) {
			Position actuelle = position(startx, starty);
			if (API.est_debris(actuelle)) {
				action -= 3;
				API.deblayer(actuelle);
				API.construire(actuelle);
			}
			if (API.est_libre(actuelle)) {
				action -= 1;
				API.construire(actuelle);
			}
			for (int[] direction : ways) {
				int ycor = starty + direction[0];
				int xcor = startx + direction[1];
				if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
					if (map[ycor][xcor] == k - 1) {
						startx = xcor;
						starty = ycor;
						break;
					}
				}
			}
			if(fromBase)
			{
				Position epais = position(actuelle.x + (actuelle.y - starty), actuelle.y + (actuelle.x - startx));
				if (API.est_libre(epais)) {
					action -= 1;
					API.construire(epais);
				}
			}
			k -= 1;
		}
		if (action > 0) {
			for (int i = -1; i < 2; i++) {
				for (int j = -1; j < 2; j++) {
					Position decal = position(pulsar.x + i, pulsar.y + j);
					if (API.est_libre(decal)) {
						action -= 1;
						API.construire(decal);
					}
				}
			}
		}
		return action;
	}
	
	public void remplirTrou(int[][] pipes)
	{
		int count = 0;
		for (int k = 0; k < pipes.length; k++) {
			for (int j2 = 0; j2 < pipes.length; j2++) {
				int value = pipes[k][j2];
				if (value == 1) {
					count += 1;
				}
			}
		}
		Position maxP = null;
		int max = -1;
		for (int y = 0; y < pipes.length; y++) {
			for (int x = 0; x < pipes.length; x++) {
				if(pipes[y][x] == -3)
				{
					int sum = nbPipes(position(x, y), pipes, 1);
					if(sum >= 2)
					{
						int[][] pipesMod = buildInitMap();
						
						pipesMod[y][x] = 1;
						pipesMod = getPipesArray(pipesMod, false);

						int score = 0;

						for (int k = 0; k < pipesMod.length; k++) {
							for (int j2 = 0; j2 < pipesMod.length; j2++) {
								int value = pipesMod[k][j2];
								if (value == 1) {
									score += 1;
								}
							}
						}
						
						score -= count;
						if(x == 25 && y == 28)
						{
							System.out.println(score);
						}
						if (score > max) {	
							maxP = position(x, y);
							max = score;
						}
					}
				}
			}
		}
		System.out.println(max);
		if(maxP != null && max > 15)
		{
			API.construire(maxP);
		}
		return;
	}

	// Cette fonction est la strategie de destruction
	// Elle regarde parmis les tuyaux ayant 2 voisins ennemi (que je connais
	// grace a "pipes")
	// tel que si on enleve le tuyaux, alors le nombre de tuyau appartenant a
	// l'ennemi baisse de 15
	// puis le detruit (elle detruit celui qui en enleve le plus possible, avec
	// minimum de 15)
	public void detruirePipes(int[][] pipes, int threshold) {
		double min = 1000;
		Position maxKill = null;
		int count = 0;
		float originPlasma = 0;

		for (int i = 0; i < pipes.length; i++) {
			for (int j = 0; j < pipes.length; j++) {
				if (pipes[i][j] == -1) {
					count += 1;
					originPlasma += API.charges_presentes(position(j, i));
				}
			}
		}

		for (int i = 0; i < pipes.length; i++) {
			for (int j = 0; j < pipes.length; j++) {
				if (pipes[i][j] == -1) {
					Position pcur = position(j, i);
					int sum = nbPipes(pcur, pipes, -1);

					if (sum == 2 || sum == 3) {
						int[][] pipesMod = buildInitMap();

						pipesMod[i][j] = -3;
						getPipesArray(pipesMod, false);

						int score = 0;
						float plasma = 0;

						for (int k = 0; k < pipesMod.length; k++) {
							for (int j2 = 0; j2 < pipesMod.length; j2++) {
								int value = pipesMod[k][j2];
								if (value == -1) {
									score += 1;
									plasma += API.charges_presentes(position(j2, k));
								}
							}
						}
						score -= count;
						plasma -= originPlasma;
						if (score < min && plasma != 0) {	
							maxKill = pcur;
							min = score;
						}
					}
				}
			}
		}
		if (maxKill != null && min < -threshold) {
			API.detruire(maxKill);
		}
	}

	// Cette fonction contruit le cache de distance pour distanceFromBase()
	// Chaque tuyau se trouve donc a une certaine distance de la base, indiquee
	// par un nombre entier
	public void buildDistanceCache() {
		distanceCache = buildInitMap();
		for (int i = 0; i < distanceCache.length; i++) {
			for (int j = 0; j < distanceCache.length; j++) {
				if (distanceCache[i][j] == 0) {
					distanceCache[i][j] = -1;
				}
			}
		}
		for (Position p2 : API.ma_base()) {
			distanceCache[p2.y][p2.x] = 0;
		}
		int k = 0;
		boolean continuer;
		do {
			continuer = false;
			for (int y = 0; y < distanceCache.length; y++) {
				for (int x = 0; x < distanceCache.length; x++) {
					if (distanceCache[y][x] == k) {
						for (int[] direction : ways) {
							int ycor = y + direction[0];
							int xcor = x + direction[1];
							if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
								if (distanceCache[ycor][xcor] == -1) {
									distanceCache[ycor][xcor] = k + 1;
									continuer = true;
								}
							}
						}
					}
				}
			}
			k += 1;
		} while (continuer);
	}

	// Cette fonction gere les aspirations
	// le principe est tres simple, elle prend les fonctions ayant l'aspiration
	// la plus faible != 0
	// et la donne a n'importe quel aspirateur ayant un tuyau connecte
	public void aspirationPipe() {
		ArrayList<Position> toAspire = new ArrayList<Position>();
		int min = 1000;
		Position minP = null;
		for (Position p : API.ma_base()) {
			int puissance = API.puissance_aspiration(p);

			Position tuyauNext = null;
			if (p.x == 0) {
				tuyauNext = position(p.x + 1, p.y);
			}
			if (p.x == 38) {
				tuyauNext = position(p.x - 1, p.y);
			}
			if (API.est_tuyau(tuyauNext)) {
				if(puissance < 5)
					toAspire.add(p);
			} else {
				if (puissance < min && puissance > 0) {
					min = puissance;
					minP = p;
				}
			}
		}

		if (toAspire.isEmpty() || minP == null)
			return;
		
		int max = -1;
		Position bestP = null;
		
		for(Position p : toAspire)
		{
			int[][] pipesMod = buildInitMap();
			for (Position p2 : API.ma_base()) {
				int puissance = API.puissance_aspiration(p2);
				if(p2.x == p.x && p2.y == p.y)
				{
					puissance++;
				}
				if(p2.x == minP.x && p2.y == minP.y)
				{
					puissance--;
				}
				pipesMod[p2.y][p2.x] = 4;
				for (int k = puissance; k > 0; k--) {
					for (int y = 0; y < pipesMod.length; y++) {
						for (int x = 0; x < pipesMod.length; x++) {
							if (pipesMod[y][x] == 4) {
								pipesMod[y][x] = 3;
								for (int[] direction : ways) {
									int ycor = y + direction[0];
									int xcor = x + direction[1];
									if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
										if (pipesMod[ycor][xcor] == 0 || pipesMod[ycor][xcor] == 2) {
											pipesMod[ycor][xcor] = 5;
										}
									}
								}
							}
						}
					}
					for (int y = 0; y < pipesMod.length; y++) {
						for (int x = 0; x < pipesMod.length; x++) {
							if (pipesMod[y][x] == 5) {
								pipesMod[y][x] = 4;
							}
						}
					}
				}
				for (int y = 0; y < pipesMod.length; y++) {
					for (int x = 0; x < pipesMod.length; x++) {
						if (pipesMod[y][x] == 3 || pipesMod[y][x] == 4) {
							pipesMod[y][x] = 2;
						}
					}
				}
			}
	
			for (Position p2 : API.base_ennemie()) {
				int puissance = API.puissance_aspiration(p2);
				pipesMod[p2.y][p2.x] = 4;
				for (int k = puissance; k > 0; k--) {
					for (int y = 0; y < pipesMod.length; y++) {
						for (int x = 0; x < pipesMod.length; x++) {
							if (pipesMod[y][x] == 4) {
								pipesMod[y][x] = 3;
								for (int[] direction : ways) {
									int ycor = y + direction[0];
									int xcor = x + direction[1];
									if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
										if (pipesMod[ycor][xcor] == 0 || pipesMod[ycor][xcor] == 2) {
											pipesMod[ycor][xcor] = 5;
										}
									}
								}
							}
						}
					}
					for (int y = 0; y < pipesMod.length; y++) {
						for (int x = 0; x < pipesMod.length; x++) {
							if (pipesMod[y][x] == 5) {
								pipesMod[y][x] = 4;
							}
						}
					}
				}
				for (int y = 0; y < pipesMod.length; y++) {
					for (int x = 0; x < pipesMod.length; x++) {
						if (pipesMod[y][x] == 3 || pipesMod[y][x] == 4) {
							pipesMod[y][x] = -2;
						}
					}
				}
			}
			int somme = 0;
			pipesMod = getPipesArray(pipesMod, true);
			for (int k = 0; k < pipesMod.length; k++) {
				for (int j2 = 0; j2 < pipesMod.length; j2++) {
					int value = pipesMod[k][j2];
					if (value == -1) {
					 somme += 1;
					}
				}
			}
			if(somme > max)
			{
				max = somme;
				bestP = p;
			}	
		}
		if(minP == null || bestP==null)
			return;
		API.deplacer_aspiration(minP, bestP);
	}

	// Cette fonction selectionne un pipe au hasard et l'ameliore
	public int ameliorerPipes(int action, int[][] pipes) {
		int sum = 1;
		while (action > 0 && sum > 0) {
			sum = 0;
			for (int i = 0; i < pipes.length; i++) {
				for (int j = 0; j < pipes.length; j++) {
					if (pipes[i][j] == 1 && API.est_tuyau(position(j, i)) && !API.est_super_tuyau(position(j, i))) {
						sum += 1;
					}
				}
			}
			// System.out.println(sum);
			int random = (int) (Math.random() * sum + 1);
			int count = 0;
			loop: for (int i = 0; i < pipes.length; i++) {
				for (int j = 0; j < pipes.length; j++) {
					if (pipes[i][j] == 1 && API.est_tuyau(position(j, i)) && !API.est_super_tuyau(position(j, i))) {
						count += 1;
					}
					if (count == random) {
						API.ameliorer(position(j, i));
						action -= 1;
						break loop;
					}
				}
			}
		}
		return action;
	}

	// Cette fonction dnone le nombre de voisins d'un pipe
	public int nbPipes(Position p, int[][] pipes, int check) {
		int sum = 0;
		for (int[] direction : ways) {
			int ycor = p.y + direction[0];
			int xcor = p.x + direction[1];
			if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
				if (pipes[ycor][xcor] == check) {
					sum += 1;
				}
			}
		}
		return sum;
	}

	public int nbPipesTotal(Position p, int[][] pipes) {
		int sum = 0;
		for (int[] direction : ways) {
			int ycor = p.y + direction[0];
			int xcor = p.x + direction[1];
			if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
				if (API.est_tuyau(position(xcor, ycor))) {
					sum += 1;
				}
			}
		}
		return sum;
	}

	// Cette fonction regarde si il y a un pipe a reparer, et le repare.
	// Puis elle ajoute une pipe (il reste 1 action) a cote tel que ce pipe
	// relie le + de pipes possibles
	public int reparerPipes(int action, int[][] pipes) {
		for (int i = 0; i < pipes.length; i++) {
			for (int j = 0; j < pipes.length; j++) {
				Position curPos = position(j, i);
				if (API.est_debris(curPos)) {
					int sum = nbPipes(curPos, pipes, 1);
					if (sum >= 1) {
						API.deblayer(curPos);
						action -= 2;
						API.construire(curPos);
						action -= 1;

						while (action > 0) {
							int max = 0;
							ArrayList<Position> bests = new ArrayList<Position>();
							boolean right = false, left = false, up = false, down = false;
							for (int decaly = -1; decaly < 2; decaly++) {
								for (int decalx = -1; decalx < 2; decalx++) {
									int ycor = i + decaly;
									int xcor = j + decalx;
									Position p3 = new Position();
									p3.x = xcor;
									p3.y = ycor;
									if (ycor >= 0 && ycor < 39 && xcor >= 0 && xcor < 39) {
										if (API.est_libre(p3)) {
											int sum2 = nbPipesTotal(p3, pipes);
											if (decalx == 0) {
												sum2 += 1;
												if (decaly == 1)
													down = true;
												if (decaly == -1)
													up = true;
											}
											if (decaly == 0) {
												sum2 += 1;
												if (decalx == 1)
													right = true;
												if (decalx == -1)
													left = true;
											}
											if (sum2 == max) {
												bests.add(p3);
											}
											if (sum2 > max) {
												// System.out.println("new max :
												// "+p3.x+" "+p3.y+" "+sum2);
												max = sum2;
												bests.clear();
												bests.add(p3);
											}
										}
									}
								}
							}
							if (bests.isEmpty())
								break;
							Position best = bests.get(0);
							if (bests.size() > 1) {
								// System.out.println("Egalite "+curPos.x+"
								// "+curPos.y+" "+max);
								// System.out.println(up+" "+down+" "+right+"
								// "+left);
								int sumBooleans = 0;
								if (up)
									sumBooleans += 1;
								if (down)
									sumBooleans += 1;
								if (right)
									sumBooleans += 1;
								if (left)
									sumBooleans += 1;

								if (sumBooleans == 1) {
									if (up) {
										float maxT = 0;
										for (Position p : bests) {
											if (p.y > maxT) {
												maxT = p.y;
												best = p;
											}
										}
									}
									if (down) {
										float minT = 100;
										for (Position p : bests) {
											// System.out.println(" "+p.x+"
											// "+p.y);
											if (p.y < minT) {
												minT = p.y;
												best = p;
											}
										}
									}
									if (right) {
										float minT = 0;
										for (Position p : bests) {
											if (p.x < minT) {
												minT = p.x;
												best = p;
											}
										}
									}
									if (left) {
										float maxT = 0;
										for (Position p : bests) {
											if (p.x > maxT) {
												maxT = p.x;
												best = p;
											}
										}
									}
								}
								if (right && left) {
									float min = 100;
									for (Position p : bests) {
										if (p.x < min) {
											min = p.x;
											best = p;
										}
									}
								}
								if (up && down) {
									// System.out.println("yes");
									float min = 100;
									for (Position p : bests) {
										// System.out.println(" "+p.x+" "+p.y);
										if (p.y < min) {
											min = p.y;
											best = p;
										}
									}
								}
							}

							API.construire(best);
							action -= 1;
						}
					}
				}
			}
		}

		return action;
	}

	boolean firstTurn = true;
	// Fonction appelée à chaque tour.

	// Le flow du programme se lit presque en franglais
	// Je suis desole pour le melange de francais et anglais
	// Je n'arrive jamais a me forcer a n'en utiliser qu'un
	public void jouer_tour() {

		// Voir description de la fonction
		int[][] pipes = getPipesArray(buildInitMap(), false);

		// Effectue la strategie de destruction
		detruirePipes(pipes, 12);
		int action = API.points_action();

		// Effectue la strategie gratuite d'aspiration
		aspirationPipe();
		// Effectue la strategie de reparation
		reparerPipes(action, pipes);
		// Si c'est le premier tour, ou que le pulsar est entoure, trouve une
		// nouvelle cible
		if (firstTurn || (cible != null && isEntoure(cible))) {
			firstTurn = false;
			buildDistanceCache();
			cible = getBestPulsar(pipes);
		}
		
		remplirTrou(pipes);
		// System.out.println("coucou "+action);

		// Idem, mais tant qu'on a de l'action (pratique sur les map avec une
		// forte densite de pulsar)
		int i = 5;
		while (action > 0 && cible != null && i > 0) {
			action = buildPipeTo(cible, pipes, action);

			if (isEntoure(cible)) {
				buildDistanceCache();
				cible = getBestPulsar(pipes);
			}
			i--;
			// System.out.println(action);
		}

		detruirePipes(pipes, 5);
		// Si jamais il reste quand meme de l'action, effectue la strategie
		// d'amelioration
		// En pratique, cela n'arrive presque jamais
		ameliorerPipes(action, pipes);
	}

	// Fonction appelée à la fin de la partie.
	public void partie_fin() {

	}
}