En fait afin de faciliter le programme, et de rendre le casse-tête IRL plus difficile j'ai une alternative. C'est de dire qu'une bonne ligne est composée de 2 couleurs, mais en 2/2 (ou bien en 1/3).
Par exemple en 2/2 le nombre de bonnes couches est de 342; donc 1E+10 itérations, donc faisable à faire tourner, et voir si il y a une solution.
Oui autant pour moi !Envoyé par Sve@r
Je t'ai induis en erreur avec mon schéma, je me permets d'expliquer mon script :
1. Création des 42 lignes possibles
2. Création des 101 274 faces possibles, mises dans la liste ARRAYS
2.a Les faces sont mises dans la liste ARRAYS
2.b Chaque face est mise dans 4 dictionnaires en lien avec leurs arrêtes, DICO_BOTTOM = {array[-1]:['''toutes_les_arrays_dont_la_derniere_ligne==array[-1]''']}, DICO_LEFT= {array[:,0]:['''toutes_les_arrays_dont_la_colonne_0==array[:,0]''']}, ...,
(array[:,0] nécessite numpy)
2.c Une idée : Mettre chaque array dans 3 dictionnaires en lien avec les couleurs, DICO_0 = {0:['''toutes_les_arrays_ne_contenant_pas_de_0'''], 1:['''toutes_les_arrays_contenant_1_0''']} , ...,
3. Création des X cubes possibles, comme suit :
• Pour chaque array_1 in ARRAYS :
• Pour chaque array_3 in DICOS["TOP"][array_1[3]]: #Càd pour chaque face dont la première ligne vaut la dernière ligne de la première face
→ On extrait toutes les array_2 et array_4 compatibles avec array_1 et array_3, càd que la dernière colonne de array_2 doit être la même que la première colonne de array_3, etc... Tout ça grâce à la fonction get_arrays_2_4().
• Pour chaque array_2 in ARRAYS _2:
• Pour chaque array_4 in ARRAYS _4:
→ On vérifie que l'ensemble de ces 4 faces obtenues jusque là respectent bien les règles de départ, càd moins de 22 zéros, 22 uns, 23 deux dans le cube.* Si non on ne poursuit pas le parcours dans cette branche.
- Pour vérifier cela j'ai choisi de découper les 6 faces comme dans le schéma plus haut : lien
- Tout ça grâce à la fonction test_intermediaire(),
• Je reproduis la même étape pour chaque array_5 et array_6 que précédemment:
→ On extrait toutes les array_5 et toutes les array_6 compatibles avec les array_1, array_2, array_3, array_4
→ On vérifie que l'ensemble des faces obtenues respectent les règles
Il y a donc 2 schémas à avoir en tête celui susmentionné et celui-ci :
Correspondant au array_1, array_2, ..., array_6 cités plus haut.
* Dans le script je me suis trompé d'ailleurs ! Conséquence de la correction => Perte importante de performance
Il serait peut-être préférable de choisir la méthode de __Obi__ qui réfléchi en tranche de 4 et non en face de 6, même s'il s'agit bien des mêmes 101274 tableaux 2D, il faudrait y ajouter une autre logique supplémentaire :
- Commencer par itérer toutes les faces
- Faire correspondre toutes les tranches #Càd la ligne_0 de la tranche_0 devra être égale à la ligne_0 de la face, la ligne_0 de la tranche_1 égale à la ligne_1 de la face, ...
![]()
A-t-il vraiment besoin d'être complexifié ?
J'ai aucune idée du nombre de solutions possibles avec les conditions de départ que tu nous as donné.
Si le gars est méthodique comme un script il va en mettre du temps pour trouver la bonne combinaison ! Qq 400 000 tests avant de trouver la première avec mon script. ^^
Je rappelle le sujet du casse tete, ce n'est pas un rubik, c'est un assemblage de 64 petits cube, 21 bleu, 21 rouge et 22 jaunes.
J'ai regardé ton programme Narvalo, et je suis impressionné par ta programmation; et comme je suis un python-noob je n'ai pas encore tout saisi mais il me semble que tu a programmer par face, et donc il n'y jamais les 21/21/22 (d'ou "<=").
Yeap !et donc il n'y jamais les 21/21/22 (d'ou "<=")
Je ne prends pas en considération les 4 cubes du centre puisque non visible de l'extérieur.
C'est triché ?
Bon moi j'ai paumé mon décapsuleur fétiche ! Vous savez pas où il est ?![]()
Pas vraiment le premier schéma. Mais ton second est plus explicite (joli le gif animé mais ma modif a fait perdre l'animation). Parce que la première arrête c'est R, J, R, J puis J, B, B, B soit (si on la prend d'un coup) 3 couleurs ; ce qui ne matche pas la règle.
Donc ma question demeure: doit-on associer les faces entre elles ou bien considérer chacune comme autant de puzzles isolés...
![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Alors moi j'ai pas compris la règle ainsi je me suis arrêté au face.
Qu'en est-il vraiment, Obi ?
bonjour
Autre façon, pas algorithmique et sans doute pas optimale : faire une recherche aléatoire
Il ne faut pas 3 ans de calculs pour trouver des réponses, et on doit sans doute trouver une réponse dans un temps humain (toutes: certainement pas!).
Juste une permutation aléatoire de 2 cubes présents en surface
Ici, le script ne teste que les lignes (oui beaucoup beaucoup plus facile) mais il tient bien compte de la 3D
il a l'air de fonctionner avec un cube 3x3 et 4x4 ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 #!/usr/bin/env python from enum import Enum, auto from random import randint class Color(Enum): NONE = 0 JAUNE = 1 ROUGE = 2 BLEU = 3 def __str__(self): if self == Color.ROUGE: return "🔴" if self == Color.JAUNE: return "🟢" if self == Color.BLEU: return "🔵" return "◾️" class FaceName(Enum): HAUT = auto() BAS = auto() AVANT = auto() POSTERIEURE = auto() GAUCHE = auto() DROITE = auto() class Point: """mini-cubes""" def __init__(self, x, y, z, color=Color.NONE) -> None: self.x = x self.y = y self.z = z self.color = color def __str__(self) -> str: return f"{self.x}/{self.y}/{self.z} {self.color}" def in_face(self, cubesize) -> list[FaceName]: """retourne position du mini-cube""" ret = [] cubesize -= 1 if self.z == 0: ret.append(FaceName.HAUT) if self.z == cubesize: ret.append(FaceName.BAS) if self.y == cubesize: ret.append(FaceName.AVANT) if self.y == 0: ret.append(FaceName.POSTERIEURE) if self.x == 0: ret.append(FaceName.GAUCHE) if self.x == cubesize: ret.append(FaceName.DROITE) return ret class Cube: def __init__(self, size: int) -> None: self.size = size self.cubes = [] x, y, z = 0, 0, 0 for y in range(self.size): for x in range(self.size): for z in range(self.size): self.cubes.append( Point(x, y, z, Color.NONE) ) print("Nombre de cubes:", len(self.cubes)) def set_colors(self, bleu=8, jaune=9, rouge=9): # TODO set bon nombre de couleurs self._set_color(Color.BLEU, bleu) self._set_color(Color.JAUNE, jaune) self._set_color(Color.ROUGE, rouge) print() l = set(p for p in self.cubes if p.color == Color.BLEU) print(Color.BLEU, len(l), l) l = set(p for p in self.cubes if p.color == Color.ROUGE) print(Color.ROUGE, len(l), l) l = set(p for p in self.cubes if p.color == Color.JAUNE) print(Color.JAUNE, len(l), l) l = set(p for p in self.cubes if p.color == Color.NONE) print(Color.NONE, len(l), l) def permuter(self, mauvais): if mauvais: ls = mauvais else: ls = [p for p in self.cubes if p.color != Color.NONE] a : Point = ls[randint(0, len(ls)-1)] b = a ls = [p for p in self.cubes if p.color != a.color and p.color != Color.NONE] while a == b: b = ls[randint(0, len(ls)-1)] if a.color == b.color: b = False continue a.color, b.color = b.color, a.color print(a,"<->", b, end=", ") if b: return set(a.in_face(self.size) + b.in_face(self.size)) # pas utilisé # retourne faces de a et b pour ne tester quelles def face_is_valid(self, namef: FaceName) -> tuple[bool, list]: #TODO bien d'autres tests f = self.get_face(namef) # Uniquement test d'une ligne for x in range(0, self.size): line = set(p.color for p in f if p.x == x) if len(line) >= len(Color)-1: ls = [p for p in f if p.x == x] print(f" # {namef}, face non valide, ligne:", end=" ") for p in ls: print(p, end= " ") print("") return False, ls return True, [] def is_valid(self): for fn in FaceName: ok, mauvais = self.face_is_valid(fn) if not ok: return False, mauvais return True, [] def _set_color(self, color: Color, maxi: int = 9): ok, n = 1, 0 anti_crash = 2000 while True: n += 1 if n > anti_crash: # TODO if not calculer_le_restant_disponible(): return print("oops, ne reste plus de mini-cube pour assigner la couleur !") return minicube: Point = self.cubes[randint(0, len(self.cubes)-1)] if minicube.color != Color.NONE: continue if not minicube.in_face(self.size): # mini-cube à l'intérieur continue minicube.color = color if ok == maxi: break ok += 1 def get_face(self, face: FaceName, display=False) -> list[Point]: """retourne les mini-cubes d'une face""" points = [p for p in self.cubes if face in p.in_face(self.size)] if display: print(face.name) for i, p in enumerate(points): print(p, end="\n" if (i+1) % self.size == 0 else " ") return points def __str__(self): return str(self.cubes) def display(self): print() self.get_face(FaceName.HAUT, True) self.get_face(FaceName.BAS, True) self.get_face(FaceName.GAUCHE, True) self.get_face(FaceName.DROITE, True) self.get_face(FaceName.AVANT, True) self.get_face(FaceName.POSTERIEURE, True) # MAIN jeux = Cube(3) jeux.set_colors(8, 9, 9) jeux = Cube(4) jeux.set_colors(21, 21, 22) jeux.display() i = 1 mauvais = [] while True: print(f"----- permuter ({i})...") jeux.permuter(mauvais) ok, mauvais = jeux.is_valid() # retourne mauvaise face if ok: print(f"YES !, au bout de {i} fois") jeux.display() exit(0) i += 1 exit(1)
wankenobi, vous êtes mon seul espoare...
Oui, comme le bogom sort...![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
@papajoker Je vois que tu t'es pris au jeu aussi ! =)
Avec des classes itou itou !!
C'est quoi ça, monsieur, svp ?
a : Point
Les annotations (v3.5). Tu indiques le type prévu pour la variable (toto:int=123), ou éventuellement les types qu'elle est susceptible avoir (toto:(int, str)=123; toto="Hello").
Tu peux l'annoter de tous les types connus en Python ("int", "float", "bytes", "str", "bool", "tuple", "list", "set", "dict" et "None"), plus "callable" (fonction), "map", "object", "any" (n'importe quoi) plus tes propres noms d'objets.
Ca s'applique aussi aux paramètres de fonctions et à ses retours => def toto(v:int) -> str: return str(v).
Et depuis la v3.8, si une variable est annotée list (ou dict ou autre ensemble), tu peux aussi préciser le type de ses éléments => toto:list[int, float, str]=[1, 2.3, "Hello"] et ce, à l'infini (toto:list[int, float, str, list[str, float, int]]=[123, 4.5, "Hello", ["World !!!", 5.4, 321]]).
Mais ce n'est (pour l'instant) pas contrôlé. Tu peux donc écrire toto:int="Hello" sans souci.
Perso j'ai pas accroché (j'ai tenté au début de le faire, j'ai rapidement abandonné). Goûts et couleurs... Les éditeurs spécifiques Python lisent les annotations et les utilisent pour l'autocomplétion => tu annotes ta variable comme étant de la classe "Point", l'éditeur te proposera ensuite les méthodes de la classe quand tu utiliseras la variable dans la suite du code.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Ok mais du coup, j'ai du mal à comprendre ça:
La variable a est une instance de classe Point et vaut une liste
Code : Sélectionner tout - Visualiser dans une fenêtre à part a : Point = ls[randint(0, len(ls)-1)]![]()
Déjà comme je l'ai dit, les annotations ne sont pas checkées. Python checke juste la syntaxe mais pas la correspondance entre ce qui est écrit et le type réel de la variable (à mon avis s'il le faisait les perfs deviendraient catastrophiques). Donc tu écris a:Point="Hello" il s'en cogne.
Toutefois "ls" est une liste de Point (liste en compréhension à partir de self.Cubes et self.Cubes, rempli dans le __init__ via append(Point(...))) donc ls[truc] est bien un point. Il faudrait annoter "mauvais", paramètre de la méthode permuter() et autre possibilité pour remplir "ls", comme mauvais:list[Point] pour que ce soit plus visible.
C'est pour ça que ça me gonfle les annotations. Si on en met sur toutes les variables, tous les paramètres, toutes les fonctions/méthodes ça devient illisible ; et pas assez alors pourquoi en mettre sur X et pas sur Y...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Oui, il faut bien prendre en compte les 8 cubes du centre. Et pour être tout à fait complet, il faut aussi prendre en compte les 4 lignes qui relie les coins totalement opposés (les grandes diagonales)
Le cube 4x4x4 est une variante d'un casse-tête que l'on ma offert il y a longtemps , et qui est 49lines, constitué de 27 petit cube en bois de 3 couleurs différentes. Et la consigne était faire les 49 lignes (horizontales, verticales, diagonales, et grandes diagonales) en respectant la consigne de 2 couleurs par ligne. C'est un véritable casse-tête qui m'a tenu tête pendant des années. Et la j'essaie d'étudier une version inventée en 4x4x4 afin de voir si il y a au moins une solution et le degré de difficulté: c'est à dire le nombre de solutions, en fonction du nombre de permutations possible.
Le nombre de permutations possibles est 4.3E+28 [64!/(21!x21x22!)]
Et j'aimerai trouvé le nombre de solutions afin de connaitre le ratio, pou déterminer le degré de difficulté.
Par exemple pour la version 3x3x3, le nombre de permutation est de 2E+11 et le nombre de solutions 576, soit 1 chance sur 400 000 000 de trouver la solution au hasard.
ici, cette annotation est juste pour faciliter la lecture code puisqu'une variable du nom de "a" est tous sauf loquace
Cette version a été réécrite juste avant de poster ici, auparavant "mauvais" n'était que le "nom" de la face alors que maintenant mauvais est une liste (tous les cubes d'une mauvaise ligne). C'était une réécriture rapide, je n'ai pas regardé les annotations sur cette partie réécrite.
Pas sûr que ce soit une entrée optimale, on pourrait par exemple aussi entrer pour "b"(second choix pour la permutation) une liste d'autres lignes non valides. Mais ne jamais casser une (autre) ligne valide devrait amener à zéro solution (il me semble)
Tu n'as pas trouvé qu'une solution au "simple" en des années ?Envoyé par ___Obi___
Le nombre de solutions en fonction des permutations possibles ne me semble pas forcément un critère : l'humain va réfléchir donc optimiser ces permutations
Il faudrait peut-être déjà partir avec moins de contraintes (supprimer les diagonales) ? et voir si c'est déjà humainement faisable : avec mon script, sur une seule contrainte ligne (si mon code est bon ?) il faut déjà plus de 20 000 permutations… (si nous étions aussi bête que mon script, on est déjà plus dans le casse-tête mais dans de la torture )
ps: mon script fonctionne aussi avec 3x3, et ici il trouve une solution avec 250 permutations, donc on peut faire le rapport cases/permutations (ici*: difficulté multipliée par 100) (avec une seule contrainte - mais pas sûr que d'ajouter des contraintes change ce rapport dans le bon sens)
@Papajoker: j'ai fait tourner ton programme et il sort une liste. Je pense effectivement que l'aléatoire doit permettre de trouver une solution relativement rapidement.
Mais dans la sortie du programme je ne comprends pourquoi il y a comme 6 faces de 16. La bonne sortie devrait être plutôt 4 couches de 16 ?
Et j'ai donc l'impression que ce script ne prend pas en compte les 8 cubes du centre.
Et les faces trouvées sont fausses (il y a parfois 3 couleurs)
en ligne 75, rouge =9 ? ou bien 10 ?
@tous: encore merci pour vos programmes et commentaires. Je n'avais pas conscience de cette diversité/richesse possible de mode programmation pour un même problème a priori si simple.
Je vais m'orienter vers une méthode aléatoire dans un premier temps (avec toutes les lignes : horizontales/verticales, petites diagonales et grandes diagonales); avant de chercher tout de suite le nombre de solutions.
Les couleurs sont assignées ligne 188 ! jeux.set_colors(21, 21, 22)En effet, c'est dans le codeEt j'ai donc l'impression que ce script ne prend pas en compte les 8 cubes du centre.
Aucune couleur ne leur est assignée donc ils ne participent pas au jeu, mais si on assigne tout, alors le code est beaucoup plus simple
MAIS pas compris comment on peut jouer avec les cubes internes dans la vie réelle ! Comment prendre/permuter un cube à l'intérieur sans casser toute la pile ????
Ok, je n'avais pas comprisJe ne comprends pourquoi il y a comme 6 faces de 16. La bonne sortie devrait être plutôt 4 couches de 16 ?C'est donc un autre jeu ! (controler que 4 plans est en fait plus simple et ne change pas grand chose au code) Pour moi, il fallait contrôler que les faces (comme un rubic) : c'était "en vie réelle" des cubes en bois donc impossible de contrôler l'intérieur sans tout caser.
Comment ce jeux peut exister en vie réelle ? même en plastique transparent, on ne va pas voir les couleurs des intérieurs ? Ou un cube plastique transparent plein mais en son centre une boule de pétanque plastique de couleur ? (pas trouvé, ce qui se rapproche le plus)
Le problème avec l'aléatoire, c'est que plus il y a de contraintes et plus on risque de ne jamais trouver une solution dans un temps acceptable pour notre cpu/facture électricitéJe vais m'orienter vers une méthode aléatoire dans un premier temps
ps: une version compilée devrait accélérer d'un facteur minimum de 50x (mais je suppose qu'avec ton cahier des charges, cela ne donnerait pas plus un temps de calcul "acceptable")
je pense que le bon moyen serait de pondre un véritable algo mathématique (type rubic: ils avaient le même problème que toi), mais ici, c'est un truc de mathématicien plus que confirmé et pas de programmeur/langage (existe un forum dédié ici) c'était la première réponse de ce sujet.
IRL: en version 3x3x3 c'est un grand cube transparent, dans lequel on insère les petits cubes. Oui on ne voit pas le cube du centre; mais c'est la règle.
Efectivelement c'est assez fastidieux quand on le manipule
IRL en version 4x4x4:
Afin d'éviter ce coté encore plus fastidieux je vais m'inspirer de ce principe d'empilement, sauf qu'au lieu d'avoir 2 couleurs de perles comme sur la photo il y en aura 3. cela permettra aussi d'avoir une vue sur les perles du centre.
![]()
Partager