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) +