Montage final : Résolu ! Voici une solution.
GNAWN|jOULE
RACHE|EUROS
IDIOT|STEAN
PINOT|TRAvE
TRIPY|SOLES
-----+-----
HOWFF|ZEBRA
AGILE|EQUID
CIVIL|BUXOM
EVENT|RIOJA
KEDGY|ADMAN
Voici une photo de sa construction avec mon jeu de scrabble. http://twitpic.com/3wn7iu
Celui-ci a été facile à trouver une fois que j'ai eu la bonne approche, donc je parie que vous pourriez en trouver beaucoup d'autres de cette façon. Voir ci-dessous pour la méthodologie.
Construire un arbre de préfixes à partir du dictionnaire des mots de 5 lettres pour chaque ligne et chaque colonne. De manière récursive, un placement de tuile donné est valide s'il forme des préfixes valides pour sa colonne et sa ligne, et si la tuile est disponible, et si le placement de tuile suivant est valide. Dans le cas de base, il est valide s'il n'y a plus de tuile à placer.
Il est probablement judicieux de trouver toutes les planches 5x5 valides, comme Glenn l'a dit, et de voir si quatre d'entre elles peuvent être combinées. Recourir à une profondeur de 100 n'a pas l'air amusant.
Edit : Voici la version 2 de mon code pour cela.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef union node node;
union node {
node* child[26];
char string[6];
};
typedef struct snap snap;
struct snap {
node* rows[5];
node* cols[5];
char tiles[27];
snap* next;
};
node* root;
node* vtrie[5];
node* htrie[5];
snap* head;
char bag[27] = {9,2,2,4,12,2,3,2,9,1,1,4,2,6,8,2,1,6,4,6,4,2,2,1,2,1,2};
const char full_bag[27] = {9,2,2,4,12,2,3,2,9,1,1,4,2,6,8,2,1,6,4,6,4,2,2,1,2,1,2};
const char order[26] = {16,23,9,25,21,22,5,10,1,6,7,12,15,2,24,3,20,13,19,11,8,17,14,0,18,4};
void insert(char* string){
node* place = root;
int i;
for(i=0;i<5;i++){
if(place->child[string[i] - 'A'] == NULL){
int j;
place->child[string[i] - 'A'] = malloc(sizeof(node));
for(j=0;j<26;j++){
place->child[string[i] - 'A']->child[j] = NULL;
}
}
place = place->child[string[i] - 'A'];
}
memcpy(place->string, string, 6);
}
void check_four(){
snap *a, *b, *c, *d;
char two_total[27];
char three_total[27];
int i;
bool match;
a = head;
for(b = a->next; b != NULL; b = b->next){
for(i=0;i<27; i++)
two_total[i] = a->tiles[i] + b->tiles[i];
for(c = b->next; c != NULL; c = c->next){
for(i=0;i<27; i++)
three_total[i] = two_total[i] + c->tiles[i];
for(d = c->next; d != NULL; d = d->next){
match = true;
for(i=0; i<27; i++){
if(three_total[i] + d->tiles[i] != full_bag[i]){
match = false;
break;
}
}
if(match){
printf("\nBoard Found!\n\n");
for(i=0;i<5;i++){
printf("%s\n", a->rows[i]->string);
}
printf("\n");
for(i=0;i<5;i++){
printf("%s\n", b->rows[i]->string);
}
printf("\n");
for(i=0;i<5;i++){
printf("%s\n", c->rows[i]->string);
}
printf("\n");
for(i=0;i<5;i++){
printf("%s\n", d->rows[i]->string);
}
exit(0);
}
}
}
}
}
void snapshot(){
snap* shot = malloc(sizeof(snap));
int i;
for(i=0;i<5;i++){
printf("%s\n", htrie[i]->string);
shot->rows[i] = htrie[i];
shot->cols[i] = vtrie[i];
}
printf("\n");
for(i=0;i<27;i++){
shot->tiles[i] = full_bag[i] - bag[i];
}
bool transpose = false;
snap* place = head;
while(place != NULL && !transpose){
transpose = true;
for(i=0;i<5;i++){
if(shot->rows[i] != place->cols[i]){
transpose = false;
break;
}
}
place = place->next;
}
if(transpose){
free(shot);
}
else {
shot->next = head;
head = shot;
check_four();
}
}
void pick(x, y){
if(y==5){
snapshot();
return;
}
int i, tile,nextx, nexty, nextz;
node* oldv = vtrie[x];
node* oldh = htrie[y];
if(x+1==5){
nexty = y+1;
nextx = 0;
} else {
nextx = x+1;
nexty = y;
}
for(i=0;i<26;i++){
if(vtrie[x]->child[order[i]]!=NULL &&
htrie[y]->child[order[i]]!=NULL &&
(tile = bag[i] ? i : bag[26] ? 26 : -1) + 1) {
vtrie[x] = vtrie[x]->child[order[i]];
htrie[y] = htrie[y]->child[order[i]];
bag[tile]--;
pick(nextx, nexty);
vtrie[x] = oldv;
htrie[y] = oldh;
bag[tile]++;
}
}
}
int main(int argc, char** argv){
root = malloc(sizeof(node));
FILE* wordlist = fopen("sowpods5letters.txt", "r");
head = NULL;
int i;
for(i=0;i<26;i++){
root->child[i] = NULL;
}
for(i=0;i<5;i++){
vtrie[i] = root;
htrie[i] = root;
}
char* string = malloc(sizeof(char)*6);
while(fscanf(wordlist, "%s", string) != EOF){
insert(string);
}
free(string);
fclose(wordlist);
pick(0,0);
return 0;
}
Il essaie d'abord les lettres peu fréquentes, ce qui n'est plus une bonne idée. Il commence à s'embourber avant d'arriver à sortir des tableaux commençant par x. Après avoir vu combien de blocs 5x5 il y avait, j'ai modifié le code pour simplement lister tous les blocs 5x5 valides. J'ai maintenant un fichier texte de 150 Mo contenant les 4 430 974 solutions 5x5.
J'ai également essayé avec une récurrence de 100 tuiles, et cela fonctionne toujours.
Edit 2 : Voici la liste de tous les blocs 5x5 valides que j'ai générés. http://web.cs.sunyit.edu/~levyt/solutions.rar
Edit 3 : Hmm, il semble qu'il y avait un bug dans mon suivi de l'utilisation des tuiles, car je viens de trouver un bloc dans mon fichier de sortie qui utilise 5 Zs.
COSTE
ORCIN
SCUZZ
TIZZY
ENZYM
Edit 4 : Voici le produit final.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef union node node;
union node {
node* child[26];
char string[6];
};
node* root;
node* vtrie[5];
node* htrie[5];
int score;
int max_score;
char block_1[27] = {4,2,0,2, 2,0,0,0,2,1,0,0,2,1,2,0,1,2,0,0,2,0,0,1,0,1,0};//ZEBRA EQUID BUXOM RIOJA ADMAN
char block_2[27] = {1,0,1,1, 4,2,2,1,3,0,1,2,0,1,1,0,0,0,0,1,0,2,1,0,1,0,0};//HOWFF AGILE CIVIL EVENT KEDGY
char block_3[27] = {2,0,1,1, 1,0,1,1,4,0,0,0,0,3,2,2,0,2,0,3,0,0,1,0,1,0,0};//GNAWN RACHE IDIOT PINOT TRIPY
//JOULE EUROS STEAN TRAVE SOLES
char bag[27] = {9,2,2,4,12,2,3,2,9,1,1,4,2,6,8,2,1,6,4,6,4,2,2,1,2,1,2};
const char full_bag[27] = {9,2,2,4,12,2,3,2,9,1,1,4,2,6,8,2,1,6,4,6,4,2,2,1,2,1,2};
const char order[26] = {16,23,9,25,21,22,5,10,1,6,7,12,15,2,24,3,20,13,19,11,8,17,14,0,18,4};
const int value[27] = {244,862,678,564,226,1309,844,765,363,4656,909,414,691,463,333,687,11998,329,218,423,536,1944,1244,4673,639,3363,0};
void insert(char* string){
node* place = root;
int i;
for(i=0;i<5;i++){
if(place->child[string[i] - 'A'] == NULL){
int j;
place->child[string[i] - 'A'] = malloc(sizeof(node));
for(j=0;j<26;j++){
place->child[string[i] - 'A']->child[j] = NULL;
}
}
place = place->child[string[i] - 'A'];
}
memcpy(place->string, string, 6);
}
void snapshot(){
static int count = 0;
int i;
for(i=0;i<5;i++){
printf("%s\n", htrie[i]->string);
}
for(i=0;i<27;i++){
printf("%c%d ", 'A'+i, bag[i]);
}
printf("\n");
if(++count>=1000){
exit(0);
}
}
void pick(x, y){
if(y==5){
if(score>max_score){
snapshot();
max_score = score;
}
return;
}
int i, tile,nextx, nexty;
node* oldv = vtrie[x];
node* oldh = htrie[y];
if(x+1==5){
nextx = 0;
nexty = y+1;
} else {
nextx = x+1;
nexty = y;
}
for(i=0;i<26;i++){
if(vtrie[x]->child[order[i]]!=NULL &&
htrie[y]->child[order[i]]!=NULL &&
(tile = bag[order[i]] ? order[i] : bag[26] ? 26 : -1) + 1) {
vtrie[x] = vtrie[x]->child[order[i]];
htrie[y] = htrie[y]->child[order[i]];
bag[tile]--;
score+=value[tile];
pick(nextx, nexty);
vtrie[x] = oldv;
htrie[y] = oldh;
bag[tile]++;
score-=value[tile];
}
}
}
int main(int argc, char** argv){
root = malloc(sizeof(node));
FILE* wordlist = fopen("sowpods5letters.txt", "r");
score = 0;
max_score = 0;
int i;
for(i=0;i<26;i++){
root->child[i] = NULL;
}
for(i=0;i<5;i++){
vtrie[i] = root;
htrie[i] = root;
}
for(i=0;i<27;i++){
bag[i] = bag[i] - block_1[i];
bag[i] = bag[i] - block_2[i];
bag[i] = bag[i] - block_3[i];
printf("%c%d ", 'A'+i, bag[i]);
}
char* string = malloc(sizeof(char)*6);
while(fscanf(wordlist, "%s", string) != EOF){
insert(string);
}
free(string);
fclose(wordlist);
pick(0,0);
return 0;
}
Après avoir découvert combien de blocs il y avait (près de 2 milliards et toujours en cours de calcul), je me suis mis à essayer de trouver certains types de blocs, en particulier ceux qui sont difficiles à construire et qui utilisent des lettres peu communes. J'espérais que si je me retrouvais avec un ensemble de lettres assez bénin pour le dernier bloc, le vaste espace de blocs valides en contiendrait probablement un pour cet ensemble de lettres.
J'ai attribué à chaque carreau une valeur inversement proportionnelle au nombre de mots de 5 lettres dans lesquels il apparaît. Ensuite, lorsque je trouvais un bloc valide, j'additionnais les valeurs des tuiles, et si le score était le meilleur que j'avais vu jusqu'alors, j'imprimais le bloc.
Pour le premier bloc, j'ai enlevé les tuiles vierges, pensant que le dernier bloc aurait le plus besoin de cette flexibilité. Après l'avoir laissé tourner jusqu'à ce que je n'aie pas vu apparaître un meilleur bloc pendant un certain temps, j'ai sélectionné le meilleur bloc, j'ai retiré les tuiles qu'il contenait du sac et j'ai relancé le programme, obtenant ainsi le deuxième bloc. J'ai répété cela pour le troisième bloc. Puis, pour le dernier bloc, j'ai rajouté les tuiles vides et utilisé le premier bloc valide qu'il a trouvé.
2 votes
Ma première inclination est que vous pouvez marquer les mouvements potentiels horizontaux en fonction du nombre de mots valides ayant les préfixes faits verticalement.
0 votes
Ce que Null Set a dit, et vous pouvez aussi éliminer des sous-ensembles entiers de recherches si vous pouvez démontrer qu'il n'y a aucun possible mots qui peuvent s'adapter dans les emplacements verticaux pour un ensemble particulier de mots horizontaux en haut.
0 votes
Tu peux également chercher à ajouter de la valeur en trouvant des endroits valides pour placer les lettres difficiles à utiliser.
0 votes
Vous avez oublié de lister combien de V'il y a.
0 votes
@NullSet Merci d'avoir repéré. J'ai corrigé la liste (mis 2 X par erreur, donc j'ai encore compté 26 lorsque j'ai revérifié). La liste provient de ici.
1 votes
Il m'a fallu quelques essais pour comprendre votre première phrase. Voulez-vous dire "vérifier que vous avez un ensemble complet de tuiles de Scrabble"? Je suis assez sûr mais pas assez sûr pour modifier pour la clarté.
0 votes
@Ben Pour être tout à fait honnête, j'ai collé cette phrase presque intégralement de mon ami car je ne suis pas accro au scrabble. Tu peux surtout ignorer cette ligne. Le cœur du problème est de disposer les tuiles disponibles (comptées énumérées) pour former les quatre grilles de 5x5 qui répondent aux critères.
0 votes
J'ai mis à jour ma réponse avec quelques réflexions sur la recherche des bonnes quatre solutions 5x5 et les calculs parallèles.
0 votes
Doit-il respecter les règles normales? C'est-à-dire, s'il est placé, doit-il se tenir au lieu de la même lettre dans les deux directions?
0 votes
@biziclop Oui, même lettre dans les deux directions.
2 votes
Si quelqu'un était curieux, j'ai finalement compté qu'il y avait 2 693 056 976 blocs 5x5 valides. Soit cela, soit 6 988 024 272 car il peut avoir débordé, mais je pense que c'est peu probable.
0 votes
Je connais seulement l'un des 20 mots dans votre exemple! 'pinot' :(
0 votes
Pour information, la liste des mots de Scrabble à laquelle vous accédez est une version Europing que la plupart utilisent TWL06 qui peut être consultée ici freescrabbledictionary.com/twl06