I138 Le carré Breton
Solution proposée par Régis Schoonheere
En réponse au problème du carré breton, je vous propose la solution suivante en 10 coups : 8, 5, 2, 5, 8, 6, 3, 6, 5, 1.
J'ai écrit un programme en C++ qui utilise une fonction récursive de choix d'un mouvement. L'algorithme choisi essaie d'optimiser une quantité que j'ai appelée distance dans le programme et qui n'est pas celle décrite dans l'énoncé mais le nombre minimum de mouvements pour amener une case donnée à être noire sur fond blanc.
Annexe
Programme en langage C++
using namespace std;
#include <vector>
#include <string>
#include <iostream>
#include <math.h>
// Données initiales
int fond[4][4]={{3,2,1,2},{3,2,3,1},{0,0,2,1},{0,0,0,0}};
int coul[4][4]={{0,4,3,4},{0,0,1,3},{1,2,4,3},{1,2,2,1}};
char let[4][4]={{'B','D','O','L'},{'A','H','C','J'},{'I','G','N','K'},{'M','F','E','P'}};
// variables globales
int mini=100; // Nombre mini de mouvements pour arriver au résultat int result[100]; // Sauvegarde des mouvements de chaque niveau int minscore; // Distance minimum atteinte
int nbcoups=0; // Nombre mini de mouvements pour atteindre la distance mini
// Calcul de la distance = nombre mini de mouvements pour atteindre les couleurs de fond et de caractère finales depuis le couleurs ff (fond) et cc
(caractère)
int dist(int ff,int cc) {
int depf=-ff; // Mouvements pour la couleur de fond if(depf<0)
depf+=4;
int ccf=cc+depf;
if(ccf>4) ccf-=5;
int depc=ccf-1; // Mouvements pour la couleur de caractère if(depc<0)
depc+=5;
return (depf+4*depc);
}
// Fonction récursive de choix d'un mouvement
void place(int f[4][4], int c[4][4], char l[4][4],int sc, int niv) {
int nf[4][4], nc[4][4];
char nl[4][4];;
int lig,col;
if(!sc) // Si score nul, résultat atteint {
if(niv<mini) // Nombre de mouvements inférieur au mini {
mini=niv;
cout << endl << "Solution en " << niv << " coups : ";
for(int i=0;i<niv;i++)
cout << result[i] << " ";
cout << endl;
} return;
}
if(niv>=mini) // Nombre de muvements supérieur au mini, abandon
return;
if(sc<minscore) // Meilleure distance {
minscore=sc;
nbcoups=niv;
cout << "Score " << sc << " en " << niv << " coups : ";
for(int i=0;i<niv;i++)
cout << result[i] << " ";
cout << endl;
}
else if(sc==minscore && niv<nbcoups) // Même distance mais nombre de coups inférieur {
nbcoups=niv;
cout << "Score " << sc << " en " << niv << " coups : ";
for(int i=0;i<niv;i++)
cout << result[i] << " ";
cout << endl;
}
// calcul des distances pour les 9 déplacements int ibest=-1,best=sc,tscore[9];
for(int i=0;i<9;i++) {
int score=sc;
lig=i/3;
col=i%3;
// Retrancher les distances des 4 cases concernées du score total for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
score-= dist(f[lig+j][col+k],c[lig+j][col+k]);
// Copie des tableaux de lettres et de couleurs memcpy(nf,f,16*sizeof(int));
memcpy(nc,c,16*sizeof(int));
memcpy(nl,l,16*sizeof(char));
// Mouvement
nf[lig][col]=f[lig+1][col]==3?0:f[lig+1][col]+1;
nf[lig][col+1]=f[lig][col]==3?0:f[lig][col]+1;
nf[lig+1][col+1]=f[lig][col+1]==3?0:f[lig][col+1]+1;
nf[lig+1][col]=f[lig+1][col+1]==3?0:f[lig+1][col+1]+1;
nc[lig][col]=c[lig+1][col]==4?0:c[lig+1][col]+1;
nc[lig][col+1]=c[lig][col]==4?0:c[lig][col]+1;
nc[lig+1][col+1]=c[lig][col+1]==4?0:c[lig][col+1]+1;
nc[lig+1][col]=c[lig+1][col+1]==4?0:c[lig+1][col+1]+1;
nl[lig][col]=l[lig+1][col];
nl[lig][col+1]=l[lig][col];
nl[lig+1][col+1]=l[lig][col+1];
nl[lig+1][col]=l[lig+1][col+1];
// Ajouter les distances des 4 cases au score total for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
score+= dist(nf[lig+j][col+k],nc[lig+j][col+k]);
tscore[i]=score;
}
// Recherche de la meilleure distance while(true)
{
best=sc; // Score maxi autorisé
ibest=-1;
for(int i=0;i<9;i++)
if(tscore[i]<best) // Meilleur score {
best=tscore[i];
ibest=i;
}
if(ibest<0) // Pas de meilleur score
return;
tscore[ibest]=101; // Supprimer ce mouvement du tableau des scores // Créer les nouveaux tableaux de données pour ce mouvement
lig=ibest/3;
col=ibest%3;
memcpy(nf,f,16*sizeof(int));
memcpy(nc,c,16*sizeof(int));
memcpy(nl,l,16*sizeof(char));
nf[lig][col]=f[lig+1][col]==3?0:f[lig+1][col]+1;
nf[lig][col+1]=f[lig][col]==3?0:f[lig][col]+1;
nf[lig+1][col+1]=f[lig][col+1]==3?0:f[lig][col+1]+1;
nf[lig+1][col]=f[lig+1][col+1]==3?0:f[lig+1][col+1]+1;
nc[lig][col]=c[lig+1][col]==4?0:c[lig+1][col]+1;
nc[lig][col+1]=c[lig][col]==4?0:c[lig][col]+1;
nc[lig+1][col+1]=c[lig][col+1]==4?0:c[lig][col+1]+1;
nc[lig+1][col]=c[lig+1][col+1]==4?0:c[lig+1][col+1]+1;
nl[lig][col]=l[lig+1][col];
nl[lig][col+1]=l[lig][col];
nl[lig+1][col+1]=l[lig][col+1];
nl[lig+1][col]=l[lig+1][col+1];
result[niv]=ibest+1; // Stocker ce mouvement pour ce niveau // Niveau suivant
place(nf,nc,nl,best,niv+1);
} }
int main() {
// Calcul du score initial
minscore=0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++) {
minscore+=dist(fond[i][j],coul[i][j]);
}
cout << "Score initial : " << minscore << endl;
// Choisir le premier mouvement place(fond,coul,let,minscore,0);
}