diff --git a/Action.py b/Action.py
new file mode 100644
index 0000000..cf4f6d8
--- /dev/null
+++ b/Action.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+# coding: utf-8
+
+'''
+Created on 16 mars 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+programme réalisé sur une base du programme dévellopé par Leonel Machava
+ http://codeNtronix.com
+'''
+from random import choice
+
+class Action:
+ """Object qui permet de tourner les faces."""
+
+ def __init__(self, parent):
+ """parent est le cube qui utilise l'instance."""
+ self.parent = parent
+ self.angle = 0 # Angle restant à parcourir
+ self.actions = [] # Actions à effectuer
+ self.indexs = [] # Indices des cubies à tourner
+ self.anglesRotation = []# Angle en x, y, et z à tourner.
+ self.listeActionsPossible = ["H CWI", "H ACWI",
+ "B CWI", "B ACWI",
+ "D CWI", "D ACWI",
+ "G CWI", "G ACWI",
+ "AV CWI", "AV ACWI",
+ "AR CWI", "AR ACWI"]
+
+
+ def doAll(self):
+ """Execute toutes les actions de la liste."""
+ while self.actions:
+ self.__call__()
+
+ def __call__(self):
+ """Méthode principale."""
+ if self.angle == 0 and not self.actions:
+ #self.actions.append("ALEA")
+ return #Si l'action est terminée et qu'il n'y en a pas d'autre, on passe.
+ elif self.angle == 0:
+ self.initNewAction()
+
+ for i in self.indexs:
+ self.parent.cubies[i] = self.parent.cubies[i].rotationX(self.anglesRotation[0])
+ self.parent.cubies[i] = self.parent.cubies[i].rotationY(self.anglesRotation[1])
+ self.parent.cubies[i] = self.parent.cubies[i].rotationZ(self.anglesRotation[2])
+ angle = 0
+ for i in self.anglesRotation:
+ angle += i
+ if self.angle < 0:
+ print("deadlock")
+ self.angle -= abs(angle)
+
+ def initNewAction(self, actions = None):
+ """Initialise une nouvelle action. Si une action est mise en argument,
+ elle est initialisée, sinon, l'action est prise dans la liste d'action."""
+ if actions:
+ commande = actions
+ actions.split()
+ else:
+ commande = self.actions.pop(0)
+ actions = commande.split()
+ if actions[0] == "ALEA":
+ self.melange()
+ if self.actions:
+ actions = self.actions.pop(0).split()
+ if actions[0] == "SOLVE":
+ self.resoudre()
+ elif actions[1] == "CW":
+ self.angle = 90
+ angle = 10
+ elif actions[1] == "ACW":
+ self.angle = 90
+ angle = -10
+ elif actions[1] == "CWI":
+ self.angle = 90
+ angle = 90
+ elif actions[1] == "ACWI":
+ self.angle = 90
+ angle = -90
+ else:
+ raise ValueError("La valeur " + str(actions[1]) + " est inconnue.")
+
+ x, y, z = 0, 0, 0
+ if actions[0] == "H":
+ y = angle
+ self.indexs = self.parent.getH()
+ elif actions[0] == "B":
+ y = angle
+ self.indexs = self.parent.getB()
+ elif actions[0] == "G":
+ x = angle
+ self.indexs = self.parent.getG()
+ elif actions[0] == "D":
+ x = angle
+ self.indexs = self.parent.getD()
+ elif actions[0] == "AV":
+ z = angle
+ self.indexs = self.parent.getAv()
+ elif actions[0] == "AR":
+ z = angle
+ self.indexs = self.parent.getAr()
+ elif actions[0] == "X":
+ x = angle
+ self.indexs = [i for i in range(len(self.parent.cubies))]
+ elif actions[0] == "Y":
+ y = angle
+ self.indexs = [i for i in range(len(self.parent.cubies))]
+ elif actions[0] == "Z":
+ z = angle
+ self.indexs = [i for i in range(len(self.parent.cubies))]
+ elif actions[0] != "SOLVE" and actions[0] != "ALEA":
+ raise ValueError("La commande " + str(commande) + " est inconnue.")
+ self.anglesRotation = [x, y, z]
+
+ def melange(self):
+ """Met des actions aléatoire dans la liste d'action."""
+ liste = []
+ while len(liste) < 21:
+ liste.append(choice(self.listeActionsPossible))
+ self.actions = liste + self.actions
+ print(liste)
+
+ def resoudre(self):
+ """Lance la resolution."""
+ self.parent.resoudre()
diff --git a/Bouton.py b/Bouton.py
new file mode 100644
index 0000000..98bc21f
--- /dev/null
+++ b/Bouton.py
@@ -0,0 +1,151 @@
+'''
+Created on 5 mai 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+
+Class pour les boutons. Une classe qui gère l'ensemble des
+boutons, et une autre qui est le bouton.
+'''
+
+import pygame
+
+class Boutons:
+ """Class gérant la création de boutons et le fait de clique dessus,
+ ainsi que l'affichage."""
+
+ def __init__(self):
+ """Cette class à pour attribut une liste de boutons."""
+
+ self.boutons = []
+
+ def nouveauBouton(self, pos, image=None, couleur=(255,0,255),
+ size=(60,60), callback=lambda *args: None, argsCallback=[]):
+ """Crée un nouveau bouton."""
+
+ bouton = Bouton(pos, self, image=image, couleur=couleur,
+ size=size, callback=callback, argsCallback=argsCallback)
+ self.boutons.append(bouton)
+ return bouton
+
+ def update(self, events):
+ """Gère le click sur le bouton."""
+
+ for event in events:
+ if event.type == pygame.MOUSEBUTTONDOWN:
+ pos = event.pos
+ self.callbackClic(pos)
+
+ def callbackClic(self, pos):
+ """Methode appellé lors d'un clic."""
+
+ for bouton in self.boutons:
+ if bouton.rect.collidepoint(*pos):
+ bouton.callback(*bouton.argsCallback)
+ return
+
+ def display(self, screen):
+ """Affiche les Boutons."""
+
+ for bouton in self.boutons:
+ bouton.display(screen)
+
+
+class Bouton:
+ """Un Bouton."""
+
+ def __init__(self, pos, parent, image=None, couleur=(255,0,255),
+ size=(60,60), callback=lambda *args: None, argsCallback=[]):
+ """Crée un bouton, si une image est donné, il la charge, sinon,
+ c'est un rectangle de taille size et de couleur couleur qui est affiché."""
+
+ self.parent = parent
+ self.pos = pos
+ if image is not None:
+ self.surface = pygame.image.load(image).convert_alpha()
+ self.rect = self.surface.get_rect()
+ else:
+ self.surface = pygame.Surface(size)
+ self.surface.fill(couleur)
+ self.rect = self.surface.get_rect()
+ self.rect = self.rect.move(self.pos)
+ self.callback = callback
+ self.argsCallback = argsCallback
+
+ def suppr(self):
+ """Suprime le Bouton."""
+
+ self.parent.boutons.remove(self)
+
+ def display(self, screen):
+ """Affiche le Bouton."""
+
+ screen.blit(self.surface, self.rect)
+
+def callbackTest(a, b, c, d, e, f, g):
+ """Test de callback."""
+ print(a)
+ print(b)
+ print(c)
+ print(d)
+ print(e)
+ print(f)
+ print(g)
+
+def callback2(*args):
+ print("toto")
+
+
+if __name__ == "__main__":
+
+ boutons = Boutons()
+
+ screen = pygame.display.set_mode((1000, 400))
+ clock = pygame.time.Clock()
+
+ pos = (50,50)
+ bouton = boutons.nouveauBouton(pos, callback=callbackTest, argsCallback=["A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G"])
+
+ pos2 = (50, 200)
+ bouton2 = boutons.nouveauBouton(pos2, callback=callback2, argsCallback=["H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N"])
+
+ while True:
+ screen.fill((150, 150, 150))
+
+ events = pygame.event.get()
+ for event in events:
+ if event.type == pygame.QUIT:
+ exit()
+ quit()
+ boutons.update(events)
+ boutons.display(screen)
+ pygame.display.update()
+ clock.tick(30)
+
\ No newline at end of file
diff --git a/Commande.py b/Commande.py
new file mode 100644
index 0000000..b4169e8
--- /dev/null
+++ b/Commande.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+#coding: utf-8
+
+"""
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author: Maxime Keller
+"""
+import pygame
+from pygame.locals import *
+from ConstanteTouche import *
+from Action import Action
+
+#pygame.init()
+
+class Commande:
+ """Objet permettant de gérer les touches du clavier"""
+
+ def __init__(self, parent):
+ self.action = Action(parent)
+ self.KANOMI = (K_UP, K_UP, K_DOWN, K_DOWN, K_LEFT, K_RIGHT, K_LEFT, K_RIGHT, TOUCHE_b, TOUCHE_a)
+ self.iKonami = 0
+
+ def testKonamie(self, event):
+ """Fait avancer, ou remet a 0, le konami code."""
+ if event.key == self.KANOMI[self.iKonami]:
+ self.iKonami += 1
+ if event.key == TOUCHE_a:
+ event.key = None
+ else:
+ self.iKonami = 0
+ if self.iKonami == 10:
+ self.iKonami = 0
+ self.action.actions.append("SOLVE")
+
+ def touches(self):
+ """Les touches sont reliés a un autre programme"""
+
+ self.events = pygame.event.get()
+ for event in self.events:
+ if event.type == QUIT:
+ pygame.quit()
+ quit()
+ if event.type == KEYDOWN:
+ self.testKonamie(event)
+ if event.key == TOUCHE_a:
+ self.action.actions.append("ALEA")
+ print("alea")
+ elif event.key == TOUCHE_e :
+ self.action.actions.append("H CW")
+ elif event.key == TOUCHE_r :
+ self.action.actions.append("B CW")
+ elif event.key == TOUCHE_y :
+ self.action.actions.append("AV CW")
+ elif event.key == TOUCHE_u :
+ self.action.actions.append("AR CW")
+ elif event.key == TOUCHE_o :
+ self.action.actions.append("G CW")
+ elif event.key == TOUCHE_p :
+ self.action.actions.append("D CW")
+ elif event.key == TOUCHE_d :
+ self.action.actions.append("H ACW")
+ elif event.key == TOUCHE_f :
+ self.action.actions.append("B ACW")
+ elif event.key == TOUCHE_h :
+ self.action.actions.append("AV ACW")
+ elif event.key == TOUCHE_j :
+ self.action.actions.append("AR ACW")
+ elif event.key == TOUCHE_l :
+ self.action.actions.append("G ACW")
+ elif event.key == TOUCHE_m :
+ self.action.actions.append("D ACW")
+ elif event.key == TOUCHE_z :
+ print("stop")
+ # self.orientation[1] = -45
+ #elif event.key == K_RIGHT :
+ # self.orientation[0] = -45
+ # self.orientation[2] = -45
+ #elif event.key == K_LEFT :
+ # self.orientation[2] = 135
+ # self.orientation[0] = 135
+ #elif event.type == KEYUP:
+ # if event.key == K_UP :
+ # self.orientation[1] = 45
+ # elif event.key == K_RIGHT :
+ # self.orientation[0] = 45
+ # self.orientation[2] = 45
+ # elif event.key == K_LEFT :
+ # self.orientation[2] = 45
+ # self.orientation[0] = 45
\ No newline at end of file
diff --git a/ConstanteTouche.py b/ConstanteTouche.py
new file mode 100644
index 0000000..6da0a5a
--- /dev/null
+++ b/ConstanteTouche.py
@@ -0,0 +1,25 @@
+from pygame.locals import K_a
+#TOUCHE_a = 113
+TOUCHE_a = K_a
+TOUCHE_z = 119
+TOUCHE_e = 101
+TOUCHE_r = 114
+TOUCHE_t = 116
+TOUCHE_y = 121
+TOUCHE_u = 117
+TOUCHE_i = 105
+TOUCHE_o = 111
+TOUCHE_p = 112
+
+TOUCHE_q = 97
+TOUCHE_s = 115
+TOUCHE_d = 100
+TOUCHE_f = 102
+TOUCHE_g = 103
+TOUCHE_h = 104
+TOUCHE_j = 106
+TOUCHE_k = 107
+TOUCHE_l = 108
+TOUCHE_m = 59
+
+TOUCHE_b = 98
diff --git a/Cube.py b/Cube.py
new file mode 100644
index 0000000..c60839e
--- /dev/null
+++ b/Cube.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+# coding: utf-8
+
+'''
+Created on 16 mars 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author: , Maxime Keller
+'''
+import pygame
+from operator import itemgetter
+from random import choice
+from Cube1x1 import Cubie3D
+from Action import Action
+from CubeGetteur import CubeGetteur
+from Commande import Commande
+from Solveur import Solver
+
+ROUGE, ORANGE, JAUNE, BLANC, VERT, BLEU = (255,0,0), (255,130,20), (255,255,20), (255,255,255), (0,255,0), (0,0,255)
+
+class Cube(Commande, CubeGetteur, Solver):
+ """Objet représentant le rubick's Cube."""
+
+ def __init__(self, screen, vide = False):
+ """Init. ''vide'' permet d'éviter une réinitialisation de tous le cube."""
+
+ Commande.__init__(self, parent = self)
+ if not vide:
+ #Place les cubies
+ lpos = []
+ for x in [-4, 0, 4]:
+ for y in [-4, 0, 4]:
+ for z in [-4, 0, 4]:
+ lpos.append((x, y, z))
+ self.cubies = [Cubie3D(pos) for pos in lpos if pos != (0,0,0)]
+
+ self.orientation = [-30,30,0]
+ self.screen = screen
+ self.setColor()
+
+ def creationRefletNonOriente(self):
+ """Crée un reflet du cube non orienté."""
+ newCube = Cube(None, vide = True)
+ newCube.orientation = [0,0,0]
+ newCubies = [cubie.copie() for cubie in self.cubies]
+ newCube.cubies = newCubies
+ newCube.screen = self.screen
+ return newCube
+
+ def creationReflet(self):
+ """Crée un reflet du cube orienté selon l'orientation du cube."""
+ newCube = Cube(None, vide = True)
+ newCube.orientation = self.orientation
+ newCubies = [cubie.rotationX(self.orientation[0]) for cubie in self.cubies]
+ newCubies = [cubie.rotationY(self.orientation[1]) for cubie in newCubies]
+ newCubies = [cubie.rotationZ(self.orientation[2]) for cubie in newCubies]
+ newCube.cubies = newCubies
+ newCube.screen = self.screen
+ return newCube
+
+ def affichage(self):
+ """Affiche le cube"""
+
+ cubiesZ = [[cubie, cubie.minZ] for cubie in self.cubies]
+
+ #self.nbImg = 0
+ liste = sorted(cubiesZ, key=itemgetter(1), reverse=True)
+
+ for tmp in liste:
+ cubie = tmp[0]
+ cubie.affichage(self.screen)
+ #pygame.display.flip()
+ #pygame.display.flip()
+ #pygame.image.save(screen,"./img/" + str(self.nbImg) + "Tri2.png")
+ #self.nbImg += 1
+ #pygame.time.wait(100)
+
+ def setColor(self):
+ """Attribut les couleurs aux faces."""
+ liste = self.getH()
+ for i in liste:
+ self.cubies[i].couleurs[0] = ROUGE
+ self.cubies[i].couleursResolution.append(ROUGE)
+ liste = self.getB()
+ for i in liste:
+ self.cubies[i].couleurs[1] = ORANGE
+ self.cubies[i].couleursResolution.append(ORANGE)
+ liste = self.getG()
+ for i in liste:
+ self.cubies[i].couleurs[2] = JAUNE
+ self.cubies[i].couleursResolution.append(JAUNE)
+ liste = self.getD()
+ for i in liste:
+ self.cubies[i].couleurs[3] = BLANC
+ self.cubies[i].couleursResolution.append(BLANC)
+ liste = self.getAr()
+ for i in liste:
+ self.cubies[i].couleurs[4] = VERT
+ self.cubies[i].couleursResolution.append(VERT)
+ liste = self.getAv()
+ for i in liste:
+ self.cubies[i].couleurs[5] = BLEU
+ self.cubies[i].couleursResolution.append(BLEU)
+
+ def run(self):
+ """Lance l'affichage."""
+ self.touches()
+ self.action()
+ reflet = self.creationReflet()
+ reflet.affichage()
+
+if __name__ == "__main__":
+
+ pygame.init()
+
+ angle = 5
+ screen = pygame.display.set_mode((500, 500))
+ pygame.display.set_caption("Rubick's Cube")
+
+ cubes = [Cube(screen)]
+
+ prendreImage = False
+
+ rot = False
+ #cubes[0].orientation = [-30,30,0]
+ #print(cubes[0].cubies[cubes[0].getCubieByPos((1,1,-1))].getOrientationFace(ROUGE))
+ #cubes[0].action.actions.append("H CWI")
+ #cubes[0].action.actions.append("H CWI")
+ #cubes[0].action.actions.append("B CWI")
+ #cubes[0].action.actions.append("B CWI")
+ #cubes[0].action.actions.append("D CWI")
+ #cubes[0].action.actions.append("D CWI")
+ #cubes[0].action.actions.append("G CWI")
+ #cubes[0].action.actions.append("G CWI")
+ #cubes[0].action.actions.append("AV CWI")
+ #cubes[0].action.actions.append("AV CWI")
+ #cubes[0].action.actions.append("AR CWI")
+ #cubes[0].action.actions.append("AR CWI")
+ #cubes[0].action.doAll()
+ #cubes[0].action.actions.append("ALEA")
+ #cubes[0].resoudre()
+ while True:
+ #for event in pygame.event.get():
+ # if event.type == pygame.QUIT:
+ # pygame.quit()
+ # sys.exit()
+ # if event.type == pygame.KEYDOWN:
+ # if event.key == pygame.K_SPACE:
+ # if rot:
+ # rot = False
+ # else:
+ # rot = True
+ # if event.key == pygame.K_LEFT:
+ # angle = 5
+ # if event.key == pygame.K_RIGHT:
+ # angle = -5
+ screen.fill((255,255,255))
+ for cube in cubes:
+ cube.run()
+ pygame.display.flip()
+ #pygame.time.wait(25)
+ if rot:
+ for cube in cubes:
+ orientation = cube.orientation
+ cube.orientation = [alpha + angle for alpha in orientation]
+
+ if prendreImage:
+ pygame.image.save(screen,"./img/pasDeTrie.png")
+ prendreImage = False
+
+
\ No newline at end of file
diff --git a/Cube1x1.py b/Cube1x1.py
new file mode 100644
index 0000000..f5a9923
--- /dev/null
+++ b/Cube1x1.py
@@ -0,0 +1,510 @@
+'''
+Created on 9 mars 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+
+Programme inspiré d'un programme dévellopé par Leonel Machava
+ http://codeNtronix.com
+'''
+
+import sys, math, pygame
+from operator import itemgetter
+
+class Point3D:
+ def __init__(self, x = 0, y = 0, z = 0):
+ self.x, self.y, self.z = float(x), float(y), float(z)
+
+ def rotationX(self, angle):
+ """ Fait pivoter le point autour de l'axe X d'une valeur donnée en degrés. """
+ rad = angle * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ y = self.y * cosa - self.z * sina #Formules d'addition de trigo.
+ z = self.y * sina + self.z * cosa
+ return Point3D(self.x, y, z)
+
+ def rotationY(self, angle):
+ """ Fait pivoter le point autour de l'axe Y d'une valeur donnée en degrés. """
+ rad = angle * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ z = self.z * cosa - self.x * sina #Formules d'addition de trigo.
+ x = self.z * sina + self.x * cosa
+ return Point3D(x, self.y, z)
+
+ def rotationZ(self, angle):
+ """ Fait pivoter le point autour de l'axe Z d'une valeur donnée en degrés. """
+ rad = angle * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ x = self.x * cosa - self.y * sina #Formules d'addition de trigo.
+ y = self.x * sina + self.y * cosa
+ return Point3D(x, y, self.z)
+
+ def projection(self, largeur_ecran, hauteur_ecran, zoom, distance):
+ """ Transforme ce point 3D en point 2D (avec la profondeur conservé). """
+ factor = zoom / (distance + self.z)
+ x = self.x * factor + largeur_ecran / 2
+ y = -self.y * factor + hauteur_ecran / 2
+ return Point3D(x, y, self.z)
+
+ def __eq__(self, point):
+ """opérateur d'égalité."""
+ x = abs(self.x - point.x) < 0.01
+ y = abs(self.y - point.y) < 0.01
+ z = abs(self.z - point.z) < 0.01
+ return x and y and z
+
+ def dans(self, points):
+ """Test si un point est dans une liste de points avec une impressition."""
+ for point in points:
+
+ x = False
+ y = False
+ z = False
+
+ if abs(self.x - point.x) < 0.01:
+ x = True
+ if abs(self.y - point.y) < 0.01:
+ y = True
+ if abs(self.z - point.z) < 0.01:
+ z = True
+
+ if x and y and z:
+ return True
+
+ return False
+
+ def copie(self):
+ """Retourne une copie de l'objet."""
+ return Point3D(self.x, self.y, self.z)
+
+class Peintre:
+ """Objet de tri pour les faces."""
+ def __init__(self, LARGEUR_ECRAN = 500, HAUTEUR_ECRAN = 500, ZOOM = 254, DISTANCE = 50, ECART_INTER = 0.01):
+ self.LARGEUR_ECRAN = LARGEUR_ECRAN # DISTANCE 10
+ self.HAUTEUR_ECRAN = HAUTEUR_ECRAN
+ self.ZOOM = ZOOM
+ self.DISTANCE = DISTANCE
+ self.ECART_INTER = ECART_INTER
+ self.coin = []
+ self.faces = []
+
+ def intersection(self, A, B, C, D):
+ """Retourne l'intersection des secgments [point1 point2] et [point3 point4] en 2 dimentions"""
+
+ # Segments paralleles
+ if A.x == B.x and C.x == D.x: return None
+
+ elif (A.x == B.x):
+ c = (C.y - D.y)/(C.x - D.x)
+ d = C.y - (c*C.x)
+ x = A.x
+ y = c*x + d
+
+ elif (C.x == D.x):
+ a = (A.y - B.y)/(A.x - B.x)
+ b = A.y - (a*A.x)
+ x = C.x
+ y = a*x + b
+
+ else:
+ a = (A.y - B.y)/(A.x - B.x)
+ b = A.y - (a*A.x)
+ c = (C.y - D.y)/(C.x - D.x)
+ d = C.y - (c*C.x)
+
+ if a == c:
+ return None # Segment parallèles
+ elif a == 0:
+ y = B.y
+ x = (y - d)/c
+ elif c == 0:
+ y = D.y
+ x = (y - b/a)
+ else:
+ x = (d - b)/(a - c)
+ y = a*x + b
+
+ pointDansSegment1 = (min(A.x, B.x) + self.ECART_INTER < x < max(A.x, B.x) - self.ECART_INTER) \
+ and (min(A.y, B.y) + self.ECART_INTER < y < max(A.y, B.y) - self.ECART_INTER)
+ pointDansSegment2 = (min(C.x, D.x) + self.ECART_INTER < x < max(C.x, D.x) - self.ECART_INTER) \
+ and (min(C.y, D.y + self.ECART_INTER) < y < max(C.y, D.y) - self.ECART_INTER)
+
+ if pointDansSegment1 and pointDansSegment2:
+ return Point3D(x, y, 0)
+ else:
+ return None
+
+ def profondeurIntersection(self, A, B, I):
+ """Retourne le point avec sa profondeur"""
+
+ x = I.x
+ y = I.y
+
+ if A.z == B.z:
+ z = A.z
+ return Point3D(x, y, z)
+
+ a = (A.x - B.x)/(A.z - B.z)
+ b = B.x - (a*B.z)
+ c = (A.y - B.y)/(A.z - B.z)
+ d = B.y - (c*B.z)
+
+ # Attention grosse formule!
+
+ denominateur = ((x - self.LARGEUR_ECRAN/2) - a*self.ZOOM)
+ if denominateur != 0:
+ z = (b*self.ZOOM - (x - self.LARGEUR_ECRAN/2)*self.DISTANCE)/denominateur
+ return Point3D(x, y, z)
+
+ denominateur = (c*self.ZOOM + y - self.HAUTEUR_ECRAN/2)
+ if denominateur != 0:
+ z = (-d*self.ZOOM - (y - self.HAUTEUR_ECRAN/2)*self.DISTANCE)/denominateur
+ return Point3D(x, y, z)
+
+ denominateur = (y - self.HAUTEUR_ECRAN/2 + (c+d)*self.ZOOM)
+ if denominateur != 0:
+ z = -(y - self.HAUTEUR_ECRAN/2)*self.DISTANCE/denominateur
+ return Point3D(x, y, z)
+
+ ## Formules qui MARCHENT:
+ #z = - (y - HAUTEUR_ECRAN/2)*DISTANCE / (y - HAUTEUR_ECRAN/2 + (c+d)*ZOOM)
+ #z = (-d*ZOOM - (y - HAUTEUR_ECRAN/2)*DISTANCE)/(c*ZOOM + y - HAUTEUR_ECRAN/2)
+ #z = (b*ZOOM - (x - LARGEUR_ECRAN/2)*DISTANCE)/((x - LARGEUR_ECRAN/2) - a*ZOOM)
+
+ ## Formules FAUSSENT z = ((y - HAUTEUR_ECRAN/2)*a/ZOOM + b) / (1- (a/ZOOM)*(y - HAUTEUR_ECRAN/2))
+ ##z = ((x - LARGEUR_ECRAN/2)*DISTANCE - b*ZOOM)/(a*ZOOM - x - LARGEUR_ECRAN/2)
+ z = 0
+ return Point3D(x, y, z)
+
+ def tri(self, faces, intersections, segments, points3D, point2D):
+ """Trie les faces en fonction des points d'intersection"""
+
+ # pointsSegments contient des listes avec en première valeur le point d'intersection
+ # en deuxième et troisième les extrèmitès du segment auquel il appartient.
+ # Ces listes vont normalement par paire.
+ while intersections:
+ # Selectionne deux points d'intersections de même position
+ intersection1 = intersections[0]
+ intersections = intersections[1:]
+ segment1 = segments[0]
+ segments = segments[1:]
+ for intersection2 in intersections:
+ if abs(intersection1.x - intersection2.x) < 0.01 and abs(intersection1.y - intersection2.y) < 0.01:
+ segment2 = segments[intersections.index(intersection2)]
+ segments.remove(segment2)
+ intersections.remove(intersection2)
+ break
+
+ # verifie la validite du point
+ if intersection1.x - intersection2.x < 0.01 and intersection1.y - intersection2.y < 0.01:
+
+ faces1 = []
+ faces2 = []
+
+ for face in faces:
+ i = faces.index(face)
+ pointsFaces = [points3D[j] for j in face]
+ if segment1[0].dans(pointsFaces) and \
+ segment1[1].dans(pointsFaces):
+ faces1.append(i)
+ if segment2[0].dans(pointsFaces) and \
+ segment2[1].dans(pointsFaces):
+ faces2.append(i)
+
+ # Nous avons associer deux points d'intersection de profondeur differentes
+ # aux faces qui contiennent le segment
+ # Il faut que les faces donc le segment est le plus proche soit avans les
+ # deux autres.
+ interTpm = [intersection1, intersection2]
+ facesTpm = [faces1, faces2]
+ # Le point le plus éloigné en premier, donc les premieres faces a afficher en premier
+ if interTpm[0].z > interTpm[1].z:
+ tmp = facesTpm[0]
+ facesTpm[0] = facesTpm[1]
+ facesTpm[1] = tmp
+ # les premieres faces doivent etre avant la limite
+ limite = min(facesTpm[0])
+ indice1, indice2 = facesTpm[1]
+
+ if indice1 > limite and indice2 > limite:
+ faces1Liste = faces[:limite]
+ faces2Liste = faces[limite:]
+ faces1Liste.append(faces[min(indice1, indice2)])
+ faces1Liste.append(faces[max(indice1, indice2)])
+ faces2Liste.remove(faces[indice1])
+ faces2Liste.remove(faces[indice2])
+ faces = faces1Liste + faces2Liste
+
+ elif indice1 > limite:
+ faces1Liste = faces[:limite]
+ faces2Liste = faces[limite:]
+ faces1Liste.append(faces[indice1])
+ faces2Liste.remove(faces[indice1])
+ faces = faces1Liste + faces2Liste
+
+ elif indice2 > limite:
+ faces1Liste = faces[:limite]
+ faces2Liste = faces[limite:]
+ faces1Liste.append(faces[indice2])
+ faces2Liste.remove(faces[indice2])
+ faces = faces1Liste + faces2Liste
+
+ return faces
+
+ def peintre1(self, faces, points2D):
+ """Algorithme du peintre traditionnel."""
+ moy_z = []
+ i = 0
+ for f in faces:
+ z = (points2D[f[0]].z + points2D[f[1]].z + points2D[f[2]].z + points2D[f[3]].z) / 4.0
+ moy_z.append([i,z])
+ i = i + 1
+
+ nouvellesFaces = []
+ # Trie lessurfaces en utlisant l'algorithme du peintre
+ # Les faces les plus éloignées sont tracées avant les plus proches.
+ for tmp in sorted(moy_z,key=itemgetter(1),reverse=True):
+ indiceFace = tmp[0]
+ nouvellesFaces.append(faces[indiceFace])
+
+ return nouvellesFaces
+
+ def peintre2(self):
+ """Retourne une liste de surface clasés selon l'algorythme du peintre, ainsi que leur couleur"""
+
+ points3D = self.coins
+ points2D = [i.projection(self.LARGEUR_ECRAN, self.HAUTEUR_ECRAN, self.ZOOM, self.DISTANCE) for i in self.coins]
+ faces = self.faces
+ intersections = []
+ segments = []
+
+ for face1 in self.faces:
+ #Test l'intersection de tous les point de chaque face
+ for face2 in self.faces:
+ for j in [-1, 0, 1, 2]:
+ for i in [-1, 0, 1, 2]:
+
+ A3D = points3D[face1[j]]
+ B3D = points3D[face1[j+1]]
+ C3D = points3D[face2[i]]
+ D3D = points3D[face2[i+1]]
+
+ A = points2D[face1[j]]
+ B = points2D[face1[j+1]]
+ C = points2D[face2[i]]
+ D = points2D[face2[i+1]]
+
+ inter = self.intersection(A, B, C, D)
+ if inter:
+ intersections.append(self.profondeurIntersection(A3D, B3D, inter))
+ segments.append([A3D, B3D])
+ intersections.append(self.profondeurIntersection(C3D, D3D, inter))
+ segments.append([C3D, D3D])
+
+ faces = self.peintre1(faces, points2D)
+ faces = self.tri(faces, intersections, segments, points3D, points2D)
+ return faces
+
+
+class Cubie3D(Peintre):
+ """Class définissant un cube en 3D"""
+
+ def __init__(self, pos):
+ """Définit le cube de centre pos et de coté 2"""
+
+ Peintre.__init__(self)
+
+ self.centre = Point3D(pos[0], pos[1], pos[2])
+
+ self.coins = [
+ Point3D(pos[0]-2,pos[1]+2,pos[2]+2), # droit haut arrière
+ Point3D(pos[0]+2,pos[1]+2,pos[2]+2), # gauche haut arrière
+ Point3D(pos[0]-2,pos[1]+2,pos[2]-2), # droit haut avant
+ Point3D(pos[0]+2,pos[1]+2,pos[2]-2), # gauche haut avant
+ Point3D(pos[0]-2,pos[1]-2,pos[2]+2), # droit bas arrière
+ Point3D(pos[0]+2,pos[1]-2,pos[2]+2), # gauche bas arrière
+ Point3D(pos[0]-2,pos[1]-2,pos[2]-2), # droit bas avant
+ Point3D(pos[0]+2,pos[1]-2,pos[2]-2)] # gauche bas avant
+ #Liste des faces, les valeurs sont les indices du point correspondant dans la liste coins.
+ self.faces = [
+ (0,1,3,2), # Haut
+ (4,5,7,6), # Bas
+ (0,2,6,4), # Droite
+ (1,3,7,5), # Gauche
+ (0,1,5,4), # Arrière
+ (2,3,7,6)] # Avant
+ #Liste des couleurs, leur indices sont les mêmes que ceux de la faces associer.
+ self.couleurs = [
+ (0,0,0), #(255,0,0), # Haut
+ (0,0,0), #(255,70,0), # Bas
+ (0,0,0), #(255,255,0), # Gauche
+ (0,0,0), #(255,255,255), # Droite
+ (0,0,0), #(0,255,0), # Arrière
+ (0,0,0)] #(0,0,255)] # Avant
+
+ self.couleursResolution = []
+
+ def getMinZ(self):
+ """Retourne la profondeur du point le plus proche."""
+ z = self.coins[0].z
+ for pt in self.coins:
+ if pt.z < z:
+ z = pt.z
+ return z
+
+ minZ = property(fget = getMinZ)
+
+ def rotationX(self, angle):
+ """ Fait pivoter le cube autour de l'axe X d'une valeur donnée en degrés. """
+ newCoins = []
+ for point in self.coins:
+ newCoins.append(point.rotationX(angle))
+ newCube = self.copie()
+ newCube.coins = newCoins
+ newCube.centre = self.centre.rotationX(angle)
+ return newCube
+
+ def rotationY(self, angle):
+ """ Fait pivoter le cube autour de l'axe Y d'une valeur donnée en degrés. """
+ newCoins = []
+ for point in self.coins:
+ newCoins.append(point.rotationY(angle))
+ newCube = self.copie()
+ newCube.coins = newCoins
+ newCube.coins = newCoins
+ newCube.centre = self.centre.rotationY(angle)
+ return newCube
+
+ def rotationZ(self, angle):
+ """ Fait pivoter le cube autour de l'axe Z d'une valeur donnée en degrés. """
+ newCoins = []
+ for point in self.coins:
+ newCoins.append(point.rotationZ(angle))
+ newCube = self.copie()
+ newCube.coins = newCoins
+ newCube.centre = self.centre.rotationZ(angle)
+ return newCube
+
+ def getOrientationFace(self, couleur):
+ """Retourn l'orientation de la face de la couleur donnée.
+ Elle est donné sous la forme x, y, z, seul l'axe perpendiculaire
+ à la face est différent ce 0, et le signe son de quel côté du cube il ce trouve."""
+ indiceFace = self.couleurs.index(couleur)
+ pointsFace = [(self.coins[i].x, self.coins[i].y, self.coins[i].z) for i in self.faces[indiceFace]]
+ pointsFaceOposee = [(self.coins[i].x, self.coins[i].y, self.coins[i].z)
+ for i in range(len(self.coins)) if i not in self.faces[indiceFace]]
+
+ orientation = [0, 0, 0]
+
+ for i in [0, 1, 2]:
+ #on compart les coordonnées du premier point des deux faces, pour x, y puis z
+ if pointsFace[0][i] > pointsFaceOposee[0][i]: orientation[i] = 1
+ elif pointsFace[0][i] < pointsFaceOposee[0][i]: orientation[i] = -1
+
+ for point in pointsFace:
+ for i in [0, 1, 2]:
+ if abs(point[i] - pointsFace[0][i]) > 0.01:
+ #if point[i] != pointsFace[0][i]:
+ orientation[i] = 0
+ # pour donner l'axe de la face,
+ #on compart les coordonnées e x,y et z entre les points de la place.
+ if orientation == [0, 0, 0]:
+ raise Exception("Cette face ne semble pas avoir d'orientation, what?")
+ return tuple(orientation)
+
+
+ def affichage(self, screen):
+ """Affiche le cube sur l'écran screen en utilisant l'algorithme du peintre"""
+
+ t = []
+ for coin in self.coins:
+ p = coin.projection(self.LARGEUR_ECRAN, self.HAUTEUR_ECRAN, self.ZOOM, self.DISTANCE)
+ # Place le point dans une liste de coins transformés
+ t.append(p)
+
+ # Trace la surface en utlisant l'algorithme du peintre
+ # Les faces les plus éloignées sont tracées avant les plus proches.
+ faces = self.peintre2()
+ for f in faces[-3:]:
+ pointlist = [(t[f[0]].x, t[f[0]].y), (t[f[1]].x, t[f[1]].y),
+ (t[f[1]].x, t[f[1]].y), (t[f[2]].x, t[f[2]].y),
+ (t[f[2]].x, t[f[2]].y), (t[f[3]].x, t[f[3]].y),
+ (t[f[3]].x, t[f[3]].y), (t[f[0]].x, t[f[0]].y)]
+
+ pygame.draw.polygon(screen,(0,0,0),pointlist, 3)
+ #Pour que les faces caches les traits
+ #en arrière, ils faut les affichers après les arrètes
+ pygame.draw.polygon(screen,self.couleurs[self.faces.index(f)],pointlist)
+ #pygame.display.flip()
+ #pygame.time.wait(100)
+
+ def copie(self):
+ """Retourne une copie de l'objet."""
+ newCubie = Cubie3D((0,0,0))
+ newCubie.centre = self.centre
+ newCubie.coins = self.coins
+ newCubie.faces = self.faces
+ newCubie.couleurs = self.couleurs
+ newCubie.couleursResolution = self.couleursResolution
+ return newCubie
+
+
+if __name__ == "__main__":
+
+ ###nb_image = 0 #######
+
+ pygame.init()
+
+ cubes = [Cubie3D((-2,-2,-2))]
+ angle = 5
+ screen = pygame.display.set_mode((500, 500))
+ pygame.display.set_caption("Rubick's Cube")
+
+ rot = True
+
+ while True:
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ pygame.quit()
+ sys.exit()
+ if event.type == pygame.KEYDOWN:
+ if event.key == pygame.K_SPACE:
+ if rot:
+ rot = False
+ else:
+ rot = True
+ if event.key == pygame.K_LEFT:
+ angle = 5
+ if event.key == pygame.K_RIGHT:
+ angle = -5
+ screen.fill((255,255,255))
+ for cube in cubes:
+ cube.affichage(screen)
+ #if nb_image == 40:
+ # pygame.quit()
+ # sys.exit()
+ #pygame.image.save(screen,"./img/" + str(nb_image)+".png")
+ #nb_image+=1################################################
+ pygame.display.flip()
+ pygame.time.wait(100)
+ if rot:
+ for i, cube in enumerate(cubes):
+ cubes[i] = cube.rotationZ(angle)#.rotationY(angle).rotationX(angle)
diff --git a/CubeGetteur.py b/CubeGetteur.py
new file mode 100644
index 0000000..7d8afb2
--- /dev/null
+++ b/CubeGetteur.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python3
+#coding: utf-8
+'''
+Created on 5 avr. 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+Sert à traiter des cubies.
+'''
+
+from operator import itemgetter
+
+class CubeGetteur:
+ """Sert à traiter des cubies."""
+
+ def __init__(self):
+ pass
+
+ def getH(self):
+ """Récupère les cubie du haut et retourne leur index."""
+ cubiesH = []
+ for cubie in self.cubies:
+ if len(cubiesH) < 9:
+ cubiesH.append([self.cubies.index(cubie), cubie.centre.y])
+ else:
+ cubiesH = sorted(cubiesH,key=itemgetter(1))
+ if cubiesH[0][1] < cubie.centre.y:
+ cubiesH = cubiesH[1:]
+ cubiesH.append([self.cubies.index(cubie), cubie.centre.y])
+ cubiesH = [item[0] for item in cubiesH]
+ return cubiesH
+
+ def getB(self):
+ """Récupère les cubie du bas et retourne leur index."""
+ cubiesH = []
+ for cubie in self.cubies:
+ if len(cubiesH) < 9:
+ cubiesH.append([self.cubies.index(cubie), cubie.centre.y])
+ else:
+ cubiesH = sorted(cubiesH,key=itemgetter(1), reverse=True)
+ if cubiesH[0][1] > cubie.centre.y:
+ cubiesH = cubiesH[1:]
+ cubiesH.append([self.cubies.index(cubie), cubie.centre.y])
+ cubiesH = [item[0] for item in cubiesH]
+ return cubiesH
+
+ def getD(self):
+ """Récupère les cubie de droite et retourne leur index."""
+ cubiesD = []
+ for cubie in self.cubies:
+ if len(cubiesD) < 9:
+ cubiesD.append([self.cubies.index(cubie), cubie.centre.x])
+ else:
+ cubiesD = sorted(cubiesD,key=itemgetter(1))
+ if cubiesD[0][1] < cubie.centre.x:
+ cubiesD = cubiesD[1:]
+ cubiesD.append([self.cubies.index(cubie), cubie.centre.x])
+ cubiesD = [item[0] for item in cubiesD]
+ return cubiesD
+
+ def getG(self):
+ """Récupère les cubie de Gauche et retourne leur index."""
+ cubiesG = []
+ for cubie in self.cubies:
+ if len(cubiesG) < 9:
+ cubiesG.append([self.cubies.index(cubie), cubie.centre.x])
+ else:
+ cubiesG = sorted(cubiesG,key=itemgetter(1), reverse=True)
+ if cubiesG[0][1] > cubie.centre.x:
+ cubiesG = cubiesG[1:]
+ cubiesG.append([self.cubies.index(cubie), cubie.centre.x])
+ cubiesG = [item[0] for item in cubiesG]
+ return cubiesG
+
+ def getAv(self):
+ """Récupère les cubie derrière et retourne leur index."""
+ cubiesA = []
+ for cubie in self.cubies:
+ if len(cubiesA) < 9:
+ cubiesA.append([self.cubies.index(cubie), cubie.centre.z])
+ else:
+ cubiesH = sorted(cubiesA,key=itemgetter(1), reverse=True)
+ if cubiesH[0][1] > cubie.centre.z:
+ cubiesA = cubiesH[1:]
+ cubiesA.append([self.cubies.index(cubie), cubie.centre.z])
+ cubiesA = [item[0] for item in cubiesA]
+ return cubiesA
+
+ def getAr(self):
+ """Récupère les cubie de derrière et retourne leur index."""
+ cubiesA = []
+ for cubie in self.cubies:
+ if len(cubiesA) < 9:
+ cubiesA.append([self.cubies.index(cubie), cubie.centre.z])
+ else:
+ cubiesA = sorted(cubiesA,key=itemgetter(1))
+ if cubiesA[0][1] < cubie.centre.z:
+ cubiesA = cubiesA[1:]
+ cubiesA.append([self.cubies.index(cubie), cubie.centre.z])
+ cubiesA = [item[0] for item in cubiesA]
+ return cubiesA
+
+ def getCubieByPos(self, pos):
+ """Retourne l'indice du Cubie de pos donné. Cette pos est relative au cube,
+ elle est donné en x,y,z, l'origine étant le centre du cube, et l'unité
+ correspond à 1 cubie."""
+
+ if pos[0] == -1:
+ potentielsCubies = self.getG()
+ elif pos[0] == 1:
+ potentielsCubies = self.getD()
+ elif pos[0] == 0:
+ #Celui est est plus embetant, il n'y a pas de méthode pour les recuperer
+ #Donc c'est toutes les valeur sauf celle des deux autre tranchhes.
+ indicesFaux = self.getG() + self.getD()
+ potentielsCubies = [i for i in range(len(self.cubies)) if i not in indicesFaux]
+ else:
+ raise ValueError("Vous devez demander une ordonné de -1, 0 ou 1")
+ # Parce que la pep 20 est bien
+
+ if pos[1] == -1:
+ potentielsCubies = [i for i in potentielsCubies if i in self.getB()]
+ elif pos[1] == 1:
+ potentielsCubies = [i for i in potentielsCubies if i in self.getH()]
+ elif pos[1] == 0:
+ indicesFaux = self.getB() + self.getH()
+ potentielsCubies = [i for i in potentielsCubies if i not in indicesFaux]
+ else:
+ raise ValueError("Vous devez demander une abscice de -1, 0 ou 1")
+ #Errors should never pass silently.
+
+ if pos[2] == -1:
+ potentielsCubies = [i for i in potentielsCubies if i in self.getAv()]
+ elif pos[2] == 1:
+ potentielsCubies = [i for i in potentielsCubies if i in self.getAr()]
+ elif pos[2] == 0:
+ indicesFaux = self.getAv() + self.getAr()
+ potentielsCubies = [i for i in potentielsCubies if i not in indicesFaux]
+ else:
+ raise ValueError("Vous devez demander une profondeur de -1, 0 ou 1")
+ #Oui, aujourd'hui j'ai voulu faire propre.
+
+ if len(potentielsCubies) > 1:
+ raise Exception("Maxime, je sait pas comment t'as fait, mais t'as réussit à trouver \
+ Une coordonnée avec plusieurs Cubie!!!")
+ elif len(potentielsCubies) == 0:
+ raise Exception("Pas de Cubies ici, peut être avez vous demandé l'origine?")
+ else:
+ return potentielsCubies[0]
+
+ def getCubieByColors(self, couleurs):
+ """Retourne l'indice du Cubie de couleurs données. Ces couleurs sont
+ une liste donnant les couleurs exact, mais pas obligatoirement dans l'ordre."""
+ for cubie in self.cubies:
+ if len(couleurs) != len(cubie.couleursResolution):
+ continue
+ bonCubie = True
+ for couleur in couleurs:
+ if couleur not in cubie.couleursResolution:
+ bonCubie = False
+ break
+ if bonCubie: return self.cubies.index(cubie)
+ raise Exception("Pas de cubies correspondanr aux couleurs données.")
+
+ def getPosRelative(self, cubie):
+ """Retourne la position relative du cubie (don on donne l'indice)."""
+
+ if cubie not in range(len(self.cubies)):
+ raise ValueError("Vous devez rentrer un indice de l'argument 'cubies'.")
+
+ if cubie in self.getG():
+ x = -1
+ elif cubie in self.getD():
+ x = 1
+ else:
+ x = 0
+
+ if cubie in self.getB():
+ y = -1
+ elif cubie in self.getH():
+ y = 1
+ else :
+ y = 0
+
+ if cubie in self.getAv():
+ z = -1
+ elif cubie in self.getAr():
+ z = 1
+ else:
+ z = 0
+
+ return x, y, z
\ No newline at end of file
diff --git a/InterfaceBoutons.py b/InterfaceBoutons.py
new file mode 100644
index 0000000..b788d6d
--- /dev/null
+++ b/InterfaceBoutons.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+#coding: utf-8
+
+"""
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+
+Interface de boutons fait à la va vite.
+"""
+
+import pygame
+from Bouton import Boutons
+
+
+def addAction(cube, action):
+ """Ajoute une action à la liste."""
+
+ cube.action.actions.append(action)
+
+CARACTS_BOUTONS = [[(100,30), "img/B1.png", addAction, ["ALEA"]],
+ [(400,30), "img/B2.png", addAction, ["SOLVE"]],
+ [(100,600), None, addAction, ["B CW"]],
+ [(500,600), None, addAction, ["B ACW"]],
+ [(200,600), None, addAction, ["AV CW"]],
+ [(400,600), None, addAction, ["AV ACW"]],
+ [(100,150), None, addAction, ["H CW"]],
+ [(500,150), None, addAction, ["H ACW"]],
+ [(200,150), None, addAction, ["AR CW"]],
+ [(400,150), None, addAction, ["AR ACW"]],
+ [(100,350), None, addAction, ["G CW"]],
+ [(100,450), None, addAction, ["G ACW"]],
+ [(500,350), None, addAction, ["D CW"]],
+ [(500,450), None, addAction, ["D ACW"]]]
+
+class InterfaceBoutons:
+ """interface gérant l'ensemble des boutons."""
+
+ def __init__(self, screen, cube, caractsBoutons=None):
+ """caractsBoutons est une liste contenants des listes
+ de caracteristiques des boutons, dans l'ordre:
+ [position, img, callback, argsCallback]"""
+
+ if caractsBoutons is None:
+ caractsBoutons = CARACTS_BOUTONS
+
+ self.screen = screen
+ self.cube = cube
+
+ self.boutons = Boutons()
+
+ for caracts in caractsBoutons:
+ pos, img, callback, argsCallback = caracts
+ # Bon c'est pas propre mais faut bien mettre le Cube
+ # quelque part...
+ argsCallback = [self.cube] + argsCallback
+ self.boutons.nouveauBouton(pos, image=img, callback=callback,
+ argsCallback=argsCallback)
+
+ def run(self):
+ """Affiche et check les envents pour une itération de la
+ boucle principale."""
+
+ events = self.cube.events
+ self.boutons.update(events)
+ self.boutons.display(self.screen)
diff --git a/Solveur.py b/Solveur.py
new file mode 100644
index 0000000..c71fbdc
--- /dev/null
+++ b/Solveur.py
@@ -0,0 +1,734 @@
+#!/usr/bin/env python3
+# coding: utf-8
+'''
+Created on 5 avr. 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author:
+Solveur du cube à faire hériter à un Cube.
+'''
+
+class Solver:
+ """Class pour résoudre le Cube,
+ Faire hériter.
+ Résoud un reflet avec des action instantanées
+ (en ajoutant un I a la direction, CWI ou ACWI)"""
+
+ def __init__(self):
+ pass
+
+ def resoudre(self):
+ """Méthode principale.
+ Pour une question de vitesse, elle résoud un cube virtuel (reflet)
+ et retourn la liste d'action à éfectuer sur le modèle d'origine."""
+ ####/DEBUG\####
+ self.action.doAll()
+ ####\DEBUG/####
+ resolution = []
+ reflet = self.creationRefletNonOriente()
+ resolution.extend(self.croixHaute(reflet))
+ resolution.extend(self.coinsHaut(reflet))
+ resolution.extend(self.arretesMilieu(reflet))
+ actions = ["X CW", "X CW"]
+ resolution.extend(actions)
+ reflet.action.actions.extend([action + "I" for action in actions])
+ reflet.action.doAll()
+ resolution.extend(self.croixBas(reflet))
+ resolution.extend(self.croixBasArrete(reflet))
+ resolution.extend(self.coinsBasPos(reflet))
+ resolution.extend(self.orientationCoinsBas(reflet))
+ ####/DEBUG\####
+ #resolution = [i + "I" for i in resolution]
+ #self.action.actions.extend(resolution)
+ #self.action.doAll()
+ #resolution =[]
+ ####\DEBUG/####
+ print(resolution)
+ self.action.actions.extend(resolution)
+
+ def croixHaute(self, cube):
+ """Résoud la croix du haut."""
+ resolution = []
+ for i in range(4):
+ resolution.extend(self.croixHauteArreteDeFace(cube))
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ return resolution
+
+ def croixHauteArreteDeFace(self, cube):
+ """Place l'arrete de face."""
+ resolution = []
+ #Positionne l'arrete
+ centreAv = cube.getCubieByPos((0,0,-1))
+ centreH = cube.getCubieByPos((0,1,0))
+ couleurAv = cube.cubies[centreAv].couleursResolution[0]
+ couleurH = cube.cubies[centreH].couleursResolution[0]
+ couleursArrete = [couleurAv, couleurH]
+ arrete = cube.getCubieByColors(couleursArrete)
+ posArrete = cube.getPosRelative(arrete)
+ ####/DEBUG\####
+ #savePos = posArrete
+ ####\DEBUG/####
+
+ # Le but de cette parti est de placer l'arrete en (1,-1,0), cad face de droite millieu bas.
+ if posArrete == (0,1,-1): #La position finale
+ orientation = cube.cubies[arrete].getOrientationFace(couleurH)
+ if orientation == (0,1,0): #Vers le Haut
+ return resolution
+ else:
+ actions = ["AV CW", "AV CW", "B ACW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ elif posArrete[1] == 1: #Le cubie est sur la face du Haut
+ if posArrete[0] == -1:
+ actions = ["G CW", "G CW"]
+ elif posArrete[0] == 0:
+ actions = ["AR CW", "AR CW"]
+ elif posArrete[0] == 1:
+ actions = ["D CW", "D CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ elif posArrete[1] == 0: # Le cubie est sur la tranche du Millieu
+ if posArrete[0] == -1: # Cette action place place ce cubie sur la face du Bas, mais pas forcement
+ if posArrete[2] == -1: # à la bonne place
+ actions = ["G ACW", "B CW", "G CW"]
+ elif posArrete[2] == 1:
+ actions = ["G CW", "B CW", "G ACW"]
+ elif posArrete[0] == 1:
+ if posArrete[2] == -1:
+ actions = ["D ACW", "B CW", "D CW"]
+ elif posArrete[2] == 1:
+ actions = ["D CW", "B CW", "D ACW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ #Normalement, arrivé ici, l'arrete est forcement sur la face du bas.
+ posArrete = cube.getPosRelative(arrete)
+ ####/DEBUG\####
+ #if posArrete[1] != -1:
+ # print("error")
+ # print(savePos)
+ #nbIter = 0
+ ####\DEBUG/####
+ while not posArrete == (1,-1,0):
+ actions = ["B CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ posArrete = cube.getPosRelative(arrete)
+ ####/DEBUG\####
+ #nbIter += 1
+ #if nbIter > 10:
+ # print("Error")
+ ####\DEBUG/####
+
+ #Maintenant, la face est en (1,-1,0), il reste une formule à appliquer,
+ #qu'il faut choisir en fonction de l'orientation du cubie.
+ orientation = cube.cubies[arrete].getOrientationFace(couleurH)
+ if orientation == (0,-1,0):
+ actions = ["B CW", "AV CW", "AV CW"]
+ else:
+ actions = ["D CW", "AV CW", "D ACW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ # Une arrete de finit!
+ return resolution
+
+ def coinsHaut(self, cube):
+ """Résoud les coins de la face du haut."""
+ resolution = []
+ for i in range(4):
+ resolution.extend(self.coinHaut(cube))
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ return resolution
+
+ def coinHaut(self, cube):
+ """Résoud le coin en (1,1,-1), cad face avant, coin haut droit."""
+ resolution = []
+ #Position du coin
+ centreAv = cube.getCubieByPos((0,0,-1))
+ centreH = cube.getCubieByPos((0,1,0))
+ centreD = cube.getCubieByPos((1,0,0))
+ couleurAv = cube.cubies[centreAv].couleursResolution[0]
+ couleurH = cube.cubies[centreH].couleursResolution[0]
+ couleurD = cube.cubies[centreD].couleursResolution[0]
+ couleursCoin = [couleurAv, couleurH, couleurD]
+ coin = cube.getCubieByColors(couleursCoin)
+ posCoin = cube.getPosRelative(coin)
+ ####/DEBUG\####
+ #savePos = posArrete
+ ####\DEBUG/####
+
+ #Si le point est en Haut, le but est de le mettre sur la face du Bas
+ actions = None
+ if posCoin == (1,1,-1): #Pos final
+ orientation = cube.cubies[coin].getOrientationFace(couleurH)
+ if orientation == (0,1,0):#Bien placé
+ return resolution
+ else:
+ actions = ["D ACW", "B CW", "D CW"]
+ elif posCoin == (1,1,1):
+ actions = ["D CW", "B CW", "D ACW"]
+ elif posCoin == (-1,1,1):
+ actions = ["G CW", "B CW", "G ACW"]
+ elif posCoin == (-1,1,-1):
+ actions = ["G ACW", "B CW", "G CW"]
+ if actions is not None:
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ #Positionne le coin en (1,-1,-1), cad face avant, coin bas droit.
+ posCoin = cube.getPosRelative(coin)
+ ####/DEBUG\####
+ #if posCoin[1] != -1:
+ # print("Error")
+ ####\DEBUG/####
+ while posCoin != (1,-1,-1):
+ actions = ["B CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ posCoin = cube.getPosRelative(coin)
+
+ #Positionne le coin en (1,1,-1) et l'oriente.
+ orientation = cube.cubies[coin].getOrientationFace(couleurH)
+ if orientation == (1,0,0):
+ actions = ["B ACW", "AV ACW", "B CW", "AV CW"]
+ elif orientation == (0,-1,0):
+ actions = ["D ACW", "B ACW", "D CW", "B CW", "AV ACW", "B CW", "AV CW"]
+ else:
+ actions = ["B CW", "D ACW", "B ACW", "D CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ return resolution
+
+ def arretesMilieu(self, cube):
+ """Résoud les arrêtes de la tranche du milieu."""
+ resolution = []
+ for i in range(4):
+ resolution.extend(self.arreteMillieuxDroit(cube))
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ return resolution
+
+ def arreteMillieuxDroit(self, cube):
+ """Résoud l'arrete du milieux droit de la face Avant (1,0,-1)."""
+ resolution = []
+ #Positionne l'arrete
+ centreAv = cube.getCubieByPos((0,0,-1))
+ centreD = cube.getCubieByPos((1,0,0))
+ couleurAv = cube.cubies[centreAv].couleursResolution[0]
+ couleurD = cube.cubies[centreD].couleursResolution[0]
+ couleursArrete = [couleurAv, couleurD]
+ arrete = cube.getCubieByColors(couleursArrete)
+ posArrete = cube.getPosRelative(arrete)
+
+ orientation = cube.cubies[arrete].getOrientationFace(couleurAv)
+ if posArrete == (1,0,-1) and orientation == (0,0,-1):
+ return resolution
+
+ elif posArrete[1] == 0:
+ #Si l'arrete est sur la tranche du milieu.
+ while not posArrete == (1,0,-1):
+ #positionne le cube de facon à placer l'arrete en (1,0,-1)
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posArrete = cube.getPosRelative(arrete)
+ resolution.extend(self.belgeD(cube))
+
+ posCentreAv = cube.getPosRelative(centreAv)
+ while not posCentreAv == (0,0,-1):
+ #positionne le cube de facon à replacer la face de depart en face.
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posCentreAv = cube.getPosRelative(centreAv)
+
+ posArrete = cube.getPosRelative(arrete)
+ while not posArrete == (0,-1,-1):
+ #Place l'arrete en bas de la face.
+ cube.action.actions.append("B CWI")
+ cube.action.doAll()
+ resolution.append("B CW")
+ posArrete = cube.getPosRelative(arrete)
+
+ orientation = cube.cubies[arrete].getOrientationFace(couleurAv)
+ if orientation == (0,0,-1):
+ resolution.extend(self.belgeD(cube))
+ else:
+ actions = ["Y CW", "B ACW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ resolution.extend(self.belgeG(cube))
+ cube.action.actions.append("Y ACWI")
+ cube.action.doAll()
+ resolution.append("Y ACW")
+ posArrete = cube.getPosRelative(arrete)
+
+ posArrete = cube.getPosRelative(arrete)
+ ####/DEBUG\####
+ #if posArrete != (1,0,-1):
+ # print("error")
+ # print(resolution)
+ ####\DEBUG/####
+
+ return resolution
+
+ def belgeD(self, cube):
+ """Applique l'algo du Belge à droite."""
+ resolution = ["B CW", "D ACW", "B ACW", "D CW", "B ACW", "AV ACW", "B CW", "AV CW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def belgeG(self, cube):
+ """Applique l'algo du Belge à gauche."""
+ resolution = ["B ACW", "G ACW", "B CW", "G CW", "B CW", "AV CW", "B ACW", "AV ACW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def croixBas(self, cube):
+ """Résoud la croix du bas (pour la resolution, le cube est retourné,
+ donc la croix du bas est en fait en haut)."""
+ resolution = []
+ posAretes, boolOrientation, nbBienOriente = self.croixBasOrientation(cube)
+ iG = posAretes.index((-1,1,0))
+ iD = posAretes.index((1,1,0))
+ iAv = posAretes.index((0,1,-1))
+ iAr = posAretes.index((0,1,1))
+
+ if nbBienOriente == 4:
+ return resolution
+
+ elif nbBienOriente == 0:
+ resolution.extend(self.algoCroixBas(cube))
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ resolution.extend(self.algoCroixBas(cube))
+ resolution.extend(self.algoCroixBas(cube))
+ return resolution
+
+ elif nbBienOriente == 2:
+ aligne = (boolOrientation[iG] and boolOrientation[iD]) or \
+ (boolOrientation[iAr] and boolOrientation[iAv])
+ if aligne:
+ if not (boolOrientation[iAr] and boolOrientation[iAv]):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ resolution.extend(self.algoCroixBas(cube))
+ resolution.extend(self.algoCroixBas(cube))
+
+ else:
+ while not (boolOrientation[iAr] and boolOrientation[iG]):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posAretes, boolOrientation, nbBienOriente = self.croixBasOrientation(cube)
+ resolution.extend(self.algoCroixBas(cube))
+
+ else:
+ print("Mais commenent quoi comment?")
+ return resolution
+
+ def croixBasOrientation(self, cube):
+ """Retourne une liste associant position des arretes
+ et une bool indiquant si leur orientation est bonne
+ au pas et le nombre d'orientation correct."""
+ #Résoud les orientation
+ centreH = cube.getCubieByPos((0,1,0))
+ couleurH = cube.cubies[centreH].couleursResolution[0]
+
+ retourBoolOrientation = []
+ retourPos = [(-1,1,0), (0,1,-1), (1,1,0), (0,1,1)]
+ nbOrientationBonnes = 0
+ for pos in retourPos:
+ cubie = cube.getCubieByPos(pos)
+ orientation = cube.cubies[cubie].getOrientationFace(couleurH)
+ if orientation == (0,1,0):
+ boolOrientation = True
+ nbOrientationBonnes += 1
+ else: boolOrientation = False
+ retourBoolOrientation.append(boolOrientation)
+
+ return retourPos, retourBoolOrientation, nbOrientationBonnes
+
+ def algoCroixBas(self, cube):
+ """Applique l'algo pour la croix du bas."""
+ resolution = ["D ACW", "H ACW", "AV CW", "H CW", "AV ACW", "D CW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def croixBasArrete(self, cube):
+ """Resolution de la position des arretes de la face du bas."""
+ resolution = []
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+ iG = posAretes.index((-1,1,0))
+ iD = posAretes.index((1,1,0))
+ iAv = posAretes.index((0,1,-1))
+ iAr = posAretes.index((0,1,1))
+
+ if nbPosBonnes == 4:
+ return resolution
+
+ while nbPosBonnes == 0:
+ cube.action.actions.append("H CWI")
+ cube.action.doAll()
+ resolution.append("H CW")
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+
+ if nbPosBonnes == 4:
+ return resolution
+
+ if nbPosBonnes == 2:
+ aligne = (posAretes[iG] == posTheo[iG]) and (posAretes[iD] == posTheo[iD]) or \
+ (posAretes[iAv] == posTheo[iAv]) and (posAretes[iAr] == posTheo[iAr])
+ if aligne:
+ if posAretes[iD] == posTheo[iD]:
+ cube.action.actions.append("H CWI")
+ cube.action.doAll()
+ resolution.append("H CW")
+ resolution.extend(self.algoTCW(cube))
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+ while nbPosBonnes == 0:
+ cube.action.actions.append("H CWI")
+ cube.action.doAll()
+ resolution.append("H CW")
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+
+ if nbPosBonnes == 4:
+ return resolution
+ elif nbPosBonnes == 2:
+ print("Mais, cette configuration n'est pas sensé exister!")
+ return resolution
+
+ else:
+ #nbBoucle = 0
+ while nbPosBonnes != 1:
+ cube.action.actions.append("H CWI")
+ cube.action.doAll()
+ resolution.append("H CW")
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+ ####/DEBUG\####
+ #nbBoucle += 1
+ #if nbBoucle > 10:
+ # print("Trop d'iteration")
+ ####\DEBUG/####
+
+ if nbPosBonnes == 1:
+ while posAretes[iG] != posTheo[iG]:
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posAretes, posTheo, nbPosBonnes = self.testCroixBas(cube)
+ if posAretes[iAv] == posTheo[iAr]:
+ resolution.extend(self.algoTCW(cube))
+ elif posAretes[iAr] == posTheo[iAv]:
+ resolution.extend(self.algoTACW(cube))
+ else:
+ print("wtf")
+
+ return resolution
+
+ def algoTACW(self, cube):
+ """Algo de resolution en T dans le sens anti horaire,
+ décale les cubies de la face du haut en forme de T
+ orienté le bas à droite, le haut à gauche.
+ Permet aussi de changer l'orientation des coins combinés à
+ algoTCW."""
+ resolution = ["D ACW", "H ACW", "D CW", "H ACW", "D ACW", "H ACW", "H ACW", "D CW", "H ACW", "H ACW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def algoTCW(self, cube):
+ """Algo de resolution en T dans le sens horaire,
+ décale les cubies de la face du haut en forme de T
+ orienté le bas à droite, le haut à gauche.
+ Permet aussi de changer l'orientation des coins combinés à
+ algoTACW."""
+ resolution = ["D CW", "H CW", "D ACW", "H CW", "D CW", "H CW", "H CW", "D ACW", "H CW", "H CW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def testCroixBas(self, cube):
+ """Test les arrete de la croix bas (donc en haut car le cube est retourné).
+ Retourne la position des cubies, la position final des cubies et le nombre
+ de cubies à la bonne place."""
+ centreH = cube.getCubieByPos((0,1,0))
+ couleurH = cube.cubies[centreH].couleursResolution[0]
+
+ retourPosTheo = [None, None, None, None]
+ nbPosBonnes = 0
+
+ retourPos = [(-1,1,0), (0,1,-1), (1,1,0), (0,1,1)]
+ couleursFace = []
+ for p in retourPos:
+ p = (p[0],0,p[2])
+ c = cube.getCubieByPos(p)
+ couleursFace.append(cube.cubies[c].couleursResolution[0])
+
+ for p in retourPos:
+ c = cube.getCubieByPos(p)
+ couleur = [ i for i in cube.cubies[c].couleursResolution if i != couleurH][0]
+ i = couleursFace.index(couleur)
+ retourPosTheo[i] = p
+ if i == retourPos.index(p):
+ nbPosBonnes += 1
+
+ return retourPos, retourPosTheo, nbPosBonnes
+
+ def coinsBasPos(self, cube):
+ """Place les coins du bas (du haut comme le cube est retourné)
+ à leur position."""
+ resolution = []
+ posCoins, posCoinsTheo, nbPosBonnes = self.testCoinsBas(cube)
+
+ iAvG = posCoins.index((-1,1,-1))
+ iAvD = posCoins.index((1,1,-1))
+ iArD = posCoins.index((1,1,1))
+ iArG = posCoins.index((-1,1,1))
+
+ if nbPosBonnes == 0:
+ resolution.extend(self.algoTriangleCW(cube))
+ posCoins, posCoinsTheo, nbPosBonnes = self.testCoinsBas(cube)
+
+ if nbPosBonnes == 4:
+ return resolution
+ elif nbPosBonnes != 1:
+ print("On vous a bien dit que le tournevis n'est pas la solution!")
+ return resolution
+
+ while posCoins[iAvD] != posCoinsTheo[iAvD]:
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posCoins, posCoinsTheo, nbPosBonnes = self.testCoinsBas(cube)
+
+ if posCoins[iArD] == posCoinsTheo[iAvG]:
+ resolution.extend(self.algoTriangleCW(cube))
+ elif posCoins[iAvG] == posCoinsTheo[iArD]:
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ resolution.extend(self.algoTriangleACW(cube))
+ else:
+ print("PAS DE TOURNEVIS!")
+
+ return resolution
+
+ def algoTriangleCW(self, cube):
+ """Algorithme en triangle dans le sens horaire, sur la face du haut,
+ décale les coins dans le sens hoaire, sauf le coin avant droit."""
+ resolution = ["G CW", "H CW", "D CW", "H ACW", "G ACW", "H CW", "D ACW", "H ACW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def algoTriangleACW(self, cube):
+ """Algorithme en triangle dans le sens anti horaire, sur la face du haut,
+ décale les coins dans le sens anti hoaire, sauf le coin avant gauche."""
+ resolution = ["D CW", "H ACW", "G CW", "H CW", "D ACW", "H ACW", "G ACW", "H CW"]
+ cube.action.actions.extend([action + "I" for action in resolution])
+ cube.action.doAll()
+ return resolution
+
+ def testCoinsBas(self, cube):
+ """Test les coins du bas (donc du haut car le cube est retourné).
+ Retourne la position des cubies, la position final des cubies et le nombre
+ de cubies à la bonne place."""
+ retourPosTheo = [None, None, None, None]
+ nbPosBonnes = 0
+
+ retourPos = [(-1,1,-1), (1,1,-1), (1,1,1), (-1,1,1)]
+ couleursCoins = []
+ # Creer la liste couleursCoins qui contien la couleur des
+ # cubie qui devraient ce trouver à cette place.
+ for p in retourPos:
+ couleurs = []
+ avancement = 0
+ for i in p:
+ pos = [0,0,0]
+ pos[avancement] = i
+ avancement += 1
+ c = cube.getCubieByPos(tuple(pos))
+ couleurs.append(cube.cubies[c].couleursResolution[0])
+ couleursCoins.append(couleurs)
+
+ for couleurs in couleursCoins:
+ # Met la position théorique du coin dans la liste pos théorique
+ # à l'indice correspondant à sa position.
+ c = cube.getCubieByColors(couleurs)
+ posRelative = cube.getPosRelative(c)
+ retourPosTheo[couleursCoins.index(couleurs)] = posRelative
+ if posRelative == retourPos[couleursCoins.index(couleurs)]:
+ nbPosBonnes += 1
+
+ return retourPos, retourPosTheo, nbPosBonnes
+
+ def orientationCoinsBas(self, cube):
+ """Oriente les coins de la face du bas (qui est en haut
+ car le cube est retourné)."""
+ resolution = []
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+
+ #Indices des pos
+ iAvG = posCoins.index((-1,1,-1))
+ iAvD = posCoins.index((1,1,-1))
+ iArD = posCoins.index((1,1,1))
+ iArG = posCoins.index((-1,1,1))
+
+ ####/DEBUG\####
+ #print((orientationCoin, nbBonneOrientation))
+ ####\DEBUG/####
+
+ if nbBonneOrientation == 4:
+ return resolution
+
+ if nbBonneOrientation == 0:
+ while not self.testOrientationCoinsBasHomogene(cube):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ resolution.extend(self.resolutionOrientationCoinsBasHomogene(cube))
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+
+ if nbBonneOrientation == 1:
+ while not orientationCoin[iAvD] == (0,1,0):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+ resolution.extend(self.algoTCW(cube))
+ resolution.extend(self.algoTACW(cube))
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+
+ if nbBonneOrientation == 2:
+ diagonal = (orientationCoin[iAvD] == (0,1,0) and orientationCoin[iArG] == (0,1,0)) or \
+ (orientationCoin[iArD] == (0,1,0) and orientationCoin[iAvG] == (0,1,0))
+
+ if diagonal:
+ while not orientationCoin[iAvD] == (1,0,0):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+ actions = ["AV CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ resolution.extend(self.algoTCW(cube))
+ resolution.extend(self.algoTACW(cube))
+ actions = ["AV ACW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ else:
+ while not self.testOrientationCoinsBasHomogene(cube):
+ cube.action.actions.append("Y CWI")
+ cube.action.doAll()
+ resolution.append("Y CW")
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+ resolution.extend(self.resolutionOrientationCoinsBasHomogene(cube))
+
+ return resolution
+
+ def testOrientationCoinsBasHomogene(self, cube):
+ """Test si les coins de droite orienté de façon "Homogene", cad
+ orientable par la fonction associer. Utilisé dans le cadre de
+ l'orentation des coin de la face du bas. (en haut parce que le cube
+ est retourné)"""
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+ #Indices des pos
+ iAvG = posCoins.index((-1,1,-1))
+ iArG = posCoins.index((-1,1,1))
+
+ facesHautesVersLaDoite = (orientationCoin[iAvG] == (-1,0,0) and orientationCoin[iArG] == (-1,0,0))
+ facesHautesVersAvAr = (orientationCoin[iAvG] == (0,0,-1) and orientationCoin[iArG] == (0,0,1))
+
+ return (facesHautesVersLaDoite or facesHautesVersAvAr)
+
+ def resolutionOrientationCoinsBasHomogene(self, cube):
+ """Oriente correctement les coins en (-1,1,-1) et (-1,1,1) si ils sont
+ "Homogene". S'utilise dans le cadre de l'orientation des coins du bas.
+ (qui sont en haut car on a retournés le cube)"""
+ if not self.testOrientationCoinsBasHomogene(cube):
+ raise Exception("Les coins ne sont pas Homogènes.")
+ resolution = []
+ posCoins, orientationCoin, nbBonneOrientation = self.testOrientationCoinsBas(cube)
+
+ #Indices des pos
+ iAvG = posCoins.index((-1,1,-1))
+ iArG = posCoins.index((-1,1,1))
+
+ if (orientationCoin[iAvG] == (0,0,-1) and orientationCoin[iArG] == (0,0,1)):
+ resolution.extend(self.algoTCW(cube))
+ resolution.extend(self.algoTACW(cube))
+ elif (orientationCoin[iAvG] == (-1,0,0) and orientationCoin[iArG] == (-1,0,0)):
+ actions = ["Z ACW", "Y CW", "Y CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+ resolution.extend(self.algoTCW(cube))
+ resolution.extend(self.algoTACW(cube))
+ actions = ["Y CW", "Y CW", "Z CW"]
+ resolution.extend(actions)
+ cube.action.actions.extend([action + "I" for action in actions])
+ cube.action.doAll()
+
+ return resolution
+
+ def testOrientationCoinsBas(self, cube):
+ """Test l'orientation des coins de la face du bas
+ (qui eest en haut parce que le cube est retourné.
+ Retourn la liste de la position des coins, celle de leur
+ orientation et le nombre de coin bien orientés."""
+ retourOrientation = []
+ nbBonneOrientation = 0
+
+ retourPos = [(-1,1,-1), (1,1,-1), (1,1,1), (-1,1,1)]
+ cubieCentreHaut = cube.getCubieByPos((0,1,0))
+ couleurH = cube.cubies[cubieCentreHaut].couleursResolution[0]
+
+ for pos in retourPos:
+ cubie = cube.getCubieByPos(pos)
+ orientation = cube.cubies[cubie].getOrientationFace(couleurH)
+ retourOrientation.append(orientation)
+ if orientation == (0,1,0):
+ nbBonneOrientation += 1
+
+ return retourPos, retourOrientation, nbBonneOrientation
\ No newline at end of file
diff --git a/img/B1.png b/img/B1.png
new file mode 100644
index 0000000..be9b2e7
Binary files /dev/null and b/img/B1.png differ
diff --git a/img/B2.png b/img/B2.png
new file mode 100644
index 0000000..6ff9b30
Binary files /dev/null and b/img/B2.png differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..0467fb0
--- /dev/null
+++ b/main.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+#coding: utf-8
+
+'''
+Created on 5 mai 2017
+
+Copyright 2017 Jean-Marie Mineau, Maxime Keller
+This file is part of "ISN's Cube".
+
+ "ISN's Cube" is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ "ISN's Cube" is distributed in the hope that it will be useful and
+ recreative, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with "ISN's Cube". If not, see .
+
+@author: , Maxime Keller
+
+ https://www.python.org/ (c'est le language, donc important)
+ Module principale du programme de Rubicks cube.
+'''
+
+import this # (c'est important aussi)
+import pygame
+from Cube import Cube
+from InterfaceBoutons import InterfaceBoutons
+
+if __name__ == "__main__":
+
+ pygame.init()
+
+ surfaceCube = pygame.Surface((500, 500))
+ screen = pygame.display.set_mode((700, 700))
+ pygame.display.set_caption("ISN's Cube")
+
+ cube = Cube(surfaceCube)
+ interfaceBoutons = InterfaceBoutons(screen, cube)
+
+ while True:
+ surfaceCube.fill((255,255,255))
+ screen.fill((255,255,255))
+ cube.run()
+ screen.blit(surfaceCube, (100,100))
+ interfaceBoutons.run()
+ pygame.display.flip()
+ pygame.time.wait(25)
+