You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.5 KiB
PHP
127 lines
4.5 KiB
PHP
<?php
|
|
echo shikakugen(8,4,5);
|
|
function shikakugen($largeur,$hauteur,$nbeCarres){
|
|
a:
|
|
$buff="T ".$largeur." ".$hauteur."\n";
|
|
$grille=array();
|
|
$aireParCarre=array();
|
|
//préparer la grille dans un array
|
|
for($i=0;$i<$largeur;$i++){
|
|
for($j=0;$j<$hauteur;$j++){
|
|
$grille[$i][$j]=0; //0 -> case libre 1 -> case prise par un carré
|
|
}
|
|
}
|
|
|
|
//tirer en random l'aire de chaque carré
|
|
$aireRestante=$largeur * $hauteur;
|
|
for($i=1;$i<$nbeCarres;$i++){
|
|
$aireOK=false;
|
|
while($aireOK==false){
|
|
$aire=rand(2,$aireRestante - $nbeCarres + $i);
|
|
//on va éliminer quelques valeurs.
|
|
$aireOK=true;
|
|
if((in_array($aire,array(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97)))
|
|
&& ($aire>$largeur)
|
|
&& ($aire>$hauteur)){
|
|
/*
|
|
* C'est un nombre premier, donc le seul carré posssible aura un coté =1 et l'autre coté= aire.
|
|
* si ce dernier coté est supérieur aux cotés de la grille, on ne pourra jamais le placer.
|
|
*/
|
|
$aireOK=false;
|
|
}
|
|
}
|
|
$aireParCarre[]=$aire;
|
|
$aireRestante=$aireRestante-$aire;
|
|
//on remplit un passage un array contenant les diviseurs possibles de l'aire.
|
|
$diviseurs[$aire]=trouveDiviseurs($aire);
|
|
}
|
|
|
|
//le dernier carré prend l'aire restante
|
|
if($aireRestante < 2){goto a;}//dans les regles de zigazou, carré de taille 1 interdit
|
|
$aireParCarre[]=$aireRestante;
|
|
$diviseurs[$aireRestante]=trouveDiviseurs($aireRestante);
|
|
shuffle($aireParCarre);
|
|
|
|
foreach($aireParCarre as $carre){
|
|
//chercher la première position x,y libre
|
|
for($y=0;$y<$hauteur;$y++){
|
|
for($x=0;$x<$largeur;$x++){
|
|
|
|
if($grille[$x][$y]==0){
|
|
//tenter de placer le carré là
|
|
$largeurMax=largeurLibre($x,$y,$grille);
|
|
$hauteurMax=hauteurLibre($x,$y,$grille);
|
|
$largeurRetenue=0;
|
|
$hauteurRetenue=0;
|
|
//on place le carré avec la largeur la plus grande possible
|
|
foreach($diviseurs[$carre] as $div){
|
|
if(($div[0] <= $largeurMax) && ($div[1] <= $hauteurMax)){
|
|
$largeurRetenue=$div[0];
|
|
$hauteurRetenue=$div[1];
|
|
$xRetenu=$x;
|
|
$yRetenu=$y;
|
|
}
|
|
}
|
|
if($largeurRetenue > 0){
|
|
//placer le carré
|
|
//choisir un nombre au hazar dans la liste des carrés qu'on va placer
|
|
$placeIndice=rand(1,$largeurRetenue*$hauteurRetenue);
|
|
$count=1;
|
|
for($xTemp=$xRetenu;$xTemp<$xRetenu + $largeurRetenue;$xTemp++){
|
|
for($yTemp=$yRetenu;$yTemp<$yRetenu + $hauteurRetenue;$yTemp++){
|
|
$grille[$xTemp][$yTemp]=1;
|
|
if($count==$placeIndice){
|
|
$buff.=$largeurRetenue*$hauteurRetenue." ".$xTemp." ".$yTemp."\n";
|
|
}
|
|
$count++;
|
|
}
|
|
}
|
|
break 2; //le carré est placé, sert à rien de tester les autres cases.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if($largeurRetenue==0){
|
|
//limpossibilité de placer le carré. retentons aec un autre tirage d'aires
|
|
goto a;
|
|
}
|
|
}
|
|
|
|
return $buff;
|
|
}
|
|
function trouveDiviseurs($nombre){
|
|
// Retourne les couples largeur et hauteur pour une aire donnée
|
|
static $diviseurs = array();
|
|
if(isset($diviseurs[$nombre])){
|
|
//si jamais ça a déja été calculé
|
|
return $diviseurs[$nombre];
|
|
}
|
|
$diviseurs[$nombre]=array();
|
|
for($i=1;$i<=sqrt($nombre);$i++){
|
|
if (fmod($nombre,$i)==0){
|
|
$diviseurs[$nombre][]=array($i,$nombre/$i);
|
|
}
|
|
}
|
|
return $diviseurs[$nombre];
|
|
}
|
|
function largeurLibre($posX,$posY,$grille){
|
|
$count=0;
|
|
while(isset($grille[$posX+$count][$posY])){
|
|
if($grille[$posX+$count][$posY]>0){
|
|
break;
|
|
}
|
|
$count ++;
|
|
}
|
|
return $count;
|
|
}
|
|
function hauteurLibre($posX,$posY,$grille){
|
|
$count=0;
|
|
while(isset($grille[$posX][$posY+$count])){
|
|
if ($grille[$posX][$posY+$count]>0){
|
|
break;
|
|
}
|
|
$count ++;
|
|
}
|
|
return $count;
|
|
}
|