The Rubik`s Project Mémoire Final

Transcription

The Rubik`s Project Mémoire Final
The Rubik's Project
Mémoire Final
John ALIX
Romain ARCILA
Matthieu DEVERT
Fabien JORQUERA
Chargé de TD : M. DESBARATS
Client : M. MONTASSIER
6 avril 2007
Résumé du Projet
Le Rubik's Cube est un des casse-têtes les plus populaires au monde, mais il
n'en demeure pas moins l'un des plus compliqués ! Ainsi, pour permettre à tous
de pouvoir s'amuser, mais aussi de comprendre et résoudre son Rubik's Cube,
nous devons mettre au point un logiciel en suivant trois axes majeurs.
Le premier axe du projet consiste à développer un logiciel possédant une
interface graphique ergonomique et conviviale, permettant à un utilisateur de
manipuler une représentation en 3 dimensions d'un Rubik's Cube.
Pour le deuxième axe de développement, il s'agit d'intégrer au logiciel une
interface de numérisation d'un Rubik's Cube physique vers le Rubik's Cube
du logiciel. Ainsi, l'utilisateur pourra manipuler et résoudre son Rubik's Cube
par l'entremise du logiciel.
Troisième et dernier axe, l'intégration au logiciel d'une aide à la résolution
d'un Rubik's Cube, i.e. obtenir le(s) prochain(s) mouvement(s) permettant de
résoudre le casse-tête.
Une extension possible au projet serait de construire un robot (en Lego
par exemple) qui résoudrait un Rubik's Cube en le numérisant et en utilisant
l'algorithme de résolution du logiciel. Plus précisément, l'intérêt de cette partie
réside dans la possibilité de rechercher et de développer les moyens d'interactions
possibles entre un ordinateur et du matériel divers.
1
Summary of the Project
The Rubik's Cube is one of the most popular brain teaser, but it is also one
of the most complicated. In order to help others to entertain with the Rubik's
Cube and to solve it, we will have to create a software following three axis.
The rst axis consists in developing a graphical interface with focus on usuability ; that makes possible for the user to manipulate a Rubik's Cube in 3
dimensions.
The second axis adds an acquisition interface of the Rubik's Cube. This will
allow users to solve their own Rubik's Cube with our software.
The last axis gives users the possiblity to solve a Rubik's Cube, either step
by step, or in one straigth.
Building a robot able to solve a Rubik's Cube is one of the possible extension
of the software. This robot would do a numerical capture of the Rubik's Cube
and would use our sofware to solve it. The main goal of this extension is to allow
us to understand how hardwares interact between each other.
2
Table des matières
1 Introduction au domaine d'application
1.1
1.2
1.3
Le Rubik's Cube . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 Description de l'appareil . . . . . . . . . . . . . . . . . . .
1.1.2 Un peu d'histoire . . . . . . . . . . . . . . . . . . . . . . .
1.1.3 Les standards . . . . . . . . . . . . . . . . . . . . . . . . .
Les algorithmes de résolution . . . . . . . . . . . . . . . . . . . .
Mathématiques et Rubik's Cube . . . . . . . . . . . . . . . . . .
1.3.1 Rubik's Cube et théorie des groupes . . . . . . . . . . . .
1.3.2 Nombre de positions diérentes . . . . . . . . . . . . . . .
1.3.3 Nombre de mouvements nécessaires pour revenir en conguration initiale . . . . . . . . . . . . . . . . . . . . . . .
2 Analyse de l'existant
2.1
2.2
2.3
Les logiciels . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Les programmes complets . . . . . . . . . .
2.1.2 Les applets . . . . . . . . . . . . . . . . . .
Acquisition d'images : logiciels, bibliothèques... . .
2.2.1 Les bibliothèques C/C++ . . . . . . . . . .
2.2.2 Les bibliothèques Java . . . . . . . . . . . .
2.2.3 La capture grâce à une application en ash
Analyse d'image . . . . . . . . . . . . . . . . . . .
3 Introduction au projet
3.1
3.2
3.3
3.4
3.5
But . . . . . . . . . . . . . . . . . .
Justication et priorité . . . . . . . .
Démarche . . . . . . . . . . . . . . .
Schéma de structure envisagé . . . .
Schéma de fonctionnement envisagé .
4.1
4.2
4.3
4.4
4.5
4.6
4.7
Relatifs
Relatifs
Relatifs
Relatifs
Relatifs
Relatifs
Relatifs
à
à
à
à
à
à
à
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
l'interface et à la modélisation .
la manipulation . . . . . . . . .
l'acquisition . . . . . . . . . . .
la validité des données fournies
la résolution . . . . . . . . . . .
l'implémentation . . . . . . . .
l'installation . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Besoins non fonctionnels
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
6
8
8
10
13
13
13
14
15
15
15
18
19
19
20
20
21
22
22
22
22
23
23
24
24
25
25
26
26
26
27
5 Besoins fonctionnels
5.1
5.2
5.3
5.4
Relatifs
Relatifs
Relatifs
Relatifs
à
à
à
à
l'interface et à la modélisation .
la manipulation . . . . . . . . .
l'acquisition et à l'initialisation
la résolution . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
28
28
29
29
6 Fonctionnalités implémentées et exemples de fonctionnement 31
6.1
6.2
6.3
Interface et visualisation . . . . . . . . . . . . . . . . . . . . . . .
Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Résolution et contrôle de validité . . . . . . . . . . . . . . . . . .
7 Comparaison : Prévisions / Réalisations
7.1
7.2
7.3
Comparaison : Cahier des charges / Travail réalisé . . . .
7.1.1 Fonctionnalités obligatoires . . . . . . . . . . . . .
7.1.2 Fonctionnalités optionnelles . . . . . . . . . . . . .
7.1.3 Fonctionnalités supplémentaires . . . . . . . . . . .
Comparaison Planning prévisionnel/Planning eectif . . .
Comparaison : Architecture prévue / Architecture réalisée
8 Choix
8.1
8.2
8.3
8.4
Choix du langage .
Choix de la boite à
Bilbiothèque 3D .
Choix des outils . .
. . . . . . . . . .
outils graphique
. . . . . . . . . .
. . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9 Description des algorithmes et structures de données
9.1
9.2
9.3
9.4
9.5
Structure . . . . . . . . . . . . .
9.1.1 Description du module . .
9.1.2 Points forts, points faibles
9.1.3 Problèmes rencontrés . .
Acquisition/Traitement . . . . .
9.2.1 Description du module . .
9.2.2 Points forts, Points faibles
9.2.3 Problèmes rencontrés . .
Modèle 3D . . . . . . . . . . . .
9.3.1 Description du module . .
9.3.2 Points forts, points faibles
9.3.3 Problèmes rencontrés . .
Interface . . . . . . . . . . . . . .
9.4.1 Description du module . .
9.4.2 Points forts, points faibles
9.4.3 Problèmes rencontrés . .
Résolution . . . . . . . . . . . . .
9.5.1 Description du module . .
9.5.2 Points forts, points faibles
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
31
32
32
33
33
33
33
34
35
36
37
37
37
38
38
40
40
40
42
43
43
43
44
45
45
45
47
47
48
48
49
50
50
50
51
10 Tests de validation et de fonctionnements
10.1 Tests aléatoires . . . . . . . . . . . . . . .
10.2 Tests unitaires . . . . . . . . . . . . . . .
10.2.1 Module Structure . . . . . . . . . .
10.2.2 Module Résolution . . . . . . . . .
10.2.3 Module Acquisition . . . . . . . . .
10.2.4 Module Rubik . . . . . . . . . . .
10.3 Tests d'intégration . . . . . . . . . . . . .
10.3.1 Substitutivité . . . . . . . . . . . .
10.4 Tests système . . . . . . . . . . . . . . . .
10.4.1 Mouvements d'une face du Rubik's
10.4.2 Acquisition d'un Rubik's Cube . .
10.4.3 Résolution d'un Rubik's Cube . . .
10.5 Tests en boîte noire . . . . . . . . . .
10.5.1 Questionnaire . . . . . . . . . . . .
10.5.2 Essais d'homologation . . . . . . .
10.6 Tests de fonctionnement . . . . . . . . . .
10.7 Tests en boîte blanche . . . . . . . . .
10.7.1 Tests mémoire . . . . . . . . . . .
11 Extensions et améliorations possibles
11.1 Extensions . . . . . . . . .
11.1.1 Acquisition . . . .
11.1.2 Résolution . . . . .
11.2 Améliorations . . . . . . .
11.2.1 Acquisition . . . .
11.2.2 Visualisation 3D .
11.2.3 Interface graphique
11.2.4 Divers . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Cube
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
52
52
52
52
54
55
55
56
56
57
57
57
61
62
62
63
64
64
64
65
65
65
65
66
66
66
66
67
Annexes
70
A Questionnaire
70
B Informations insolites sur le Rubik's Cube
72
C Howto
74
D Valgrind
77
C.1 Chargement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
C.2 Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
C.3 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Les mots écrits en italique sont présents dans le glossaire
5
74
74
75
Chapitre 1
Introduction au domaine
d'application
1.1 Le Rubik's Cube
Bien que vous ayez certainement déjà eu l'occasion de manipuler un Rubik's
Cube, nous allons maintenant vous présenter brièvement et sous des aspects
moins communs cet objet.
1.1.1 Description de l'appareil
Le Rubik's Cube est comme son nom l'indique un cube formé d'un assemblage de 26 cubes plus petits : les cubics. Chaque face du cube est composée
de 9 cubics. Le Rubik's Cube est un cube 3x3x3 (trois rangées de trois cubics
par face), mais il existe de nombreuses variantes : Pocket Cube (2x2x2), Rubik's Revenge (4x4x4), Professor's Cube (5x5x5), mais aussi d'autres formes
géométriques (tétraèdre, octaèdre...).
Fig.
1.1 Un Rubik's Cube résolu. Crédit : [Wik07a]
Chaque face pivote indépendamment par rapport aux autres grâce à un
mécanisme interne assez complexe composé notamment d'un axe central reliant
6
les cubics centraux de chaque face.
Fig.
1.2 Un Rubik's Cube désassemblé. Crédit : [Wik07a]
Dans l'état résolu d'un Rubik's Cube, chaque face est d'une seule couleur.
Il y a 6 couleurs diérentes au total : le blanc, le bleu, le vert, l'orange, le
rouge et le jaune. Grâce aux rotations des faces, les couleurs du Rubik's Cube
se mélangent. Le jeu consiste alors à réunier la couleur de chaque face.
Fig.
1.3 Un Rubik's Cube mélangé et en cours de rotation. Crédit : [Wik07a]
Il y a 3 types de cubics : les cubics centraux, les cubics d'arêtes et les cubics
de coins. Les 6 cubics centraux sont bien évidemment chacun d'une couleur différente et surtout, propriété importante : ils sont invariants les uns par rapport
aux autres. Par exemple, sur un cube standard le cubic central blanc sera toujours opposé au jaune , le orange au rouge et le bleu eu vert. De ce fait, les 6
cubics centraux forment un repère invariant. Les 12 cubics d'arêtes sont colorés
de 2 couleurs diérentes sur leur 2 faces apparentes. Ils ne peuvent prendre place
qu'à côté d'un cubic central selon une cardinalité 4 points. Bien entendu, on en
retrouve 4 par face et un tel cubic, de par ses 2 faces apparentes, est présent
sur 2 faces du Rubik's Cube. Les 8 cubics de coins sont colorés de 3 couleurs
diérentes sur leur 3 faces apparentes. Ils ne peuvent prendre place que sur les
coins de chaque face. Là encore il existe 4 spécimens par face et ils chevauchent
3 faces.
7
1.1.2 Un peu d'histoire
Le Rubik's Cube a été inventé par Erno Rubik, professeur d'architecture et
sculpteur hongrois, en 1974.
Fig.
1.4 Portrait d'Erno Rubik. Crédit : [Pic00]
La commercialisation dans les magasins de jouets de son pays débute en 1977.
La popularité croissante de ce jeu en Hongrie permet au Rubik's Cube d'être
vendu dans le monde entier en 1980. En l'espace de deux ans, c'est le raz de
marée. En eet, cent millions de Rubik's Cube sont vendus entre 1980 et 1982.
Depuis, le Rubik's Cube a gagné le titre de casse-tête parfait, et aujourd'hui
plus de deux cent millions d'exemplaires ont été vendus.
Durant la période faste du Rubik's Cube, où ce jeu est devenu un véritable
phénomène de mode, de nombreux concours de vitesse ont vu le jour. La pratique du Rubik's Cube de vitesse (résoudre un Rubik's Cube le plus rapidement
possible) est appelée le SpeedCubing. Vu la complexité apparente du casse-tête,
terminer un cube en moins d'une minute apparaît être une grande performance.
Pourtant, le record authentié pour résoudre un Rubik's Cube est de 10,48 secondes, eectué par Toby Mao (Californie) en 2006, au concours national des
États Unis.
D'autres catégories de concours existent : en aveugle, à une main, avec les pieds
ou encore en faisant le moins de mouvements possibles.
D'après [Wik07b], les règles pour les concours sont les suivantes : tout d'abord,
le compétiteur a 15 secondes pour observer le Rubik's Cube puis le remet au
juge de la compétition. Ensuite, il pourra le revoir dès qu'il aura déclenché le
chronomètre. Le chronomètre s'arrête une fois que le compétiteur à posé le Rubik's Cube sur la table et ses deux mains à plat devant lui.
Il existe deux méthodes pour juger les candidats :
Le meilleur temps de résolution parmi un certain nombre d'essais.
La moyenne des temps de résolution parmi un certain nombre d'essais.
1.1.3 Les standards
Il existe quelques désignations standards pour le Rubik's Cube qui sont indispensables pour la compréhension des méthodes de résolutions. Ces standards
servent notamment à représenter les faces du cube et le mouvement qu'on doit
8
produire sur celles-ci. Nous utiliserons les standards anglo-saxons qui semblent
être les plus répandus (voir [Bum]).
Fig.
1.5 Vue des 6 faces d'un Rubik's Cube résolu. Crédit : [Bum]
Des noms ont été choisis pour désigner chaque face en fonction de leur orientation par rapport au joueur. On trouve fréquemment les conventions suivantes :
La face bleue est appelée face UP, abréviation U ;
la face blanche est appelée face FRONT, abréviation F ;
la face rouge est appelée face RIGHT, abréviation R ;
la face verte est appelée face DOWN, abréviation D ;
la face jaune est appelée face BACK, abréviation B ;
la face orange est appelée face LEFT, abréviation L.
Grâce à ces désignations, on peut facilement décrire un mouvement. En
eet, le standard veut que lorsque l'on appelle un mouvement R, cela veut dire
tourner la face RIGHT d'un quart de tour dans le sens horaire . Le quart
de tour est le mouvement de base du Rubik's Cube. On peut aussi décrire le
mouvement inverse, noté alors R', et qui veut dire tourner la face RIGHT d'un
quart de tour dans le sens anti-horaire .
Fig.
1.6 Application d'un mouvement R'. Crédit : [Bum]
Ainsi, en enchaînant U F' B par exemple, on tournera d'abord la face du
haut dans le sens horaire, puis la face de devant dans le sens anti-horaire et
9
enn la face arrière dans le sens horaire.
Il existe encore une autre notation pour désigner le mouvement des faces du
milieu, celles dont on ne voit que les côtés. La face nommée Um est la face située
entre la face UP et son opposée (qui est la face DOWN). La face nommée Fm
est la face située entre la face FRONT et la face BACK, et la face nommée Rm
est la face située entre la face RIGHT et la face LEFT.
Fig.
1.7 Application d'un mouvement Um . Crédit : [Bum]
Cependant, ces types de mouvements ne sont utilisés que si on ne se préoccupe pas de garder un référentiel particulier (si on peut changer la position
d'un centre). C'est pourquoi, on préférera sûrement eectuer un mouvement R'
suivis d'un mouvement L plutôt que de faire un mouvement Rm .
1.2 Les algorithmes de résolution
Vu le nombre exorbitant de congurations possibles, on ne peut résoudre
un Rubik's Cube au hasard, mais rassurez-vous, de nombreuses techniques de
résolutions ont vu le jour depuis 1980. Nous allons présenter ici les principales
méthodes.
Nous allons voir dans la prochaine partie certains algorithmes pouvant orir
un nombre dérisoire de mouvements pour résoudre un Rubik's Cube. Cependant, ils ne sont applicables que par des machines car ils demandent de remplir
des grandes tables de mouvements impossibles à mémoriser dans le cerveau humain (à moins d'être quelqu'un d'exceptionnel bien entendu). Des algorithmes
moins ecaces mais à dimension humaine existent donc pour nous permettre
de résoudre notre casse-tête préféré.
Voici les méthodes les plus employées, tirées de [Wik07b] et de [Wik07c] ;
elles sont pour la plupart utilisées avec plus ou moins d'améliorations, pour le
SpeedCubing par exemple :
Méthode couche par couche , la plus simple et la plus longue, souvent
employée par les débutants :
1. Tout d'abord, il faut réaliser une face entière.
2. Il faut ensuite placer la première couronne, c'est à dire chaque cubic se situant en dessous de la face complétée. En plaçant ensuite
10
convenablement les centres, on obtient ce que nous montre la gure
suivante.
1.8 Rubik's Cube avec la première couronne terminée. La face du dessus
est complète ainsi que la première couche. Les cubics colorés en gris peuvent
être de n'importe quelle couleur.
Fig.
3. Il faut ensuite placer la deuxième couronne, c'est à dire positionner
correctement les cubics d'arêtes se situant en dessous de la première
couche. La gure suivante illustre cette étape.
1.9 Rubik's Cube avec la seconde couronne terminée. La face du dessus,
la première couche et la deuxième couche sont complètes. Les cubics colorés en
gris peuvent être de n'importe quelle couleur.
Fig.
4. Ensuite il faut déplacer les cubics d'arêtes de la dernière couche à
leur places et les positionner correctement.
5. Pour nir, il ne reste plus qu'à positionner les cubics de coins de la
dernière couche et de les placer au bon endroit.
Une deuxième méthode assez simple :
1. Tout d'abord, il faut résoudre une face entière.
2. Ensuite il faut réaliser la face opposée à celle déjà en place. Il faut
d'abord mettre les cubics de coins puis ceux d'arêtes.
11
3. Il faut ensuite bien placer tous les centres en tournant la rangée du
milieu du Rubik's Cube. Désormais il ne reste plus que les cubics
d'arêtes de la couche centrale à placer.
4. Il ne reste plus qu'à placer les cubics d'arêtes de chaque face non
réalisée, et de les orienter comme il faut.
Troisième algorithme : celui de Lars Petrus 1 , SpeedCuber suédois né en
1960. Il termina quatrième du premier championnat du monde de Rubik's
Cube à Budapest en 1982. Son record personnel est à 13,60 secondes. Fan
inconditionnel de cette discipline, il parvient toujours à tenir la dragée
haute aux adolescents qui dominent traditionnellement les compétitions.
Sa méthode est beaucoup plus rapide que les précédentes (60 mouvements
en moyenne), mais plus délicate. Vous pouvez aller voir la page traduite
de la méthode de résolution de Lars Petrus : [Cou97].
1. Pour commencer, il faut réaliser un cube 2x2x2 (de 3 couleurs).
2. Ensuite on va avancer par agrandissements successifs de la forme. Il
faut passer du petit cube à un parallélépipède rectangle de 2x2x3
(formé par 4 couleurs) sans toucher au cube 2x2x2 créé précédemment.
3. Avant d'agrandir à nouveau la forme, il faut arranger les 2 faces libres
de manière à acher une croix sur chacune d'elles.
4. On agrandit encore la forme pour obtenir une forme 2x3x3, on complète ainsi 2 couches du Rubik's Cube.
5. Pour terminer, on place d'abord les 4 cubics de coins restants puis
les 4 cubics d'arêtes.
Quatrième algorithme, celui de Jessica Fridrich 2 , professeur d'informatique à l'Université de New York. Elle est l'auteur de la méthode de résolution la plus prisée des SpeedCubers. Son algorithme est à peu près aussi
rapide que celui de Lars Petrus, mais il est améliorable à certains endroits ;
il est donc très apprécié en SpeedCubing.
1. Cet algorithme commence facilement : il sut de réaliser une croix
sur une face.
2. Ensuite, il faut placer chaque cubic de coin de cette face tout en plaçant le cubic d'arête qui leur correspond (à savoir les cubics d'arêtes
de la rangée du milieu). Ainsi, à cette étape les deux premières
couches du Rubik's Cube sont terminées.
3. Pour nir, il faut orienter puis bien positionner les cubics de la dernière face.
Il faut savoir que pour des mouvements diciles (comme rétablir les 4 derniers
cubics de coins par exemple), des algorithmes de mouvements (appelés patterns )
existent et permettent, par exemple, de permuter un ensemble de 3 cubics sans
bouger le reste du Rubik's Cube. Lorsque l'on débute dans la résolution, on
peut sans peine réussir à terminer son Rubik's Cube en suivant pas à pas ces
méthodes.
Il existe trois types de patterns essentiellement utilisés.
1 Lien vers sa page personnelle : http ://lar5.com/
2 Lien vers sa page personnelle : http ://www.ws.binghamton.edu/fridrich
12
Tout d'abord les opérations dites de cycle de 3 arêtes , qui permutent
3 cubics d'arêtes du Rubik's Cube qui ne sont pas nécessairement sur
la même face à l'origine. Il existe 3 suites de mouvements diérents qui
peuvent eectuer cette opération, à partir de congurations diérentes du
cube.
Ensuite, l'opération de cycle de 3 coins , qui permute 3 cubics de coins
du Rubik's Cube.
Enn, l'opération twist de coins qui permet de faire tourner sur eux
mêmes 3 cubics de coins, et eectue en même temps une opération de
cycle de 3 arêtes.
1.3 Mathématiques et Rubik's Cube
Outre le fait d'être un des jeux les plus répandus au monde, le Rubik's
Cube est aussi un objet en forte relation avec les mathématiques. En eet, sa
structure et les mouvements qui lui sont associés sont en corrélation avec un
objet mathématique fondamental : le groupe.
1.3.1 Rubik's Cube et théorie des groupes
Le Rubik's Cube est associé à la théorie des groupes car l'ensemble des
manoeuvres de celui-ci forme un groupe.
Soit M l'ensemble des manoeuvres du Rubik's Cube, et soit suivi de une
opération. Soit m n et o ∈ M .
m suivi de n ∈ M (une manoeuvre suivie d'une autre manoeuvre est
encore une manoeuvre).
Par conséquent, M est stable par l'opération suivi de .
(m suivi de n) suivi de o ⇔ m suivi de (n suivi de o).
Par conséquent, suivi de est une opération associative.
Soit ² la manoeuvre qui consiste à ne rien faire.
m suivi de ² ⇔ m (une manoeuvre suivie de ne rien faire est toujours
la même manoeuvre).
Ainsi, la manoeuvre qui consiste à ne pas bouger est l'élément neutre.
Chaque manoeuvre peut être eectuée à l'envers. Ceci est donc une manoeuvre inverse.
Voila donc pourquoi l'ensemble des manoeuvres du Rubik's Cube constitue
un groupe. Pour prolonger le plaisir de la théorie mathématique, nous vous
conseillons [Joy 7].
1.3.2 Nombre de positions diérentes
Voici le calcul du nombre de congurations possibles d'un Rubik's Cube
(calcul issu de [Wik07c] et [Pic00]) :
Il y a 12 cubics d'arêtes et chacun d'entre eux possède 2 orientations possibles, ce qui donne 212 possibilités. Or, on ne peut modier l'orientation
d'un seul cubic sans en bouger un autre. L'orientation du dernier cubic
est xée par les autres. Par conséquent on n'a plus que 211 possibilités.
Il y a 8 cubics de coins et chacun d'entre eux possède 3 orientations possibles ce qui donne 38 possibilités. Or, on ne peut modier l'orientation
13
d'un seul cubic sans en bouger un autre. L'orientation du dernier cubic
est xée par les autres. Il ne reste donc plus que 37 possibilités.
Les 12 arêtes peuvent prendre 12 positions diérentes. Si une arête prend
une place, la suivante n'aura plus que onze possibilités, etc. Par conséquent, il y a 12! possibilités de positionnement des cubics d'arêtes.
Les 8 cubics de coins peuvent prendre 8 positions diérentes. Si un coin
prend une place, le suivant n'aura plus que 7 possibilités, etc. Par conséquent, il y a 8! possibilités de positionnement des cubics de coins.
Les cubics centraux ne comptent pas car ils sont invariants.
Il reste une contrainte : lorsque tous les cubics sont positionnés sauf 2, la
position de ces 2 derniers cubics est imposée. En eet, il est impossible de
permuter seulement 2 cubics. Par conséquent, il faut diviser le nombre de
possibilités par deux.
Ce qui nous amène au résultat suivant :
8! × 37 × 12! × 210 = 43252003274489856000
Soit un peu plus de 43 milliards de milliards de possibilités. Il est donc quasiment impossible de résoudre un Rubik's Cube au hasard ; il faudrait plus d'un
millénaire à raison de mille mouvements par seconde pour explorer toutes les
congurations.
1.3.3 Nombre de mouvements nécessaires pour revenir en
conguration initiale
Depuis que le Rubik's Cube a vu le jour, le grand dé est de trouver un
algorithme qui peut résoudre n'importe quel Rubik's Cube en utilisant le moins
de mouvements possibles. Cette question a même fait l'objet de diverses thèses
universitaires !
La première personne à faire descendre le nombre maximal de mouvements en dessous de 100 fut le mathématicien anglais Morwen B. Thistlethwaite.
Dans sa première mouture, le nombre de mouvements maximal de cet algorithme
était de 52 ; ce chire a été ramené par la suite à 42 puis 29 mouvements.
Grâce à la théorie des groupes, on a prouvé mathématiquement qu'il existe
un algorithme pour résoudre n'importe quel Rubik's Cube en 22 mouvements
maximum. Cet algorithme a été baptisé l'algorithme de Dieu (God's Algorithm).
Si personne n'a trouvé l'algorithme de Dieu, il existe cependant un algorithme révolutionnaire qui résout un Rubik's Cube en 18 à 20 coups en moyenne.
Cet algorithme à été mis au point par Herbert Kociemba (chercheur allemand
et fan inconditionnel de Rubik's Cube), en 1992, en améliorant l'algorithme de
Morwen B. Thistlethwaite. Cependant, cet algorithme résout des Rubik's Cube
faciles en 12 mouvements, mais peut mettre plus de 22 mouvements pour des
Rubik's Cube diciles.
Comme précisé plus haut, ces algorithmes ne sont pas applicables par un
humain car ils se servent de tables de mouvements pour calculer la solution. Ils
ne sont donc utilisés que par les ordinateurs.
14
Chapitre 2
Analyse de l'existant
La communauté cubiste (les pratiquants de Rubik's Cube) étant très active
et l'époque d'apparition du casse tête coïncidant avec l'émergence de l'informatique, il existe sur Internet une masse d'informations et de programmes très
conséquente. Toutefois ceci n'est pas qu'un avantage car sélectionner des informations pertinentes dans une telle masse de données n'est pas chose aisée. Au
contraire, la littérature sur le Rubik's Cube n'est pas courante. Il existe certes de
nombreuses références sur le SpeedCubing mais ceci n'est pas enrichissant pour
notre projet. On peut toutefois citer Adventures in Group Theory : Rubik's
Cube , Merlin's Machine, and Other Mathematical Toys [Joy02] , Mathematics of the Rubik's Cube [Joy 7] ou encore The Mathematics of the Rubik's
Cube [Bum] qui traitent du Rubik's Cube sous un aspect purement mathématique, plus particulièrement de la théorie des groupes soutenant le modèle du
Rubik's Cube. An de rester clairs et de bien xer les choses, nous parlerons de
l'existant au niveau logiciel pour mieux cerner ce qui se fait. Pour cela nous nous
appuierons sur une brève analyse des logiciels les plus populaires en la matière.
Dans un autre temps nous entrerons plus en détails sur ce qui existe pour les
diérents objectifs de notre projet.
2.1 Les logiciels
2.1.1 Les programmes complets
Il existe sur Internet de nombreux logiciels se rapportant au Rubik's Cube qui
vont du logiciel professionnel aux réalisations plus amateures voire incongrues.
Dans cette partie nous nous proposons d'analyser un panel des logiciels les plus
populaires. La sélection a été réalisée selon l'ordre d'apparition de ces diérents
programmes sur le robot de recherche Google , mais également par rapport
à leur popularité chez les cubistes, sur la foi des sites spécialisés. Nous verrons
ensuite quelques applications de moindre importance mais qui par un aspect ou
un autre peuvent également nous intéresser.
15
CubeTwister : la référence
Le logiciel le plus populaire semble être CubeTwister 1 . Un programme libre
et Open Source qui peut traiter le cube classique 3*3*3, objet de notre projet, mais aussi des Rubik's Cube plus étonnants : des cubes de taille variable,
la Barrique, le Diamant et l'Octaèdre ! Le programme est paramétrable selon
les souhaits de l'utilisateur. En eet celui-ci reconnaît les notications de mouvements selon 5 conventions diérentes. L'utilisateur a même la possibilité de
dénir son propre système de notations grâce à un système de scripts extrêmement simple à utiliser. De plus ce programme possède une base de données pour
les man÷uvres et les patterns (i.e. une suite de mouvements permettant par
exemple de changer seulement l'orientation de deux coins sans changer le reste
de la conguration du cube). Là encore, un utilisateur lambda peut dénir ses
propres scripts assez facilement. Une fonction de résolution est bien entendu intégrée. L'algorithme utilisé est un des plus ecaces : l'algorithme de Kociemba.
Nous sommes donc en face d'un logiciel qui eectue une véritable résolution.
L'utilisateur peut entrer une conguration de cube et demander au programme
de le résoudre. Nous verrons par la suite que ce n'est en fait que rarement le cas.
Ce logiciel fonctionne sur toutes les plates-formes grâce à la machine virtuelle
Java. En ce qui concerne les défauts, on peut noter une interface un peu austère.
Ceci permet certes une clarté de l'interface mais elle pourra rebuter certaines
personnes. De plus la multitude de fonctionnalités présentes, notamment les
fonctions de script, peut faire passer ce logiciel pour un programme dicile à
utiliser alors que ce n'est pas le cas. Une aide contextuelle aurait peut-être été
la bienvenue. Le logiciel n'est pas doté d'un module de capture par Webcam
ou autre, la conguration d'un cube doit se faire à la souris. Il n'en demeure
pas moins que nous sommes en face d'un excellent logiciel et qui sera à n'en
pas douter une source d'inspiration intéressante pour notre future réalisation,
même si celle-ci n'a pas l'ambition d'être aussi complète que Cube Twister.
Fig.
2.1 Interface du Cube Twister : mise en place des scripts
1 CubeTwister : http ://www.randelshofer.ch/cubetwister2/download.html
16
Cube Explorer 4.0 : le logiciel de M. Kociemba
Herbert Kociemba, le père de l'algorithme éponyme, a aussi développé un
logiciel 2 traitant du problème de la résolution du Rubik's Cube. Disons le tout
de suite, ce logiciel est d'une extrême puissance. Il permet des choses toutes à
fait étonnantes à la mesure de la passion de Kociemba pour le Rubik's Cube.
On peut, outre les fonctions classiques de modélisation et de résolution, éditer
des patterns et les tester grâce à un générateur de cube. On peut également
comparer le nombre de coups nécessaires à la résolution selon les patterns détectés dans les Rubik's Cube, chercher des symétries sur le cube an d'utiliser
les patterns les plus appropriés à la résolution, etc. Par ailleurs, le cube n'est pas
représenté sous une forme 3D classique, comme un cube réel, mais comme un
patron aplati du cube, ce qui n'est pas évident à appréhender pour un novice.
Ce choix est compréhensible car ce programme est clairement destiné au cubiste
possédant de solides connaissances en informatique et en mathématiques. En
eet, non seulement la plupart des fonctionnalités oertes par le programme
ne concerne pas le cubiste amateur, mais en plus, l'interface est, à notre sens,
un exemple de non ergonomie. Menus, sous-menus et réglages divers sont omniprésents. Toutefois il y a quand même quelques points intéressants en ce qui
concerne la manipulation du cube. Une ligne de commande destinée à rentrer
les mouvements au clavier est présente. Le joueur peut ainsi saisir une séquence
de mouvements au lieu d'indiquer ceux-ci un par un. De plus, ce programme est
doté d'un système de capture par Webcam comme demandé pour notre projet.
Assez complet mais pas évident à paramétrer, il assure par contre, d'après nos
tests personnels, une très bonne détection des Webcams. De plus le protocole
qui régit la capture d'un Rubik's Cube peut être une piste intéressante pour
notre logiciel. En eet pour bien capturer chaque face, et surtout leurs orientations les unes par rapport aux autres, trois mouvements de 90° sont demandés
an d'exposer les faces par séries de 2. Ce programme tourne exclusivement sous
Windows. Il est malheureusement impossible de trouver le code source. Nous
continuons nos recherches car les versions précédentes de Cube Explorer étaient
apparemment Open Source.
Fig.
2.2 Cube Explorer : simples amateurs, passez votre chemin !
2 Cube Explorer : http ://kociemba.org/cube.htm
17
2.1.2 Les applets
Après avoir vu les deux mastodontes de la résolution de Rubik's Cube
nous allons voir une autre catégorie de programmes : les applets Java. Ces applets pullulent littéralement sur Internet. Bien évidemment leur qualité est très
variable. Voyons ce qui se fait de plus signicatif dans ce domaine :
Tout d'abord, des applets comme celui de Karl Hörnell 3 qui sont les plus
basiques. Une modélisation du cube et des contrôles à la souris en cliquant sur
la couronne à faire tourner. Il n'y a aucun algorithme de résolution implémenté
et la représentation 3D est souvent sommaire. Ceci ne sera pas très intéressant
pour nous. Nous signalons simplement leur existence.
Bien sûr, il est possible de trouver des applets de bien meilleure qualité.
L'Applet Magic, par exemple, est un applet où le cube est assez bien modélisé
et où les mouvements se font de manière instinctive. Comme beaucoup de bons
applets java sur le Rubik's Cube, nous avons trouvé celui-ci sur le site [Pic00].
Malheureusement, il est impossible de le trouver ailleurs. Nous nous permettons
donc de donner ce site comme référence.
2.3 L'Applet Magic : maniable, agréable, mais pas de résolution à proprement parlé
Fig.
Malheureusement le programme ne permet pas de rentrer sa propre conguration de cube, il propose un puzzle avec un choix dans le niveau de diculté.
En eet, ce type de programmes ne résout pas vraiment le cube, ils eectuent
simplement une suite de mouvements qu'ils gardent en mémoire. Quand l'utilisateur demande de résoudre le Rubik's Cube, ceux-ci font simplement les mouvements inverses de ceux qu'ils avaient eectués lors du mélange, en ajoutant
éventuellement l'inverse de ceux entrés par l'utilisateur. Bien entendu, ce type
de programmes n'inclut pas d'acquisition par Webcam non plus. Toutefois la
représentation des cubes ou l'ergonomie dans ces programmes sont parfois impressionnantes et pourraient être intéressantes pour notre projet.
Enn une dernière catégorie de logiciel un peu moins attrayante, mais qui
est toute aussi intéressante pour nous : les solveurs de Rubik's Cube qui ne
modélisent pas en 3 dimensions le cube, mais orent résolution et manipulation
3 http ://www.javaonthebrain.com/java/rubik/
18
en s'exécutant sur une console. On peut citer par exemple le Dimcik's Rubik 4
écrit en Java.
En eet ces programmes souvent austères sont souvent très bien codés et
Open Source. Il pourrait être intéressant pour nous de voir l'architecture adoptée
par les programmeurs ainsi que la (ou les) structure(s) représentant le Rubik's
Cube en mémoire. En eet, pour une manipulation facile de la structure, avec un
temps d'accès acceptable, le choix de celle-ci doit être particulièrement rééchi.
Ainsi, dans le cas du Dimcik's Rubik, on trouve un système de tableau à 3
dimensions qui permet une implémentation des mouvements du Rubik's Cube
excessivement concise.
2.2 Acquisition d'images : logiciels, bibliothèques...
Dans le domaine de la capture d'image provenant d'une Webcam, l'existant
est beaucoup moins vaste que dans le cas des programmes de modélisation de
Rubik's Cube, notamment quand on a l'ambition d'orir une application portable et libre de droit.
2.2.1 Les bibliothèques C/C++
On peut citer certaines bibliothèques en C++ comme PWLib 5 qui provient
du framework OpenH323 destiné à la vidéo-conférence. Cette bibliothèque sert
de fondation pour le framework en fournissant des classes de base pour les string,
le multithreading... ainsi que pour l'accès aux périphériques vidéo. Cependant
les conteneurs de cette bibliothèque ne sont pas compatibles avec ceux de la
STL ; elle est également trop lourde en terme de place et de manipulation par
rapport à nos besoins. De plus PWLib n'est pas compatible avec Mac OS X et
elle est assez mal documentée.
En C++, il existe également OpenWengo 6 : application de Voix par IP :
version libre et Open Source de Skype. Dans la nouvelle version (version ng), elle
ore une architecture modulaire, il est donc possible de récupérer facilement le
code pour la Webcam. OpenWengo est portable sur les trois plate-formes voulues
mais, revers de la médaille, il est basé sur un code en cours de développement,
d'où des problèmes récurrents de compilation, et il peut toujours y avoir des modications de l'API. Même si nous avons trouvé des choses susceptibles d'être
plus intéressantes pour nous, cette application n'est pas à négliger pour l'instant.
Autre bibliothèque en C++ : PortVideo 7 est une bibliothèque gérant l'accès au périphériques d'acquisition vidéo : cette application a l'avantage d'être
assez légère, totalement portable (win32, Linux, MacOS X, testée sur win32 et
Linux), de gérer les caméras sur USB et Firewire et elle est bien entendu Open
Source. Quelques petits tests réalisés donnent des résultats encourageants.
Enn dernière piste explorée : OpenCV,
8
une bibliothèque C Open Source
4 http ://dimm.ifrance.com/old/dimakubik.html
5 PWLib : http ://www.openh323.org/PWLib
6 OpenWengo : http ://ww.openwengo.org
7 PortVideo : http ://www.iua.upf.es/mtg/reacTable/ ?portvideo
8 OpenCV : http ://www.intel.com/technology/computing/opencv/index.htm
19
en partie développée par Intel. Les possibilités semblent vastes et une version
Linux existe également. Toutefois, à l'instar de la PWLib, cette application est
peut-être un peu trop dense pour nos besoins même si elle reste une solution
envisageable. Elle a cependant comme avantage d'orir certaines fonctions de
traitement d'image.
Un autre moyen de détecter et d'acher le signal provenant d'une Webcam
est l'utilisation du module dédié de aMSN. Cependant, ce module est entièrement écrit en Tool Command Language et la reprise de code s'annonçait fastidieuse de par notre manque de connaissance de ce langage et l'absence totale
de commentaire dans le code source.
2.2.2 Les bibliothèques Java
En Java, les applications de ce type semblent plus limitées et reposent uniquement sur le Java Media Framework 9 . On peut noter de lourdes dicultés à
installer ce framework durant nos tests : erreurs de compilation, de bibliothèques
... De plus l'engouement pour le JMF ne semble pas être énorme dans le monde
des développeurs. Toutefois une application comme celle de David Fischer 10
permettant de stocker un ux vidéo et de l'exploiter ensuite, serait pour nous
largement susante. Reposant sur Java, elle est censée être totalement portable.
Lors d'un rapide essai nous avons pu voir que la réalité n'est pas aussi idyllique.
Réussissant tout de même à la faire fonctionner sous Windows, le résultat est
alors globalement positif. Le problème est que le programme, tout du moins
la partie concernant la caméra USB, doit être conguré par l'utilisateur avant
d'être ensuite compilé. Nous ne sommes clairement pas en face d'une solution
grand public. Néanmoins, certaines parties du code seront peut-être réutilisables.
2.2.3 La capture grâce à une application en ash
Enn, dernière solution trouvée lors de nos recherches : l'utilisation de la
technologie Flash. En eet depuis la version 8 de Flash 11 , la classe BitmapData
a fait son apparition et permet de manipuler des images. La photo prise est
ensuite stockée sur le disque dur grâce à un petit script PHP. Les avantages de
l'utilisation de cette technologie sont un repérage immédiat de la quasi-totalité
des Webcams du marché, pas seulement les Webcams USB, mais aussi celles
qui sont intégrées (comme sur les ordinateurs portables), une portabilité sur
les trois systèmes d'exploitation majeurs du marché. De plus, elle dispense de
posséder des solutions lourdes à côté pour faire tourner l'application.
Un programme comme WebSnap 12 permet de réaliser ceci facilement et est
assez bien documenté. Cependant, cela implique l'utilisation de JDIC 13 pour
incorporer le code Flash dans une application Java. JDIC est un projet SUN
permettant la présence dans une application Java de nombreux outils, avec entre
9 JMF : http ://Java.sun.com/products/java-media/jmf/
10 http ://www.mutong.com/scher/java/usbcam/
11 http ://www.adobe.com/fr/products/ash/ashpro/
12 http ://ww.homeunix.net/category/ash/
13 https ://jdic.dev.java.net/
20
autre la possibilité d'incorporer un Browser l est donc concevable d'émuler un
minibrowser puis de charger notre petite application Flash dessus. Des exemples
assez bien pensés circulent sur Internet ; il reste toutefois à les tester. Le choix
de la solution la plus adaptée à nos besoins devra donc être débattu dans le
groupe ainsi qu'avec le client, notamment en fonction du temps que nous nous
impartirons pour développer la capture, sachant qu'elle est prioritaire dans le
projet. Le temps alloué à sa mise en place sera donc assez conséquent.
2.3 Analyse d'image
Pour l'analyse d'image, les solutions sont multiples et indépendantes du ou
des langages de programmation choisis. En eet, ce domaine est particulièrement prisé par la recherche et le choix dans les algorithmes d'analyse d'images
est très conséquent. On peut penser notamment à associer des solutions comme
la détection de contour pour repérer le cube sur notre image, grâce par exemple
à l'application de matrices comme Sobel ou bien encore Prewitt puis la transformée de Hough pour repérer les lignes sur notre Rubik's Cube. Dans un troisième
temps, on pourra essayer de récupérer sur le quadrillage théoriquement obtenu
grâce à Hough la couleur de chacune des cases qui devrait être chacune une face
d'un cubic. Bien sûr cette théorie sera implacablement démontée par l'épreuve
de la réalité ! Mais les solutions ne manquent pas dans ce domaine et peuvent
généralement se trouver déjà codées pour eectuer des tests assez rapidement.
Il faudra toutefois justement envisager une lourde phase de tests sachant que le
public visé est large et que l'utilisateur est considéré par défaut comme imprévisible. Ces tests devront notamment déterminer la tolérance de notre solution
en fonction du fond sur lequel se trouve le Rubik's Cube, de son orientation,
de la luminosité... an, si celle-ci est trop restrictive, d'envisager soit une toute
autre solution, basée par exemple sur le détecteur de Harris ou la segmentation,
soit une refonte partielle de celle existante.
21
Chapitre 3
Introduction au projet
3.1 But
Le but du projet est donc d'implémenter un logiciel de manipulation, de
résolution et d'acquisition de Rubik's Cube. De l'analyse de l'existant, il ressort
que l'interface graphique est un des points faibles des logiciels présents sur le
marché. La facilité d'utilisation, l'interface de navigation et de manipulation du
cube sont donc des points à améliorer. De même, l'acquisition d'un cube pour
le manipuler et le résoudre dans le logiciel est une fonctionnalité qui pour le
moment n'a pas été souvent implémentée dans un logiciel open source. Quand
ce fut le cas (Cube Explorer), le logiciel n'était ni multi-OS ni orienté grand
public.
3.2 Justication et priorité
Le projet vise donc à améliorer certaines fonctionnalités déjà existantes sur
certains logiciels comme par exemple la manipulation du Cube tout en incluant
une possibilité rarement présente : l'acquisition. On devra essayer d'avoir une
portabibilité sur les systèmes Microsoft (Windows XP), Linux et si possible Mac
OS X. Nous implémenterons donc les modules du logiciel dans l'ordre suivant :
Modélisation du cube, en orant plusieurs possibilités de navigation : claviers et/ou à la souris. Une représentation du cube en 3D est obligatoire.
Tout autre représentation, tel que le cube déplié, est optionnelle.
Acquisition de la conguration d'un Rubik's Cube, par un périphérique
vidéo, un ensemble d'image ou une saisie des cubics à la souris.
Résolution du cube par un algorithme.
La mise en place d'un robot manipulant le Rubik's Cube (optionnel voir
utopiste).
3.3 Démarche
La structure pour le cube n'est pas clairement dénie. Le choix eectué sera
déterminant pour le reste du projet car les autres modules du projet notamment
l'algorithme permettant la manipulation reposent tous d'une manière ou d'une
22
autre sur cette structure. Bien sûr la mise en place d'un adaptateur est envisageable mais une solution plus élégante sans cette artice serait préférable. De
multiples tests seront eectués an de choisir en toute connaissance de cause.
Concernant l'acquisition, elle sera faite en utilisant une librairie externe, peutêtre adaptée à nos besoins (cf analyse de l'existant). L'analyse d'image sera faite
à partir de la transformée de Hough, voir [DH72] , et/ou du détecteur de Harris,
voir [HS88]. Diérentes méthodes pour éclaircir/assombrir l'image selon nos besoins d'analyse des clichés seront également implémentés. Ceci toujours dans le
même but à savoir orir une souplesse d'utilisation maximale pour l'utilisateur.
Si ces méthodes ne fonctionnent pas, nous utiliserons alors une autre méthode
ou compléterons la précédente avec une technique qui consisterait à donner un
cadre de placement du Rubik's Cube sur le signal vidéo pour nous faciliter le
traitement des résultats.
3.4 Schéma de structure envisagé
Fig.
3.1 Schéma de Structure
3.5 Schéma de fonctionnement envisagé
Fig.
3.2 Schéma de structure
23
Chapitre 4
Besoins non fonctionnels
An de cerner les besoins nécessaires au développement de notre logiciel
de modélisation, d'acquisition et de résolution du Rubik's Cube, nous avons
commencé par écrire un questionnaire que nous avons soumis à un panel de
personnes. L'analyse des réponses à ce questionnaire nous a permis de mieux
cerner certains besoins de conception de l'interface, de la partie concernant
l'acquisition ou encore la résolution, et enn du système d'aide à mettre en
place. Vous trouverez ce questionnaire et son analyse en Annexe (cf. Annexe
A).
4.1 Relatifs à l'interface et à la modélisation
L'interface de l'application sera conçue de telle manière que l'utilisateur
pourra modéliser son cube (en utilisant la souris et la molette de délement
de celle-ci), ou encore lancer la phase d'acquisition via les chiers images ou
la Webcam, et enn lancer la résolution. Pour ceci, des boutons de raccourcis
explicites seront préférés à des menus déroulants trop chargés, dans un souci de
clarté.
Toujours dans un souci de clarté, il ne faut pas surcharger l'achage ; l'utilisateur pourra donc masquer ou montrer à sa guise l'écran de contrôle de la
Webcam. An de tester si l'interface de l'application est intuitive, un test d'utilisation sera eectué sur un panel de testeurs n'ayant pas forcément de connaissances en informatique au sens large, ni en Rubik's Cube.
De plus, un questionnaire post-conception reposant sur le même type de questions utilisées dans le questionnaire pré-conception sera réalisé an d'interroger
les utilisateurs sur la qualité du logiciel produit et de le comparer à ce qui existe
déjà dans le domaine d'application de notre logiciel.
Lorsque l'utilisateur fera tourner le cube ou pivoter les diérentes faces, nous
devrons garantir un minimum de uidité an d'éviter un achage saccadé. Nous
ferons donc des tests sur les nombres d'images par seconde sur plusieurs congurations matérielles diérentes. Si l'on passe sous un seuil xé (par exemple 18
images par seconde), il faudra soit baisser la qualité de l'achage si cela s'avère
possible, soit informer l'utilisateur que sa machine n'est pas assez puissante et
que par conséquent des ralentissements peuvent se produire.
24
4.2 Relatifs à la manipulation
L'utilisateur commandera les diérentes opérations de rotation des faces du
cube en se servant de raccourcis claviers ou en entrant une instruction ou une
liste d'instructions sur une ligne de commande ceci dans un souci d'orir de la
souplesse d'utilisation. Nous utiliserons la terminologie anglo-saxonne : U désigne la face du dessus (Up), D la face du dessous (Down), L la face
de gauche (Left), R la face de droite (Right), F la face de devant (Front)
et enn B la face de derrière (Back). Ces faces seront dénies par rapport
à une référence (soit en modélisant un repère orthonormal, soit par exemple en
décidant que la face blanche sera la face supérieure, la rouge la face de gauche,
etc.)
Ici, l'interprétation correcte des commandes sera testée avec des multitudes d'enchaînements de commandes diérentes an de nous rendre plus conants quant
à la qualité de l'interpréteur mis en place.
Nous devrons tester des raccourcis claviers utilisés par notre logiciel et d'autres
non utilisés, notamment an de vérier qu'il n'y a pas de conits avec des raccourcis claviers propres au système d'exploitation.
4.3 Relatifs à l'acquisition
L'acquisition devra être la plus simple possible : ce besoin non fonctionnel
nécessitera des compromis entre exibilité et ecacité. En eet, il va falloir xer
des règles quant à la manière de fournir six images d'un cube depuis la Webcam
ou depuis un disque quelconque (OPTIONNEL) :
Si l'utilisateur capture son Rubik's Cube via un périphérique de type Webcam, des conditions d'acquisition particulières devront être respectées an
de pouvoir exploiter les images capturées. Par exemple, le cube devra être
présenté sur un fond blanc, ou uni, de face,... sont des conditions d'acquisition qui pourront être choisies.
Si l'utilisateur fournit six images depuis un moyen de stockage quelconque,
il faudra que les chiers respectent un ou plusieurs formats d'image, qu'ils
représentent des faces orientées dans un certain sens et qu'ils aient un nom
respectant ceux du standard imposé par le logiciel : par exemple, il faudra
nommer les chiers : white.jpg ou encore red.bmp suivant le ou
les formats d'images choisis.
Dans le cas de l'acquisition à l'aide d'un périphérique de type Webcam, si
jamais ce périphérique n'était pas détecté, il faudrait le signaler à l'utilisateur
et lui proposer de modéliser son Rubik's Cube à l'aide de photos ou à l'aide de
la souris pour une modélisation manuelle.
Dans le cas où la phase d'acquisition se déroule visiblement bien, il faut garantir
que l'image numérisée corresponde bien au cube présenté devant la Webcam ;
nous pouvons pour cela demander à l'utilisateur de valider l'image numérisée ou
de recommencer la numérisation si l'image a subi une mauvaise acquisition ou
un mauvais traitement. Si l'utilisateur décide de fournir six images contenant
respectivement chaque face du cube à modéliser, il faut tester les diérents
formats de chiers supportés. Si un format n'est pas supporté, il faut le signaler
pour que l'utilisateur puisse fournir les images dans un autre format, ou bien
lancer une acquisition par Webcam ou une modélisation à l'aide de la souris.
25
Avec ce type d'acquisition, il faudra être très rigoureux quant à l'orientation des
faces fournies dans les chiers.
4.4 Relatifs à la validité des données fournies
Si l'utilisateur modélise son cube à l'aide la souris, il faut vérier que le
cube ainsi donné en paramètre est valide (i.e. possible à résoudre car conforme
aux standards de fabrication d'un Rubik's Cube). Ainsi, s'il modélise un cube
qui contient par exemple 10 cubics rouges, il faudra le signaler et reprendre la
modélisation à la souris.
Nous mettrons donc en place une série de tests courts qui compteront par
exemple qu'il y a exactement 9 cubics de chaque couleur, que deux couleurs
opposées ne se trouvent jamais sur un même cubic ou encore qu'il n'y a pas
plusieurs faces centrales de la même couleur, etc.
(OPTIONNEL) Si cette batterie de test ne détecte pas d'erreur, nous pourrons
lancer en arrière plan l'algorithme de résolution implémenté en le bornant à un
nombre de coups très supérieur au nombre maximal de coups nécessaires pour
résoudre le Rubik's Cube. Si l'algorithme n'a pas réussi à résoudre le cube après
ce nombre de coups, alors nous pouvons en déduire que le jeu de données fourni
est erroné, et prévenir l'utilisateur que son cube est invalide.
4.5 Relatifs à la résolution
Il faudra lancer l'algorithme de résolution sur un nombre très important de
congurations de cubes diérentes an d'être conants quant à la qualité de
celui-ci.
(OPTIONNEL) Nous implémenterons un compteur de coups restant qui indiquera le nombre de coups séparant l'état actuel du cube de l'état résolu en
appliquant l'algorithme implémenté. Il faudra veiller à représenter le cube par
la structure la plus adaptée possible, pour pouvoir utiliser l'algorithme de résolution avec cette structure.
4.6 Relatifs à l'implémentation
Le programme devra être totalement modulaire : ceci est nécessaire pour
avoir un programme propre, améliorable à souhait : si l'utilisateur veut représenter son cube en trois dimensions ou en vue éclatée par exemple, l'utilisation
de modules est indispensable ; de même si l'on possède plusieurs algorithmes de
résolution, plusieurs moyens de capture ou d'acquisition.
Le ou les langage(s) de programmation choisi(s) sera (seront) un choix reposant
essentiellement sur l'existence de bibliothèques permettant de gérer les périphériques de type Webcam, d'autres permettant les traitements d'images, la
construction et l'achage d'objets en trois dimensions...
Notre programme devra être portable : nous souhaitons qu'il fonctionne sous
Linux, Windows et Mac OS X. Les deux premiers systèmes d'exploitation seront
ceux sur lesquels nous accorderons le plus d'importance dans un premier temps
(puisque ce sont ceux sur lesquels nous pourrons faire tous les tests). Nous ferons
donc plusieurs exécutions de notre application sur des systèmes d'exploitation
26
diérents en tentant de vérier que son exécution est identique dans le sens où
l'application doit répondre à son cahier des charges sur ces diérents systèmes
d'exploitation. La portabilité sera un critère majeur du choix des bibliothèques
et donc du langage de programmation.
Enn, il faudra assurer une compatibilité maximale du logiciel avec les périphérique de type Webcam qui sont très nombreux sur le marché et donc bien sûr
pas tous identiques.
4.7 Relatifs à l'installation
Destiné à être un logiciel grand public, notre programme de Rubik's Cube
se devra d'être facile à installer (notamment dans sa version Windows) pour
quiconque connaît un minimum l'informatique. Pour se faire, nous essayerons
de nous rapprocher du système d'installation des logiciels commerciaux notamment sous Windows où tout se fait à la souris par l'entremise de quelques clics.
On pourra éventuellement faire tester par des utilisateurs notre système d'installation pour voir s'ils trouvent sa mise en place abordable.
27
Chapitre 5
Besoins fonctionnels
5.1 Relatifs à l'interface et à la modélisation
Nous devons modéliser un Rubik's Cube en trois dimensions : pour cela,
il faudra utiliser les couleurs standards du Rubik's Cube ociel : le rouge, le
orange, le vert, le bleu, le jaune et le blanc. De plus, il faudra respecter certaines
dispositions des faces centrales : en eet, dans un Rubik's Cube ociel, le blanc
est toujours opposé au jaune, le rouge au orange, et enn le bleu au vert.
Nous devrons proposer à l'utilisateur une vue en trois dimensions du Rubik's
Cube modélisé. (OPTIONNEL : Nous implémenterons aussi une vue éclatée du
cube pour l'utilisateur.)
5.2 Relatifs à la manipulation
Une fois que le Rubik's Cube sera modélisé et aché à l'écran, l'utilisateur
devra pouvoir tourner autour de celui-ci à sa guise. Pour des raisons de facilité
et d'ecacité lors de la manipulation du Rubik's Cube, soit il faut modéliser un
repère orthonormal, soit il faut remettre le cube dans sa position initiale une fois
que l'utilisateur a ni de tourner autour de celui-ci. De cette façon, l'utilisateur
pourra toujours se repérer lors de l'exécution d'un mouvement. L'utilisateur utilisera la souris pour faire pivoter le cube comme bon lui semble.
Il faudra pouvoir faire pivoter les faces du Rubik's Cube comme l'on ferait pivoter les faces d'un cube réel. Pour ceci, soit l'utilisateur utilisera des raccourcis
claviers correspondants aux diérents mouvements possibles, soit il tapera sur
une ligne de commande des instructions ou une suite d'instructions reprenant la
terminologie anglo-saxonne décrivant tous les mouvements possibles à eectuer.
Il faudra donc tester, au moyen de tests en boîte noire, que les faces du cubes
pivotent de manière satisfaisante. En eet, un problème pourra se poser si nous
ne nous préoccupons pas des cas où l'utilisateur actionnerait plusieurs mouvements à la fois. Il faudra donc vérier au moyen de ces tests que les faces pivotent
une par une sur le modèle 3 dimensions. Il faudra aussi coupler ces tests avec
des tests en boîte blanche. En eet, il faudra vérier que lors de l'exécution de
mouvements simples, puis de plusieurs mouvements simultanés, la structure de
donnée représentant le Rubik's Cube soit correctement modiée.
28
5.3 Relatifs à l'acquisition et à l'initialisation
L'utilisateur devra pouvoir initialiser un Rubik's Cube dans une position
donnée an de le résoudre. Cette initialisation pourra se faire de quatre manières
diérentes :
Soit en générant un cube aléatoirement à l'aide d'un bouton sur l'interface
graphique de l'application.
Soit l'utilisateur pourra créer de toute pièce la conguration initiale de son
cube en indiquant la couleur de chaque facette du Rubik's Cube. Il pourra
donner des couleurs aux cubics grâce à sa souris, en pointant un cubic et en
changeant sa couleur grâce à la molette. On considérera dans un premier
temps que l'utilisateur fournit un jeu de données qui correspond à une
situation réelle, et donc résoluble. (OPTIONNEL : nous implémenterons
une vérication du jeu de données fournies)
(OPTIONNEL) Soit l'utilisateur fournira six images dans un format que
l'on déterminera et qui représenteront les six faces du Rubik's Cube à
modéliser. Il faudra pour cela dénir des conventions quant à l'orientation
des faces sur les images fournies.
Enn l'utilisateur pourra se servir d'une Webcam. Il pourra ainsi présenter
son Rubik's Cube devant celle-ci et permettre l'acquisition des six faces en
prenant six clichés de son cube. Il faudra bien sûr qu'il ait à sa disposition
une petite fenêtre dans laquelle se situera en temps réel la visualisation de
ce qu'il s'apprête à numériser.
Il faudra présenter à l'utilisateur la face numérisée an qu'il puisse vérier si
elle est correcte. Dans le cas contraire, l'utilisateur pourra à nouveau numériser
la face incorrecte.
5.4 Relatifs à la résolution
Notre client désire avant tout un programme interfacé qui permet la modélisation et l'acquisition d'un Rubik's Cube. Selon l'avancement du développement
du logiciel, soit nous intégrerons un algorithme de résolution existant, soit nous
en implémenterons un.
Quand cet algorithme tournera, le Rubik's Cube modélisé devra eectuer en
même temps les mouvements calculés par l'algorithme. L'utilisateur aura la
possibilité d'eectuer les mouvements pas à pas an, pas exemple, de pouvoir
résoudre son Rubik's Cube physique en même temps. Il existe déjà plusieurs
algorithmes concernant la résolution du Rubik's Cube ; dans un premier temps,
si la structure de données utilisée le permet, nous tenterons d'intégrer un algorithme déjà écrit dans notre programme.
Attention : dans le cas d'un Rubik's Cube généré aléatoirement, l'algorithme de
résolution doit réellement résoudre le cube, et non pas se contenter d'empiler
les transformations eectuées puis de les refaire en sens inverse !
Nous implémenterons un compteur de coups restants qui indiquera le nombre
de mouvements restants tel qu'il est calculé par notre algorithme.
Un système d'aide devra être mis en place an que l'utilisateur ait les informations nécessaires à l'utilisation du logiciel. Cette aide concernera notamment :
Les diérentes façons de représenter le cube.
29
Les commandes pour faire pivoter le cube.
Les commandes pour exécuter les diverses rotations des faces du Rubik's
Cube.
Les moyens d'acquisition et leur utilisation simpliée.
La signication du nombre aché par le compteur (i.e. nombre de coups
restants d'après l'algorithme implémenté, et non pas nombre minimal de
coups restants, les deux pouvant être diérents)
30
Chapitre 6
Fonctionnalités implémentées
et exemples de
fonctionnement
En ce qui concerne la portabilité, le logiciel n'a pas pu être réellement testé
sous Mac OS X, car nous n'avions pas la possibilité d'accéder à un système Mac.
6.1 Interface et visualisation
L'utilisateur se voit oertes les possibilités suivantes grâce au logiciel :
Fonctionnalités de base
Au lancement du logiciel un cube résolu est aché. L'utilisateur peut le
manipuler par diérents biais (cf. partie Manipulation). Il peut, s'il le souhaite,
générer un cube aléatoirement grâce à l'icône prévue à cet eet. A tout moment
du jeu il lui est possible de sauvegarder et de charger son Rubik's Cube.
Au lancement de l'application sont proposées les vues en 2 dimensions et
en 3 dimensions du Rubik's Cube. Lorsque le panneau d'acquisition vidéo est
ouvert, le modèle en 3 dimensions est masqué.
Acquisition
Concernant l'acquisition, deux options sont disponibles :
L'utilisateur lance l'interface de capture vidéo et suit les instructions données par le logiciel quant à l'ordre et l'orientation des faces du Rubik's
Cube à présenter devant la caméra.
L'utilisateur eectue une capture manuelle. Pour ce faire, il peut utiliser
les boutons ou la molette de la souris. La fenêtre d'acquisition manuelle
possède également une ligne de commandes pour rentrer directement la
séquence de couleurs. On utilise une correspondance lettre ↔ couleur pour
décrire ligne par ligne et face par face la conguration du Rubik's Cube.
Toutefois lorsque l'utilisateur valide la ligne de commande, celle-ci est
entièrement interprétée sans vérier sa validité.
31
Visualisation
En ce qui concerne la visualisation, l'interface propose deux modèles :
Une visualisation en 3 dimensions qui permet d'acher ou de masquer les
axes sortant du centre de chaque face du Rubik's Cube. Ces axes ont pour
couleur celle de la face dont ils sont issus. Ils ont pour but de faciliter la
manipulation du Rubik's Cube en lui permettant de voir les couleurs des
faces cachées.
Une visualisation en 2 dimensions, qui représente le cube déplié.
6.2 Manipulation
La manipulation du cube peut se faire via deux méthodes :
En utilisant les raccourcis claviers. Dans ce cas de manipulation, les fonctionnalités Annuler et Refaire sont à la disposition de l'utilisateur.
En utilisant la ligne de commandes. Il est possible d'eectuer au coup par
coup les mouvements de la séquence saisie ou de valider la séquence dans
son ensemble. Un curseur permet de parcourir la ligne de commandes dans
un sens ou dans l'autre.
6.3 Résolution et contrôle de validité
L'utilisateur a à sa disposition une fonctionnalité de résolution. Lorsque
celui-ci lance le calcul de la solution, la séquence de mouvements correspondante
s'ache sur la ligne de commandes. L'utilisateur peut utiliser cette séquence
comme indiqué dans la description de la manipulation.
L'algorithme de résolution permet également de vérier la validité d'un Rubik's Cube entré par l'utilisateur via les diérentes fonctions d'acquisition. Celuici peut décrire brièvement les raisons de la non-validité du Rubik's Cube.
32
Chapitre 7
Comparaison : Prévisions /
Réalisations
7.1 Comparaison : Cahier des charges / Travail
réalisé
Nous allons détailler ici uniquement les fonctionnalités, obligatoires ou optionnelles, spéciées dans les besoins qui n'ont pas été implémentées ou qui diffèrent de ce qui était prévu. De plus, nous décrirons celles qui ont été ajoutées
au cours du développement.
7.1.1 Fonctionnalités obligatoires
Toutes les fonctionnalités obligatoires spéciées dans le cahier des charges
ont été réalisées, excepté le calcul du nombre d'images par seconde et donc la
possibilité de faire des tests sur celui-ci an de baisser la qualité d'achage en
cas de valeur trop faible.
7.1.2 Fonctionnalités optionnelles
Parmi les fonctionnalités optionnelles, nous avons pu en implémenter certaines ; d'autres, par contre, n'ont pas été réalisées.
Fonctionnalités implémentées :
Vue dépliée du cube.
Vérication des données après acquisition. Cette fonctionnalité est opérationnelle et est basée sur l'algorithme de résolution (cf. Fonctionnalités
implémentées).
Le compteur de coups restant. Cette fonctionnalité est partiellement
implémentée. En eet, le compteur n'est pas actualisé après chaque
mouvement. Il indique le nombre de coups restant avant d'atteindre
l'état initial du Rubik's Cube uniquement lorsque l'utilisateur déclenche
la résolution.
Fonctionnalités non-implémentées :
Internationalisation de l'interface. Le travail nécessaire à cette fonctionnalité a été en partie réalisé mais n'est pas abouti. L'interface n'est donc
33
disponible qu'en français.
Acquisition via des photos des diérentes faces du Rubik's Cube. Cette
fonctionnalité n'a pas du tout été abordée.
7.1.3 Fonctionnalités supplémentaires
Nous avons implémenté les fonctionnalités suivantes, bien qu'elles ne soient
pas inscrites dans le cahier des charges :
Généricité de certains modules : structure, visualisation 2D et acquisition.
Nous reviendrons plus en détail sur cette généricité dans la description des
structures et des algorithmes.
Nous avons ajouté un bouton coulissant permettant de régler la vitesse de
rotation des faces du modèle en 3 dimensions.
Ligne de commande dans le panneau d'acquisition manuelle (cf. Fonctionnalités implémentées).
Possibilité de corriger chaque face du cube immédiatement après sa capture vidéo.
34
7.2 Comparaison Planning prévisionnel/Planning
eectif
Voici le planning initialement prévu, inclus dans le mémoire intermédiaire :
Taches \Semaines
Implémentation
du cube
Modélisation 3D
Acquisition
Webcam
Manipulation
du cube
Interface
graphique
Traitement
Webcam
Algorithme
de résolution
Tests
naux
Mémoire
nal
1
26/02
X
X
X
2
05/03
X
X
X
X
X
3
12/03
4
19/03
5
26/03
6
02/04
X
XX
X
X
X
XX
XX
XX
XX
XX
Le planning est un élément déterminant de la gestion d'un projet et le nôtre
s'est avéré discutable sur certains points. Par exemple, nous avons consacré
beaucoup de temps à la partie structure qui s'est nalement révélée être un
élément du logiciel moins fondamental que prévu (cf. Architecture). Nous avons
aussi sous-estimé le temps nécessaire à la représentation en 3 dimensions du
cube. Si au nal notre cube se révèle plutôt esthétique, son implémentation a
subi un retard de presque 10 jours. Le temps perdu sur la structure aurait
par exemple pu être consacré à l'amélioration de l'acquisition, notamment la
détection des couleurs qui aurait pu être dynamique. De plus, nous aurions pu
passer plus de temps sur l'ergonomie de l'interface et sur les tests.
35
Voici donc le planning réellement suivi :
Taches \Semaines
Implémentation
du cube
Modélisation 3D
Acquisition
Webcam
Manipulation
du cube
Interface
graphique
Traitement
Webcam
Algorithme
de résolution
Tests
naux
Mémoire
nal
1
26/02
X
X
X
2
05/03
X
X
X
3
12/03
4
19/03
5
26/03
X
X
6
02/04
X
X
XX
X
X
X
XX
X
XX
X
X
XX
XX
XX
7.3 Comparaison : Architecture prévue / Architecture réalisée
L'architecture proposée dans le rapport intermédiaire s'est révélée adéquate
pour répondre aux besoins xés par le cahier des charges. Nous avons donc
gardé notre architecture modulaire. Chaque module est dédié à un regroupement
logique de fonctionnalités. Le changement eectué concerne la classe Rubik qui
ne délègue plus le travail à Visualization, alors qu'elle le faisait dans certains
cas. Ainsi, les parties interface graphique et visualisation sont séparées de la
partie Rubik, an de pouvoir intégrer le Rubik avec n'importe quelle boîte à
outils graphique. Cependant, nous n'avons pas totalement réussi à dissocier la
visualisation et l'interface que nous utilisons (la classe UnfoldedCube dépend de
QT), mais cela peut être modié relativement aisément.
La classe MainWindow délègue le travail d'un Rubik's Cube à la classe Rubik
et prend en charge les visualisations par l'intermédiaire de classes faisant le lien
entre QT et le code OpenGL. De plus, elle gère les interactions utilisateurs ↔
Rubik's Cube.
La classe Rubik délègue aux classes Struct, Acquisition et Solver les fonctionnalités qui leurs reviennent.
Cette construction nous permet de pouvoir facilement changer la taille du
Rubik's Cube. Elle permet en outre de changer les comportements intrinsèques
à la classe Rubik en fournissant des sous-classes de celles qui sont déléguées. Par
exemple, on peut changer d'algorithme de résolution facilement en créant une
classe dérivée de Solver.
36
Chapitre 8
Choix
8.1 Choix du langage
Après avoir écrit l'analyse de l'existant et l'architecture, nous avons dû chercher un langage de programmation adapté à nos besoins. L'architecture suggérait un langage objet (organisation structurée, besoin d'héritage...). Cela laissait
un choix important de langages car les langages objets sont nombreux (C++,
Java, Python, Ruby, Lisp...). Nous avions besoin que notre programme soit portable, ce qui a éliminé de la liste certains langages (Delphi, C#). De plus, nous
voulions un minimum de performances, ce qui en a en partie éliminé d'autres
(les langages de script, bien qu'il soient probablement susamment performants
pour faire fonctionner notre application).
Le critère déterminant pour choisir le langage a été la bibliothèque d'acquisition. Nous n'avions pas le temps d'écrire des bindings pour la bibliothèque,
surtout que cela pouvait être complexe pour certains langages. La bibliothèque
que nous avions choisie (PortVideo) étant écrite en C, il nous fallait un langage
capable de pouvoir accéder à du code C directement. A part certains langages
marginaux, seul le C++ le permet facilement.
Le C++ a donc été le langage choisi car il est celui qui répond le plus à
nos critères : objet, performant, portable (à condition de choisir les bonnes bibliothèques), une bibliothèque standard contenant ce dont nous avions besoin,
susamment expressif, et capable d'utiliser du code C directement. Cependant,
il a tout de même quelques défauts : c'est un langage relativement dur à maîtriser ; le plus gros défaut est la gestion de la mémoire explicite qui peut être
laborieuse.
8.2 Choix de la boite à outils graphique
Une fois le langage choisi, nous avons eu besoin de choisir quelle GUI nous
allions utiliser. Le nombre de boîtes à outils graphique est important, cependant
l'objectif de la portabilité a considérablement réduit la liste. Nous avions au
choix (en se limitant aux plus connus) :
GTK [GTK07a] (C)
GTKMM [GTK07b] (version C++ de GTK)
QT [Tro07] (C++)
37
WxWidget [WxW07] (C++)
Le choix s'est en partie fait sur des expériences personnelles : GTK est
beaucoup trop verbeux et il pose certains problèmes sous Windows (fenêtres
s'achant mal...). Par conséquent, GTK et GTKMM n'ont pas été choisis. Il
restait donc QT et WxWidget. Nous avons préféré opter pour QT car certains
membres du groupe connaissaient déjà cet outil.
Ce choix a été remis en question au début de la phase de codage : sous
Windows, la bibliothèque PortVideoSDL ne compile qu'avec Visual C++ 2003 ;
or QT OpenSource Edition ne fonctionne pas avec Visual C++. Nous étions
donc confrontés à une impasse, et nous avons pensé que nous allions devoir
utiliser WxWidget. En poursuivant les investigations , nous avons trouvé un
patch pour QT [Q..07] permettant de le faire fonctionner avec Visual C++.
Cela nous oblige à fournir notre version de QT avec l'application (i.e. compilé
en statique). Celle-ci faisant une taille de 6 Mo, QT compris, cela ne nous a pas
semblé trop gênant. En accord avec notre client et notre chargé de TD, nous
avons donc opté pour cette solution.
8.3 Bilbiothèque 3D
Au niveau des bibliothèques permettant de rendre des graphismes 3D accélerés, il n'y pas beaucoup de choix : OpenGL1 et Direct3D (partie de DirectX2 ),
sans compter les bibliothèques se basant sur ces deux bibliothèques. Si l'on veut
en plus avoir un programmme portable, il ne reste que OpenGL, qui bien que
moins bien supporté par certains chipsets graphiques intégrés sous Windows, est
la seule alternative performante et multi-système. Il existe bien des bibliothèques
comme OGRE3D3 qui permettent d'utiliser les deux bilbiothèques, cependant
elles vont bien au delà de nos besoins (tout comme OpenGL et DirectX) et surtout elles rajoutent une dépendance non négligeable à notre projet. Nous avons
donc decidé d'utiliser OpenGL qui est un standard performant, globalement
bien supporté et multi-plateformes.
8.4 Choix des outils
Pour nous aider à mener à bien le projet, nous avons été amenés à nous
servir d'outils particuliers. Voici comment nous avons choisi ceux-ci :
Le gestionnaire de version étant imposé (SVN), nous n'avons pas eu
le choix. Cet état de fait ne nous a pas dérangés, car nous voulions de toutes
façons utiliser un tel outil. SVN s'est avéré très utile et quasiment indispensable.
An de décrire l'avancement du projet, tant pour le client que pour les éventuels visiteurs, nous avons décidé d'utiliser un wiki4 . Celui-ci est disponible sur
le site du projet. Nous avons tenté de maintenir au maximum ce site à jour, mais
il est vrai que nos temps libres étant extrêmement restreints, nous n'avons
1 http ://www.opengl.org
2 http ://www.microsoft.com/windows/directx/default.mspx
3 http ://ogre3d.org/
4 PmWiki : www.pmwiki.org
38
pas toujours été très réguliers dans la mise à jour de celui-ci.
Pour tester et réparer les fuites mémoire, nous avons choisi d'utiliser Valgrind. En eet, c'est le logiciel Open Source le plus abouti dans ce domaine,
les autres alternatives (ccmalloc5 , electric fence6 ) n'étant pas aussi stables ou
autant avancées.
Nous avons choisi d'utiliser CppUnit7 pour eectuer les tests unitaires.
Pour la construction du projet, nous avions le choix entre le standard Unix :
Autoconf [Aut07a] et Automake [Aut07b], ou les deux outsiders : CMake
[Kit07] ou Scons [Sco07].
Autoconf et Automake ont le défaut de ne pas être portables (sous Windows
ils requièrent Cygwin8 ). De plus, malgré le fait que ce soient des standards, ils
ne sont pas très pratiques à utiliser, du moins pour des non-initiés. Nous avons
notamment trouvé que le fait de devoir écrire plusieurs lignes de code pour un
petit programme est très embêtant. Ils requièrent de plus la connaissance de
plusieurs outils (script sh, langage m4...) pour pouvoir être utilisés convenablement.
Il restait donc CMake et Scons. Le choix s'est fait en fonction d'expériences
personnelles, d'avis extérieurs, et de tests sur des programmes courts.
CMake a l'avantage d'utiliser un système de générateurs :
Sous Windows, il peut produire des Makele pour GNU Make, NMake, et
des chiers pour VisualC++...
Sous Unix, il peut produire des Makele pour GNU Make et les projets
pour KDevelop.
Sous Mac OS X, il gère des Makele pour GNU Make et les projets XCode.
CMake s'est avéré plus complet, plus rapide et plus adapté à nos besoins que
Scons. Nous avons donc choisi d'utiliser CMake.
Enn, le dernier outil utilisé est astyle9 dont nous nous servons pour réindenter le code et l'uniformiser.
5 http ://www.inf.ethz.ch/personal/biere/projects/ccmalloc/
6 http ://perens.com/FreeSoftware/ElectricFence/
7 http ://cppunit.sourceforge.net/cppunit-wiki/FrontPage ?action=show&redirect=PageD%27Accueil
8 http ://www.cygwin.com/
9 http ://astyle.sourceforge.net/
39
Chapitre 9
Description des algorithmes
et structures de données
9.1 Structure
9.1.1 Description du module
Toute classe implémentant un Rubik's Cube doit hériter de la classe Structure. En eet, cette classe présente l'interface nécessaire et donc les fonctions et
mouvements minimums que doit supporter toute classe fournissant une structure de Rubik's Cube.
Nous avons choisi d'implémenter une structure de Rubik's Cube dans la
classe Cube qui se veut la plus proche possible du modèle physique de l'objet,
et ce, dans un souci de facilité de manipulation.
Ainsi, un Rubik's Cube est un ensemble de cubics dans un vecteur N*N*N
où N est la taille du cube.
Un cubic est déni dans la classe Cubic3D, et est un ensemble de 6 faces
(Up, Down, Front, Back, Left et Right). Une face, dénie dans la classe Face,
possède une couleur (Red, Yellow, White, Blue, Green ou Orange) et un nom.
Les couleurs sont dénies dans une classe Colour, qui possède 7 membres statiques de type Colour. Ceci permet d'éviter la création abusive d'objets de type
Colour.
Avec le recul, nous nous sommes rendus compte que cette construction est
trop profonde et présente des classes inutiles. Une classe Cube et une classe
Cubic3D auraient certainement su. Cependant, nous étions trop avancés dans
le projet pour avoir le temps de changer de stratégie d'implémentation.
Les N*N*N cubics composant le Cube sont stockés dans un
vector<vector<vector<Cubic3D> > >
Ceci permet d'obtenir une structure en 3 dimensions semblable à celle d'un
Rubik's Cube réel.
Nous aurions pu utiliser un simple vecteur linéaire pour réduire les temps
d'accès à chaque Cubic3D. Cependant, la taille des données à traiter étant réduite (la taille d'un Rubik's Cube étant rarement supérieure à 5), cela reste tout
40
à fait acceptable.
Pour eectuer les mouvements de face du Rubik's Cube, nous avons implémenté diérentes méthodes :
0
1
2
3
4
5
void
void
void
void
void
void
turnFrontLayer(int layer);
turnBackLayer(int layer);
turnUpLayer(int layer);
turnDownLayer(int layer);
turnLeftLayer(int layer);
turnRightLayer(int layer);
Ces mouvements prennent en paramètre un entier décrivant sur quelle couche
du Rubik's Cube s'eectue la rotation. Ils permettent d'eectuer les mouvements
standards tels qu'ils sont décrits dans la partie Introduction au domaine .
Techniquement, ces méthodes procèdent de la manière suivante : tout d'abord,
il faut permuter dans le sens horaire chaque cubic avec son voisin sur la face
considérée. Cette opération est eectuée par le biais des méthodes privées suivantes :
0
1
2
3
4
5
void
void
void
void
void
void
moveFront(int size);
moveBack(int size);
moveUp(int size);
moveDown(int size);
moveLeft(int size);
moveRight(int size);
Puisque la structure est générique, il faut eectuer cette opération (la permutation des cubics ) N - 1 fois. De cette façon, un cubic de coin se retrouvera
au coin suivant . Une fois cette opération eectuée, il ne reste plus qu'à faire
pivoter les cubics de la face considérée sur eux-même dans le même sens que le
mouvement en cours. Ceci s'eectue via les méthodes de la classe Cubic3D :
0
1
2
3
4
5
void
void
void
void
void
void
U();
D();
F();
B();
R();
L();
Techniquement, ces méthodes changent juste la couleur des faces du cubic
en question.
La complexité de cette opération (le mouvement d'une face sur la structure)
est donc :
((N −1) permutations de (N ×N −1)) cubics +((N −1) rotations de (N ×N −1)) cubics
Soit au nal, une complexité en O(N 3 ). Cette complexité est importante mais
elle est à relativiser face à la taille du cube, qui n'excède que rarement 5.
Les mouvements standards (up, down, right, back, left et front) sont dénis
dans l'interface Structure, directement à partir des fonctions décrites précédemment. Ainsi, up s'eectue grâce à un appel à la fonction : turnUpLayer(1).
Les accesseurs en lecture sur la structure sont les suivants :
41
0
1
2
3
4
5
6
7
8
Cubic3D getCubic(int i, int j, int k) const;
int *getCube();
int *getFaceUp();
int *getFaceDown();
int *getFaceFront();
int *getFaceBack();
int *getFaceRight();
int *getFaceLeft();
int getSize() const
Nous n'allons pas décrire le fonctionnement de toutes ces méthodes, leurs
noms susent à exprimer leur rôle et leur fonctionnement.
Les méthodes d'accès sur les faces retournent un tableau d'entiers représentant les couleurs des faces visibles des cubics des faces du Rubik's Cube en
question. Nous avons xé une correspondance entre int et Colour et donc créé
2 fonctions qui réalisent les conversions :
0
1
Colour int2Colour(int n);
int colour2Int(const Colour &c);
Les méthodes d'accès aux faces (getFaceX) retournent un tableau d'entiers
correspondant aux couleurs des faces, dans un ordre précis : lignes par lignes. La
complexité de ces méthodes est en O(N 2 ). La méthode d'accès au cube complet
(getCube) retourne un tableau d'entiers correspondant aux valeurs renvoyées
par les méthodes d'accès aux faces, dans un ordre précis : up, left, front, right,
back , down. Ainsi, le tableau renvoyé aura une taille de N*N*6 (avec 6 le nombre
de faces du Rubik's Cube bien évidemment). La complexité de cette opération
est de O(6 ∗ N 2 ), c'est à dire O(N 2 ).
Les accesseurs en écriture sur la structure sont les suivants :
0
1
2
3
4
5
6
void
void
void
void
void
void
void
setCube(int *tab);
setFaceUp(int *tab);
setFaceDown(int *tab);
setFaceFront(int *tab);
setFaceBack(int *tab);
setFaceRight(int *tab);
setFaceLeft(int *tab);
Ces fonctions sont les équivalentes des accesseurs en lecture précédemment
décrits. Leur complexité est identique.
9.1.2 Points forts, points faibles
Les points forts de notre structure sont :
La généricité : il est possible d'instancier des Rubik's Cube de taille variables (2*2*2, 3*3*3, etc).
Comme précisé plus haut, la similarité de la structure avec le modèle réel,
qui permet de manipuler plus facilement la structure.
Une interface bien dénie permettant plusieurs implémentations de structure diérentes.
42
Les points faibles sont :
Comme précisé plus haut, la profondeur relativement importante de la
classe Cube (Cube → Cubic3D → Face → Colour).
Nous nous sommes rendus compte en implémentant les autres modules
qu'une telle construction de structure était partiellement inutile. En eet,
pour interagir avec celle-ci, les autres modules n'utilisent que des tableaux
d'entiers, nous aurions donc pu nous contenter d'une structure plus simple.
9.1.3 Problèmes rencontrés
Nous n'avons pas rencontré de problèmes majeurs dans cette partie. Cependant, nous avons eu des dicultés à la tester correctement. La description de
cette phase sera eectuée dans la prochaine partie ( Tests de validation et de
fonctionnement ).
9.2 Acquisition/Traitement
9.2.1 Description du module
La classe abstraite Acquisition est la classe responsable de l'acquisition et
du traitement. Toute classe implémentant une acquisition (par image) ou une
nouvelle méthode de détection doit hériter de cette classe (ou bien sûr d'une de
ses dérivées).
Elle possède les méthodes suivantes :
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public:
Acquisition(int size);
virtual ~Acquisition();
virtual void close();
virtual unsigned char *getFrame() =0;
virtual void getPicture(unsigned char *buffer, int color) =0;
virtual int nbFace() { return _face;}
virtual void setMirror(bool mir) { _mirror=mir;};
protected:
virtual void computeFrame();
void drawSquare(int x, int y);
virtual void drawFrame();
map<int, pair<pair<int, int>,Triple<double> > > _centreFaces;
Nous allons voir dans un premier temps la partie acquisition.
Le constructeur de la classe Acquisition appelle la méthode computeFrame.
Cette méthode calcule l'espacement entre les cadres de captures, ainsi que leurs
coordonnées. Ainsi, ils ne sont calculés qu'une seule fois. La complexité de cette
méthode est en O(N 2 ) (on a N*N cadres). Ces informations sont stockées dans
la structure _centreFaces. Celle-ci contient donc les coordonnées des cadres de
capture ainsi que la couleur associée.
43
La deuxième méthode utilisée pour l'acquisition est la méthode getFrame qui
est virtuelle pure. Les méthodes auxiliaires sont drawSquare qui dessine un cadre
ainsi que drawFrame qui dessine tous les cadres de capture. Les complexités
de ces méthodes sont respectivement en O(taille d'un cadre de capture) et en
O(N 2 ).
La classe Webcam implémente l'acquisition par Webcam. Celle-ci s'appuie
sur la bibliothèque PortVideoSDL (version 0.3), à laquelle elle délègue l'accès
au matériel.
Elle implémente la méthode virtuelle getFrame. Celle-ci est chargée de récupérer les images issues du périphérique. Elle y ajoute la superposition des
cadres et applique si nécessaire la fonction mirror, fonction appliquant un miroir d'axe horizontal de complexité O(hauteur de l'image/2*largeur de l'image).
Sa complexité dépend donc de la complexité inconnue de la récupération du ux
sur la Webcam. Elle est donc en O(max(O(hauteur/2*largeur), récupération du
ux)).
Après l'acquisition, passons à l'analyse des images récupérées. Pour cela nous
disposons des méthodes suivantes dans la classe Acquisition :
0
1
2
3
4
virtual
virtual
virtual
virtual
virtual
int*
int*
int*
void
void
getPicture(unsigned char *buffer)=0
cubeAcquisition() {
getFace()
reset()
checkFace(unsigned char *buffer,int color) =0;
La méthode reset réinitialise l'acquisition. La méthode cubeAcquisition
renvoie une copie du cube détecté sous forme de tableau d'entiers (cf. Structure)
et getFace renvoie le cube sous forme de pointeur d'entiers (ce n'est pas une copie), elle est donc utilisée pour les corrections sur la capture (cf. Fonctionnalités
implémentées).
La classe Webcam implémente les fonctions virtuelles getPicture récupérant l'image sur la Webcam et appliquant le ltre bgr2rgb (complexité en
O(hauteur * largeur)) ainsi que la fonction mirror si nécessaire ; donc la complexité de getPicture est en O(max(hauteur*largeur, récupération du ux)). La
méthode checkFace lance la détection, elle fait appel à la méthode averageColor
qui calcule les couleurs moyennes des cadres de capture et les convertit en
HSV (espace de couleurs plus adapté à nos besoins, dénissant les couleurs
en fonctions de leur teinte, saturation, intensité), de complexité en O(N 2 ∗
tailled0 uncadredecapture2 ) (complexité peu importante vu que N est généralement petit et qu'en pratique nous ne calculons pas la moyenne sur tout le cadre,
pour éviter de prendre en compte d'éventuels débordements). Enn checkFace
appelle la méthode computeFace qui remplit la face du cube en fonction des
valeurs trouvées dans averageColor ; sa complexité est en O(N 2 ).
9.2.2 Points forts, Points faibles
Les points forts sont les suivants :
Généricité. Permet des acquisitions sur des cubes de taille inférieure à 8
(cf. Extensions possibles).
Périphérique Dummy permettant de simuler une fausse Webcam.
Résultats d'acquisition satisfaisants. (cf. Tests)
Possibilité de correction de la capture par la méthode getFace.
44
Les points faibles sont les suivants :
Détection non dynamique, qui peut dépendre de l'éclairage ou de la Webcam (cf. Extensions possibles, Tests).
9.2.3 Problèmes rencontrés
Les problèmes rencontrés sont les suivants :
Les valeurs seuils des couleurs ont été trouvées de manière empirique ; cela
a donc nécessité de nombreux essais et ajustements.
9.3 Modèle 3D
9.3.1 Description du module
La visualisation avec GLUT
Comme cela a été fait pour les autres fonctionnalités du logiciel, la partie
visualisation 3D a été développée de manière indépendante.
Ainsi, nous avons dans un premier temps utilisé GLUT1 qui permet de rendre
de l'OpenGL dans une fenêtre la plus simple possible sans devoir concevoir une
interface quelconque. Il y a ici un avantage indéniable à l'utilisation de GLUT :
on est sûr que s'il y a un problème d'achage ou de manipulation, seul le modèle
3D est en cause.
Modélisation du cube en 3D Le Rubik's cube est considéré comme un
assemblage de 27 cubics. C'est ainsi un tableau 3*3*3 de cubics. Chaque cubic
possède ses 3 coordonnées (x, y, z), les rotations qui lui sont associées (RotX,
RotY, RotZ) et la liste des rotations à eectuer.
Une fois que l'initialisation est faite par la fonction initializeRubik, nous
pouvons dessiner le cube. Pour cela, nous avons implémenté la fonction drawRubik
qui récupère d'abord les informations propres à chaque cubic an de savoir où
le dessiner, et qui les dessine donc un par un.
En OpenGL, il n'existe pas de fonction permettant de dessiner directement
des objets complexes. Il faut se servir de primitives permettant de dessiner des
points, des lignes ou encore des formes géométriques planes particulières.
Pour dessiner un cubic, nous commençons donc par dessiner une face colorée. Puis nous appliquons une rotation et/ou une translation et dessinons
la face suivante. Cette opération est eectuée 6 fois en prenant soin de changer de couleur à chaque transformation. Ainsi nous avons dessiné notre cubic. Une fois qu'un cubic est dessiné, on eectue une translation du repère
an de se placer correctement avant de dessiner le prochain cubic. A la n
de l'exécution de drawRubik nous avons donc un Rubik's Cube composé de
27 cubics strictement identiques. La complexité de drawRubik est en O(N 3 ∗
tailledelalistecontenantlesrotationsdescubics).
Ce Rubik's Cube n'est à ce stade pas très beau puisqu'il ressemble à un
unique cube, les côtés étant composés des faces des cubics de même couleur
collées les unes aux autres. C'est pourquoi nous avons créé, avec un logiciel
1 http ://www.opengl.org/resources/libraries/glut/
45
de dessin basique, une texture représentant le bord noir d'une face d'un cubic.
Cette texture est chargée grâce aux fonctions loadGLTextures et imageLoad.
Puis lorsque nous dessinons une face d'un cubic, nous lui appliquons la texture.
Notre cube ressemble désormais à un Rubik's cube du monde réel.
Animation du Rubik's cube Dans un premier temps, la première idée qui
nous est venue à l'esprit est de créer des fonctions up(), down(), left(), right(),
front(), back() qui prendraient en paramètre un sens an de pouvoir eectuer
le mouvement anti-up() par exemple sans faire appel à 3 fois up().
Mais pour éviter de trop grosses duplications de code, nous avons eu une
autre idée : nous n'avons écrit qu'une seule procédure rotation qui fera tourner
la tranche concernée dans le sens indiqué selon un certain axe (déni en variable
globale). Ainsi, faire un up ou un down revient à exécuter une rotation avec 2
valeurs de tranche diérentes.
Par soucis de sécurité, nous implémentons la procédure isRotationPossible
qui nous indique si une rotation est possible à eectuer au moment de l'appel.
En eet si l'on est en train d'eectuer un left, il faut attendre qu'il soit terminé
avant d'eectuer un up par exemple.
Nous évitons en écrivant ces deux fonctions de grosses duplications de code.
Pourtant, en regardant l'implémentation de ces 2 fonctions, on peut constater
l'utilisation d'un switch avec dans chaque case des triples boucles imbriquées et
des instructions se ressemblant énormément... Mais celles-ci ne sont visiblement
pas factorisables. La complexité de ces fonctions est en O(N 3 ).
Le point de vue Maintenant que les mouvements sont implémentés, nous
devons pouvoir tourner autour de notre Rubik's Cube. Ceci est possible grâce
à l'utilisation de variables globales x_scene et y_scene qui permettent lors du
drawRubik() de tourner autour du centre de notre repère via l'utilisation de la
fonction standard glRotated.
Eclairage Nous décidons d'éclairer le Rubik's cube avec 6 lampes, ce qui per-
met d'éclairer simultanément tous les côtés du cube sans aucune zone d'ombre.
En eet, lorsque nous tournons autour du cube, le repère tourne, entraînant
avec lui les lampes ; d'où la nécessité de placer une lampe en face de chaque
face.
Nous initialisons cet éclairage ainsi que la couleur de fond dans une fonction
init appelée dans le main avant glutMainLoop.
An d'avoir un rendu agréable, les lumières utilisées sont de type positionelles blanches et nous devons redénir les faces des cubics en leur associant des
couleurs de diusion avec glMaterialfv.
Amélioration Enn, nous décidons d'acher des axes avec des couleurs cor-
respondant aux faces correspondantes (cf. Fonctionnalités implémentées). La
complexité de cet achage est en temps constant.
46
Intégration à l'interface
Maintenant que le modèle en 3D est implémenté et correspond à nos besoins,
nous pouvons l'intégrer à notre interface.
De GLUT à QT4 Nous supprimons donc le main et toutes les fonctions se
référant à GLUT. Nous réservons un espace de rendu 3D OpenGL dans notre
interface en QT4.
GLWidget Nous créons donc une classe GLWidget héritant d'un QGLWidget. Notre cher rubik3D.cc est interfacé et propose maintenant des fonctions
utilitaires à GLWidget.
Ainsi, on écrit les fonctions de mouvements qui appellent toutes doRotate
avec les arguments nécessaires, celle-ci appelant à son tour isRotationPossible
et rotation.
Lien avec la structure Notre cube est maintenant correctement intégré à
l'interface du logiciel. Il nous manque cependant une fonctionnalité importante :
nous devons pouvoir initialiser le cube dans une position quelconque, et non plus
seulement en position résolue ou initiale.
Pour ceci, lors de l'exécution de drawRubik, nous fournissons des paramètres
à la fonction cube qui est chargée de dessiner un cubic. Ces paramètres sont les
couleurs des faces du cubic à dessiner calculées en fonction du contenu de la
conguration du Rubik's cube.
9.3.2 Points forts, points faibles
Les points forts de ce module sont :
Esthétisme général du cube.
Possibilité de régler la vitesse de rotation des faces.
Les points faibles de ce module sont :
Pas de généricité.
Pas de gestion du nombre d'images par seconde (cf. Fonctionnalités implémentées, Extensions possibles).
Switch de 27 cas dans la fonction cube an de dessiner une conguration particulière du Rubik's Cube (par exemple après une acquisition). Ce
switch nuit grandement à la généricité du module.
9.3.3 Problèmes rencontrés
Lorsque nous avons voulu implémenter la méthode setCube, nous nous
sommes retrouvés confrontés à un problème de conception : il était impossible
de changer la couleur des cubics de façon propre ; nous avons envisagé deux
solutions : une prenant en compte l'orientation des cubics qui changeait l'implémentation du module Structure ; une autre, celle choisie, qui xe les faces
visibles du cube et qui xe une couleur arbitraire aux faces non-visibles. Aucune
de ces deux solutions n'est convenable. Durant l'écriture du rapport, nous nous
sommes rendu compte qu'il aurait fallu ajouter 6 variables correspondant aux 6
47
faces d'un cubic dans la structure cubic. La méthode setCube aurait alors plus
ou moins ressemblé à celle de la classe Cube.
9.4 Interface
9.4.1 Description du module
L'interface a été réalisée avec QT4 (cf. Choix). C'est la classe MainWindow qui implémente celle-ci. La plupart des méthodes de cette classe ne sont
pas intéressantes, puisqu'il s'agit uniquement de la mise en place des diérents
éléments (QPushButton, QLineEdit...).
Les fonctionnalités plus délicates à implémenter sont celles correspondants
au parsage de la ligne de commande, et le système de mémoire de coups.
Le parsage de la ligne de commande est assuré par les méthodes suivantes :
0
1
2
3
4
5
6
7
private slots:
QString readCommand();
void prevReadCommand();
bool nextReadCommand();
[...]
private:
void analyseCommand(QString command);
QString reverseCommand(QString command);
Les méthodes prevReadCommand et nextReadCommand permettent de déplacer le curseur dans la QLineEdit, et de mettre en sur-brillance la commande
en cours d'analyse. Pour la première, celle-ci sera la commande précédant la
position du curseur.
La fonction readCommand récupère le contenu de la ligne de commande à
partir de la position du curseur et calcule la taille de la prochaine commande
(celles-ci peuvent être de taille variable).
La méthode analyseCommand analyse, comme son nom l'indique, la commande, obtenue par readCommand, qui lui est passée en paramètre. Si celle-ci
est valide, elle eectue les mouvements sur les modèles en conséquence.
La méthode reverseCommand permet d'inverser la commande qui lui est passée en paramètre. Cela permet notamment de pouvoir gérer les historiques de
commandes.
Le système de mémorisation de coups est basé sur un tableau de taille xée
(nous avons choisis 200), auquel on ajoute chaque mouvement entré au clavier,
traduit en commandes. Chaque mouvement incrémente le pointeur du tableau.
Lorsque l'utilisateur utilise la fonctionnalité Annuler , le pointeur du tableau
est décrémenté, le contenu de celui-ci est inversé grâce à reverseCommand et est
analysé. Lorsque l'utilisateur eectue un Refaire le pointeur du tableau est
incrémenté et le contenu de celui-ci est ré-inversé puis analysé.
L'acquisition vidéo est gérée dans l'interface par un WebcamWidget. Il utilise
donc une classe de type Acquisition* pour faire le travail. Au début il avait
été conçu de manière multi-threadée : un thread était chargé de récupère les
48
images de la Webcam. Un système de producteur consommateur permettait à
QT d'acher les images lorsqu'elles étaient disponibles.
Cependant, cette méthode a été abandonnée pour plusieurs raisons :
QT ne permet pas qu'un mutex soit déverrouillé par un thread autre que
celui qui l'avait verrouillé.
Il y avait des problèmes de synchronisations non résolus à la fermeture
du programme. QT refusait parfois d'attendre que le thread chargé de
récupérer les images nisse, et ce malgré un appel à QThread.wait
Après plusieurs essais, les performances gagnées n'étaient pas susantes
pour justier le temps passé à corriger les problèmes énoncés.
Une autre méthode a donc été utilisée : il n'y a plus de thread créé pour
récupérer les images, à la place, un timer (QTimer) déclenche un signal toutes
les x millisecondes. Ce signal est connecté au slot update de WebcamWidget,
ce qui provoque la récupération d'une image sur la Webcam et l'ache.
Un Widget a été ensuite créé : CaptureWidget, an de proposer l'interface
graphique à l'acquisition. Il est composé, entre autres, d'un WebcamWidget
qui récupère les images de la Webcam et les ache et d'un label donnant les
consignes nécessaires à l'utilisateur pour réaliser la capture (face désirée et son
orientation).
Lorsque l'acquisition d'une face est terminée, il propose une fenêtre permettant de corriger les erreurs d'acquisition.
L'acquisition manuelle est gérée dans l'interface par la classe ManualCaptureWidget. Elle repose sur 6 FaceWidget. L'achage d'un FaceWidget est en
O(N 2 ).
Il existe une subtilité dans cette partie : lors de la construction de ManualCaptureDialog, un paramètre (memSet) permet de dire si le cube doit être
initialisé (i.e. si tous les cubics doivent être de couleur grise, sauf les centraux)
ou non. Ainsi, si l'utilisateur débute une acquisition, cela lui présente un cube
initialisé. Si toutefois l'utilisateur se retrouve en position de devoir corriger une
acquisition, cette fonctionnalité permet de redonner à celui-ci la conguration
qu'il tentait de valider.
La classe UnfoldedCube utilise la classe ManualCaptureWidget où les possibilités d'édition sont désactivées. Elle ajoute les mouvements indispensables à
un Rubik's Cube. Ces mouvements sont implémentés avec une complexités en
O(N 2 )
9.4.2 Points forts, points faibles
Les points forts de ce module sont :
Une interface relativement claire et complète.
Un choix varié dans les façons de manipuler un cube.
Des possibilités d'acquisition manuelle diverses.
Possibilités de corrections de capture (cf. Fonctionnalités implémentées)
Les points faibles sont :
La classe MainWindow centralise quelques fonctions qui ne devraient pas
s'y trouver (parser de la ligne de commande et gestion de l'historique des
mouvements).
49
Non générique.
9.4.3 Problèmes rencontrés
Après le retrait du thread dans la partie acquisition, alors que nous pensions
que cela ne baissait pas les performances (car c'était le cas sous Linux), sous
Windows il semblerait que les diérences soient conséquentes. En eet, lors de
l'ouverture du panneau de capture, l'application est considérablement ralentie.
Ceci dit, nous ne sommes pas sûr de la provenance de ce problème.
9.5 Résolution
9.5.1 Description du module
Chaque algorithme de résolution est dans l'obligation d'hériter et donc d'implémenter les méthodes de la classe abstraite Solver. Voici le contenu de cette
classe :
0
1
2
virtual string generateSolution(int *cubeConfig) = 0;
virtual int checkValidity(int *cubeConfig) = 0;
virtual int getNumMoves() = 0;
La méthode generateSolution doit retourner une suite de mouvements
respectant le standard du parser de commandes de l'interface graphique (décrits
dans solver.h). Bien évidemment, cette suite de mouvements doit permettre de
résoudre le Rubik's Cube dont la conguration lui a été passée en paramètre.
La méthode checkValidity permet un contrôle de la validité du Rubik's
Cube passé en paramètre. Cette méthode doit au minimum retourner 0 lorsque
le Rubik's Cube est valide.
Enn, getNumMoves renvoie le nombre de mouvements de la solution calculée par l'algorithme de résolution.
La résolution s'eectue par le biais de la classe LayerByLayer qui utilise la
bibliothèque Cubex écrite en C. Cette bibliothèque fournit un algorithme de
résolution de Rubik's Cube en couches par couches . Cette bibliothèque est
performante, et visiblement sûre (cf. Tests), facilement intégrable à notre programme.
Pour intégrer cette bibliothèque, nous avons dû implémenter un adaptateur.
En eet, la suite de mouvements retournée par la bibliothèque n'est pas adaptée
au standard que nous utilisons. Ainsi, la classe LayerByLayer dérivée de la classe
abstraite Solver, réalise cette adaptation.
LayerByLayer implémente donc les méthodes décrites ci-dessus. La complexité de l'algorithme utilisé dans la bibliothèque Cubex n'est pas précisée
dans les spécications de celle-ci. La densité du code de cette dernière ne nous
a pas permis de pouvoir estimer cette complexité. Cependant, les tests eectués
sur cette partie, et la rapidité avec laquelle la solution est calculée nous semblent
satisfaisants quant à la rapidité de l'algorithme (cf. Tests).
50
9.5.2 Points forts, points faibles
Les points forts sont les suivants :
La rapidité d'exécution de l'algorithme.
La fonction de vérication de validité fournissant de nombreux (7) codes
d'erreurs permettant d'interpréter d'où proviens l'invalidité du Rubik's
Cube.
Les points faibles de ce module sont les suivants :
Il est impossible d'être sûr à 100% de la validité de l'algorithme de résolution fourni par la bibliothèque Cubex.
La bibliothèque utilisée fournit un des algorithmes les plus basiques qui
soient. Nous n'avons pas voulu utiliser l'algorithme de Kociemba, pour
plusieurs raisons : tout d'abord il est beaucoup plus coûteux du point de
vue processeur/mémoire, il ne fournit pas de contrôle de validité évolué,
et de plus, nous n'avions pas le temps d'implémenter un algorithme aussi
évolué.
51
Chapitre 10
Tests de validation et de
fonctionnements
10.1 Tests aléatoires
Pour tester les diérents modules de notre logiciel, au cours et à la n du développement de celui-ci, nous avons souvent utilisé les tests aléatoires. En eet,
il est naturel d'éprouver nos diérents modules sur des Rubik's Cube générés
aléatoirement, et d'eectuer sur celui-ci les opérations que nous voulons tester.
Cette méthode a été utilisée à de nombreuses reprises pour les tests systèmes et
les tests en boîte noire que nous décrirons par la suite.
Nous avons aussi employé cette méthode pour tester l'algorithme de résolution avant de décider de l'employer dans notre logiciel. Pour contrôler la validité
de celui-ci, l'opération consistait à tenter de résoudre des Rubik's Cube générés
aléatoirement.
10.2 Tests unitaires
Nous avons eectué un certain nombre de tests unitaires pour chaque module du programme. Ainsi, pour les parties structure, résolution et acquisition,
nous avons créé au fur et à mesure de la progression de notre travail, des tests
spéciques à chaque unité. Nous testons ainsi une par une, parfois à l'aide de
tests aléatoires, chacune des fonctionnalités d'un module. A noter que dans cette
partie, nous utilisons l'outil CppUnit comme décrit dans la partie Choix .
10.2.1 Module Structure
Démarche
Pour le module de la structure du Rubik's Cube, nous créons une structure
dont nous sommes certain qu'elle corresponde à une conguration particulière du
cube, pour ensuite la comparer à la conguration produite par une opération du
module. Par exemple, pour tester l'opération left (qui, on le rappelle, consiste
52
à faire tourner dans le sens horaire la face gauche d'un Rubik's Cube), on créé
une conguration de Rubik's Cube correspondant à un cube auquel on a eectué
ce mouvement :
int left_tab[] = {4,2,2,4,2,2,4,2,2,3,3,3,3,3,3,3,3,3,2,1,1,2,1,1,2,
1,1,5,5,5,5,5,5,5,5,5,4,4,6,4,4,6,4,4,6,1,6,6,1,6,6,1,6,6};
Puis, on eectue ce mouvement sur un Rubik's Cube créé par le module,
avec l'opération left, et on compare le résultat produit par cette méthode et
la conguration prévue :
cube =new Cube(3);
[...]
cube->left();
CPPUNIT_ASSERT_MESSAGE("test 1",!memcmp(left_tab,
cube->getCube(), 3*3*6*sizeof(int)));
On répète cette opération pour les diérentes méthodes de la structure.
On prote de ces tests de méthodes pour utiliser un invariant spécique
an de doublement contrôler celles-ci. En eet, lorsque la structure dispose
d'un mouvement, elle dispose aussi de son contraire (par exemple : left et
antiLeft).
On créé donc un Rubik's Cube neutre, c'est à dire un cube dans son état
initial ou résolu :
cube =new Cube(3);
int *neutral=cube->getCube();
Lorsqu'on test la validité d'une opération sur le cube, on eectue directement
l'opération inverse sur celui-ci pour vérier que le cube obtenu est bien un
Rubik's Cube neutre (i.e. résolu) :
cube->right();
CPPUNIT_ASSERT_MESSAGE("test 3",!memcmp(right_tab,
cube->getCube(), 3*3*6*sizeof(int)));
cube->antiRight();
CPPUNIT_ASSERT_MESSAGE("test 4",!memcmp(neutral,
cube->getCube(), 3*3*6*sizeof(int)));
On teste ainsi, pour chacun des mouvements sur le Rubik's Cube, qu'appliquer une opération et son contraire ramène bien à un cube en état initial.
Pour nir, on teste unitairement chacune des méthodes de cette classe en
comparant similairement le résultat obtenu avec une conguration attendue.
On peut ainsi tester les méthodes setCube et getCube, setInitialState et
isInitialState.
53
Résultats
Avant que nous ne commencions à tester les méthodes de ce module à l'aide
de CppUnit, mais que nous testions visuellement (avec des achages de résultats
sur la console), les résultats nous semblaient corrects alors qu'ils étaient en
partie erronés. Nous nous sommes rendus compte de nos erreurs lors des tests
d'intégration (cf. Tests d'intégration).
Nous avons mis par la suite en place les tests exposés ci-dessus, et grâce à
CppUnit, nous limitons les risques liés à une erreur humaine. Ces tests fonctionnent tous et nous permettent d'être sereins quant à la abilité de notre
structure. Il est évident que ces tests ne sont pas infaillibles et doivent aussi être
couplés, par exemple, aux tests d'intégration.
10.2.2 Module Résolution
Démarche
Pour le module de résolution du Rubik's Cube (le module solver), nous
employons approximativement les mêmes méthodes.
Pour tester la validité des opérations disponibles dans ce module, on créé un
certain nombre de congurations de Rubik's Cube dont nous sommes certains
de la non validité. On créé par exemple, 10 congurations non valides de Rubik's
Cube :
int cubeInvalid0[]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
int cubeInvalid1[]= {0,0,0,0,2,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,6,0,0,0,0};
...
Ces congurations sont obtenues par nos soins, à la main ; les risques
d'erreurs liées à l'utilisation d'une méthode du programme pour créer ceux-ci
sont donc éliminés. Cependant, cela engendre un risque dans la mesure où nous
sommes faillibles et inuencés par ce que nous nous attendons à obtenir comme
résultat pour créer ces échantillons. Malgré tout, créer un Rubik's Cube invalide
est assez aisé ; il sut par exemple de ne donner qu'une seule couleur à tous les
cubics.
Une fois ces échantillons créés, nous pouvons tester les diérentes méthodes
du module. Ainsi, on peut tester la méthode checkValidity (qui retourne un
entier correspondant ou non à la validité de la conguration de Rubik's Cube
passée en paramètre) : D'une part, on teste un certain nombre de fois avec un
cube valide obtenu grâce à la fonction mix construite par échafaudage, d'autre
part, on vérie pour chaque conguration non valide créé, que ceux-ci sont bien
non valides.
CPPUNIT_ASSERT(!solver->checkValidity(cubeValidX->getCube()));
CPPUNIT_ASSERT(solver->checkValidity(cubeInvalid1));
[...]
On peut eectuer cette opération pour l'ensemble des échantillons créés.
54
On teste de la même façon la méthode generateSolution qui, elle, renvoie
soit la solution sous forme de chaîne de caractères, soit renvoie une chaîne vide.
De plus, on peut tester la validité de la solution retournée, grâce à la fonction
apply_resol créé par échafaudage, qui permet d'analyser et d'appliquer sur une
structure la suite de mouvements retournée par l'algorithme de résolution. On
eectue cette opération un certain nombre de fois, sur des Rubik's Cube générés
aléatoirement par la fonction mix, créé plus haut.
Résultats
Les résultats dans cette partie sont conformes à ceux attendus. Les méthodes
que nous pouvons tester de manière unitaire sont validées par CppUnit. Ces
tests restent néanmoins faillibles, puisque nous fournissons des congurations de
Rubik's Cube à la main Comme
pour le module structure, il est donc évident
que nous devons coupler cette méthode de tests avec d'autres techniques.
10.2.3 Module Acquisition
Pour le module acquisition, on ne peut tester de manière automatisée que
les méthodes getPixel et mirror. En eet, les autres sont des méthodes interactives nécessitant une manipulation de la part d'un utilisateur pour être
testées. Cette partie s'eectuera donc dans les tests en boîte noire ou les
tests système.
Démarche
Pour tester les méthodes getPixel et setPixel, on récupère l'image capturée par la caméra dans un buer, puis on récupère un pixel sur ce buer. On
applique ensuite ce pixel par la méthode setPixel sur un buer contenant une
copie de l'image et on compare les deux buers pour savoir si les pixels sont
identiques.
Pour tester la méthode mirror, on utilise la méthode de l'invariant : on applique deux fois la méthode mirror sur un buer contenant une image capturée
par une caméra. Si au nal le buer avant la double application de cette méthode
et après cette application est invariant, alors c'est que la méthode fonctionne.
Résultats
Comme pour les parties précédentes, les résultats sont conformes à ceux
attendus, les comportements des méthodes testées semblent bons.
10.2.4 Module Rubik
Démarche
Pour tester le module Rubik, nous avons repris les tests appliqués à chaque
module et nous les avons fait passés, lorsque cela avait un sens, à la classe Rubik.
Les résultats obtenus doivent donc être les mêmes que pour les autres modules.
55
Résultats
Comme la classe Rubik ne fait que déléguer le travail aux autres classes, le
résultat devrait être positif sous peine d'avoir de gros problèmes. Les tests ont
été heureusement validés.
10.3 Tests d'intégration
Notre logiciel a été étudié et conçu pour fonctionner de manière modulaire.
Ainsi, les parties structure, algorithme de résolution, acquisition, visualisation
et interface graphique sont indépendantes et peuvent être remplacées ou enlevées.
Partant de cette vision des choses, nous avons conçu notre logiciel de manière
complètement individuelle entre les diérentes parties. Ce n'est que dans les
dernières phases de développement que nous avons rassemblé le tout. Cette
phase de rassemblement est celle qui nous a vus eectuer des tests d'intégration.
Ces tests sont en partie liés aux tests en boîte noire : ils font intervenir
l'utilisateur qui doit contrôler la cohérence de l'ensemble des éléments une fois
regroupés. Ainsi, lorsque nous avons testé les opérations de mouvements sur le
Rubik's Cube, nous avons vérié, et ce de manière interactive, que l'ensemble
des visualisations se comportaient de façon identique et correcte. Pour chacune
des opérations interactives , nous avons agi de même, an de contrôler la
cohérence de l'ensemble.
Ces tests d'intégration nous ont permis de déceler de nombreux bugs.
Par exemple, lorsque nous avons rassemblé la partie structure et la partie visualisation 2D dans l'interface graphique, nous nous sommes aperçus de
l'apparition d'incohérences lors des opérations de mouvements ou de sauvegarde/chargement de Rubik's Cube. Nous avions pris soin préalablement de
tester chacun des modules indépendamment avec des tests unitaires ; nous ne
nous attendions donc pas à trouver des erreurs dans ceux-ci. Au nal, les erreurs
se trouvaient dans les deux modules : les opérations de mouvements étaient incorrectes dans la structure, et certains mouvements s'eectuaient dans un mauvais sens sur le modèle 2D. Cet incident nous a fait comprendre toute la
nécessite de coupler les diérentes techniques de tests. Si nous n'avions compté
que sur les tests unitaires, notre logiciel aurait été complètement buggé .
10.3.1 Substitutivité
Il n'y a que pour deux types de modules que nous avons plusieurs implémentations diérentes : la partie visualisation, et la partie acquisition.
Dans la partie visualisation, nous avons à notre disposition une représentation en 3 dimensions et une représentation en 2 dimensions du Rubik's Cube.
Nous avons donc pu tester la substitutivité de ces 2 composants. Ainsi, nous
avons pu essayer notre logiciel avec l'une ou l'autre des visualisations, avant
de tester celui-ci avec les 2. Ces tests ne sont pas automatisés, il faut modier
la classe Mainwindow, pour que s'ache dans l'interface graphique tel ou tel
QWidget. Mais nous avons pu vérier que du moment que les visualisations res-
56
pectaient l'interface prévue à cette eet, l'intégration de celles-ci ne comportait
aucun problème.
Dans la partie acquisition, nous avons deux acquisitions possibles : l'une faisant intervenir une Webcam, l'autre utilisant la classe Dummy, an de simuler une Webcam lorsque l'utilisateur n'en a pas à sa disposition. La substitutivité
ne pose aucun problème ici aussi, du moment que l'interface prévue à cet eet
est respectée.
Pour les autres modules, nous avons à notre disposition uniquement un modèle de chaque. Il nous est donc dicile de tester la substitutivité de ceux-ci.
Cependant, puisque l'intégration de la totalité des modules s'est bien déroulée,
il est naturel de penser que cela ne devrait pas poser de problème majeur.
10.4 Tests système
10.4.1 Mouvements d'une face du Rubik's Cube
Pour tester le fonctionnement global de cette opération, puisque notre logiciel est un programme complètement interactif et nécessite les actions d'un
utilisateur, les tests sur le bon fonctionnement du mouvement d'une face de
Rubik's Cube doivent s'eectuer de manière interactive. Par exemple, lorsque le
testeur appuie sur la touche U, il doit contrôler que la face Up a bien tourné
dans le bon sens, et que le résultat sur le Rubik's Cube est cohérent.
10.4.2 Acquisition d'un Rubik's Cube
L'acquisition en elle même, comme décrite dans les tests unitaires, ne peut
se tester que de manière interactive. Il faut donc là aussi que le testeur eectue
de nombreuses acquisitions an de vérier que celles-ci soient correctement répercutées sur les représentations du Rubik's Cube. Nous avons donc eectué ce
travail à de nombreuses reprises an de valider cette opération.
On peut également tester les performances de cette fonctionnalité. Quels
sont les pourcentages de succès de celle-ci en fonction de la caméra utilisée et
des conditions d'éclairages ?
Pour eectuer ces tests, il n'y a pas d'autre solution que d'eectuer des
mesures et de tracer des courbes de résultats. Nous avons à notre disposition
diverses caméras de marques diérentes, et des congurations d'ordinateurs différentes. Les conditions d'éclairages font varier également les taux de réussite de
détection des couleurs. Par conséquent, pour chaque Webcam que nous possédons, nous traçons deux graphiques. Un premier représentant le nombre de cubics correctement détectés par couleur dans des conditions d'éclairage naturelles
(lumière ambiante), et une seconde dans des conditions d'éclairage articielles.
57
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.1 Documents illustrant l'opération de capture par la caméra Logitech
QuickCam Chat, en conditions d'éclairage naturelles.
Fig.
On remarque dans la gure précédente que les couleurs bleue, rouge et
blanche sont parfaitement bien détectées (100%), mais que le système d'acquisition a beaucoup plus de problèmes pour les couleurs oranges jaune et verte.
Lorsque l'on regarde la capture d'écran donnant l'image renvoyée par la Webcam
durant l'acquisition, on remarque que même à l'oeil nu, on a du mal à distinguer
certaines couleurs. Ainsi, le cubic au milieu à droite n'est pas blanc, mais jaune.
Il est évident que si nous sommes incapables de diérencier les deux couleurs,
le système le peut encore moins. Le phénomène est identique pour la couleur
orange : avec cette caméra le rendu est blanc. La couleur verte est quand à elle
plus problématique, nous arrivons à la distinguer à peu près clairement, cependant, elle est tellement proche du bleu, que notre logiciel l'interprète comme tel
dans environ 65% des cas pour cette caméra.
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.2 Documents illustrant l'opération de capture par la caméra Logitech
QuickCam Chat, en conditions d'éclairage articielles.
Fig.
Sur la gure ci-dessus, les tests sont eectués avec le même matériel que précédemment, sauf que cette fois-ci les conditions d'éclairages sont de moins bonne
qualité : éclairage articiel. Cependant, les résultats sont sensiblement identiques, à savoir une image de très basse qualité, qui ne permet pas de distinguer
les couleurs claires telles que le orange, le jaune et le blanc. Dans ces conditions,
le vert est moins bien rendu qu'en pleine lumière naturelle. Par conséquent, le
pourcentage d'acquisition baisse considérablement dans cette conguration. Les
résultats restent probants pour les cubics rouges, bleus et blancs.
58
Pour la caméra Logitech QuickCam Chat, le résultat n'est donc que très
moyennement satisfaisant, car dans des conditions d'éclairage naturelles, la validité de l'acquisition atteint dicilement les 60%, et dans de mauvaises conditions d'éclairage, ce chire baisse à 50%. Cependant, lorsque nous regardons
l'image produite par cette Webcam, nous pouvons aisément disculper notre
logiciel.
Nous avons testé ce module sur d'autres caméras mieux gérées et plus performantes. Voici les résultats des tests eectués sur celles-ci :
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.3 Documents illustrant l'opération de capture par la caméra Logitech
Navigate STX, en conditions d'éclairage naturelles.
Fig.
Sur la gure précédente, nous voyons les résultats d'acquisitions eectuées
avec une autre caméra Logitech. On remarque d'emblée que l'image générée
par cette Webcam est de bien meilleure qualité que celle de la précédente. Les
conditions d'éclairage sont ici naturelles ; les couleurs sont parfaitement bien distinguables à l'÷il nu. Les résultats d'acquisition sont donc naturellement presque
excellents. En eet, ceux-ci sont presque de 100% pour toutes les couleurs, excepté pour le jaune qui possède cependant de très bons résultats. Il est à noter
que nous obtenons très souvent des résultats de 100% pour toutes les couleurs
avec cette caméra, notamment lors de tests en extérieurs. Ces résultats sont
pour le moins excellents et permettent à l'utilisateur une opération d'acquisition presque sans nécessiter de corrections. Cependant, ils sont obtenus dans des
bonnes conditions d'éclairage, et pour reéter complètement la puissance de
notre acquisition, nous devons aussi tester dans des conditions d'éclairage plus
diciles. Voici ces résultats :
59
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.4 Documents illustrant l'opération de capture par la caméra Logitech
Navigate STX, en conditions d'éclairage articielles (lumière jaune).
Fig.
Ces tests sont eectués en lumière articielle, jaune, donc dans des conditions très diérentes de la lumière naturelle. Les tests restent très bons pour
toutes les couleurs sauf pour le blanc sur cette caméra. La très faible luminosité
de l'image explique assez bien ce résultat. Certes les chires sont mauvais pour
une couleur, mais le pourcentage global est de plus de 83%, ce qui est très bon.
Pour cette caméra Logitech, les résultats sont proches de l'excellence, avec un
taux de réussite naturellement très proche de 100%. Ce sont donc des résultats
très probants, mais qui ne susent pas pour faire de notre acquisition un modèle
de abilité, surtout après les tests sur la première Webcam. Voyons désormais
les tests pour la troisième caméra :
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.5 Documents illustrant l'opération de capture par la caméra Creative
Instant Webcam, en conditions d'éclairage naturelles.
Fig.
Sur la gure ci-dessus, nous voyons les résultats d'acquisition eectuée avec la
caméra Creative. On remarque que la qualité d'image est moins bonne que pour
la précédente caméra, mais que, cependant, les couleurs sont bien distinguées.
Les conditions d'éclairage sont ici naturelles. Les résultats sont identiquement
excellents avec cette Webcam puisque nous frôlons les 100%. Seul le blanc a
quelques petits ratés ; ceci est dû à la clarté relativement faible de l'image.
Cependant, les résultats pour cette couleur restent très satisfaisants. Il est à
noter que là aussi, nous avons souvent obtenu des résultats de 100% de réussite
lors de tests eectués à l'extérieur (i.e. conditions d'éclairage parfaites).
60
10
8
6
4
2
0
Blanc Bleu
Vert Orange Rouge Jaune
(a) Nb de cubics
(moyenne sur 3 essais)
détectés/couleurs (b) Exemple de la qualité d'image produite
par la caméra
10.6 Documents illustrant l'opération de capture par la caméra Creative
Instant Webcam, en conditions d'éclairage articielles (lumière jaune).
Fig.
Les résultats pour les tests eectués en conditions d'éclairage articielles sont
naturellement moins bons que les précédents. Le blanc est encore à 0%, comme
pour la seconde caméra Logitech, et l'acquisition perd un peu de précision pour
le jaune et le orange. Les résultats sont donc d'un peu moins de 80% de bonnes
détections. C'est un peu moins concluant que pour la précédente caméra, mais
cela reste quand même un très bon pourcentage, surtout dans des conditions
d'éclairage extrêmes .
Concluons sur les tests sur la partie acquisition : on a donc pu voir 3 exemples
de tests d'acquisition avec 3 caméras diérentes et dans des conditions d'éclairage diérentes. Les résultats sont globalement très positifs, puisque nous frôlons les 100% de bon résultats pour les Webcams qui fonctionnent de manière
satisfaisante. L'exemple de la première Webcam est là pour montrer que sur
certaines congurations, un utilisateur aura plus de mal à acquérir son cube,
puisque l'opération nécessite quand même une certaine qualité d'image.
10.4.3 Résolution d'un Rubik's Cube
Il est possible de tester les performances du système en calculant, pour des
Rubik's Cube générés aléatoirement, d'une part : le temps moyen mis pour
calculer la solution, et d'autre part : le nombre moyen de mouvements calculés
par l'algorithme.
Pour eectuer ces tests de performances, nous avons conçu un test automatisé par échafaudage : il a fallu créer une méthode mix dans le module solveur spécialement pour générer des Rubik's Cube de manière aléatoire. Cette
méthode utilise un nombre pseudo-aléatoire généré par la fonction rand. En
fonction de la valeur de ce nombre, on applique tel ou tel mouvement au Rubik's Cube. Ainsi, puisque les mouvements sont testés et (a priori) surs, nous
obtenons des congurations de Rubik's Cube aléatoires et valides.
Une fois le cube aléatoire généré, on peut lancer la méthode generateSolution
de l'algorithme de résolution. Nous avons eectué ce test sur un million de Rubik's Cube générés aléatoirement. Le résultat est le suivant : l'algorithme calcule
des séquences de résolution de 99 mouvements en moyennes, en un peu plus de
105 milli secondes en moyenne. Ce résultat est conforme à ce que la bibliothèque
annonçait dans sa documentation, et à la théorie de l'algorithme de résolution
61
couche par couche.
10.5 Tests en boîte noire 10.5.1 Questionnaire
Lors des tests préparatoires, nous avions eectué un sondage sur un panel d'utilisateurs pour connaître leurs goûts et leurs envies. Nous pouvons désormais soumettre le logiciel à leur approbation. Cette approche nous permet
non seulement de tester l'ergonomie du logiciel, mais aussi la stabilité de celuici, puisqu'en multipliant les testeurs, nous multiplions la possibilité de déceler
d'éventuels bugs.
Le questionnaire que nous avons soumis à notre panel d'utilisateur est disponible en annexe.
Cette opération nous a permis de faire remonter des informations intéressantes :
Tout d'abord, l'esthétisme de notre logiciel a été plébiscité. Ainsi, presque la
moitié des sondés le place en tête en ce qui concerne l'esthétisme, devant l'Esp1 .
Cet objectif majeur (un bon esthétisme global) semble donc atteint.
Les utilisateurs sont en grande majorité satisfaits des modes de manipulation proposés. Cependant, les moins expérimentés en informatique préfèrent la
manipulation des faces à la souris, comme c'est le cas pour l'Esp. Cette fonctionnalité étant trop longue à implémenter, nous n'avons pas eectué de modications. Malgré tout, la majorité des sondés est satisfaite de ce que nous leur
proposons.
Nous avons eu des réactions liées à l'ergonomie du logiciel. Par exemple,
certains utilisateurs se sont plaints de la trop grande sensibilité de la rotation
du modèle 3D à l'aide de la souris. Nous avons donc adapté cette opération aux
envies des sondés.
Certains utilisateurs désiraient de plus pouvoir augmenter la taille de la
fenêtre de l'interface, que nous avions xée par commodité. Nous avons donc
modié cela ; désormais, un utilisateur peut augmenter la taille de la fenêtre, ce
qui permet de grossir le modèle 3D.
Nous avons modié une autre fonctionnalité, cette fois-ci concernant l'acquisition manuelle. Au départ, nous ne fournissions comme possibilité pour changer
la couleur des cubics que la molette de la souris. Des utilisateurs se sont plaints
de ne pas avoir de souris à molette, et donc de ne pas pouvoir eectuer d'acquisition manuelle. Nous avons donc ajouté la possibilité de changer de couleurs
avec les boutons gauches et droits de la souris.
1 Logiciel de manipulation de Rubik's Cube en Flash, numéro un en ce qui concerne l'esthétisme lors des tests préparatoires. Disponible ici : http ://www.eviltron.com/modules/esp/
62
10.5.2 Essais d'homologation
Lors des essais eectués avec le client, celui-ci nous a fait part de certaines
remarques quand à l'ergonomie du logiciel. Nous nous sommes eorcés de nous
plier à ses souhaits, dans la mesure du possible, puisque les essais n'ont pu
s'eectuer que vers la n de la phase de codage.
Voici la description de ces remarques, et ce que nous avons entrepris pour y
remédier :
Le client nous a signalé une autre méthode d'acquisition manuelle ergonomique que celle utilisant la souris : la ligne de commande. En eet, il serait
possible de donner la liste des couleurs des cubics sur une ligne de commande.
Nous avons donc procédé à cet ajout : désormais, on peut non seulement changer la couleur des cubics avec la souris, mais on peut aussi rentrer la liste des
couleurs du Rubik's Cube. Cette fonctionnalité n'a pas pu être très optimisée
en raison d'un manque de temps, mais elle est parfaitement fonctionnelle.
Le client nous a aussi fait part d'un souhait particulier concernant la ligne de
commande. En eet, avant que nous ne procédions à des modications, lorsque
l'utilisateur lançait l'analyse d'une commande, celle-ci était analysée, répercutée sur les modèles et supprimée de la ligne de commande. Notre client nous
a fait part de sa préférence pour un curseur qui surlignerait la commande en
cours d'analyse et qui se déplacerait sur la ligne de commande au fur et à mesure des mouvements. Cette fonctionnalité entraînerait l'ajout de la possibilité
au curseur de revenir dans le sens inverse, an de pouvoir recommencer la suite
de commandes. Nous avons donc implémenté cette fonctionnalité. Nous avons
ajouté deux boutons supplémentaires : un qui permet de placer le curseur au
début de la ligne de commande, et un qui permet de nettoyer cette dernière.
Un autre souhait de notre client était de pouvoir régler la vitesse de rotation
du modèle 3D. Nous avons donc ajouté une barre de délement qui permet de
régler ce paramètre.
Un dernier v÷u du client était de pouvoir stopper l'analyse de la ligne de
commande lorsque l'on lance l'exécution complète de celle-ci. Nous avons essayé
de procéder à ce changement, mais sans succès. La raison en est que pour exécuter tout le contenu de la ligne de commande, on eectue une boucle sur l'analyse
d'une seule commande, jusqu'à ce qu'on arrive au bout de la ligne. L'analyse
étant beaucoup plus rapide que les mouvements du modèle 3D, les ordres de
mouvements sur le modèle s'enchaînent et celui-ci les empile, ne s'arrête jamais,
et empêche toute manipulation pendant qu'il eectue sa série. Le seul remède
que nous avons trouvé serait de lancer un thread sur la partie OpenGL, an de
pouvoir garder la main sur l'interface. Hélas, le temps qui nous restait à ce
moment là était bien trop court pour pouvoir eectuer ce changement.
Nous avons tenté de nous plier au maximum aux souhaits du client. Le fait
que nous n'ayons pu commencer à rassembler les diérents modules du logiciel
que 2 semaines avant le terme du projet, et le fait que nous ayons eu une interface
fonctionnelle seulement 1 semaine et demi avant cette date, nous a empêchés de
pouvoir soumettre plus amplement notre logiciel aux envies de notre client.
63
10.6 Tests de fonctionnement
Notre logiciel étant un programme interactif, le gros travail de tests ne peut
se faire de façon automatisée. Nous avons besoin des actions de l'utilisateur pour
tester et déceler des éventuels bugs. Le gros du travail de test à donc été une
exploration de toutes les fonctionnalités du logiciel, en cherchant dans tous les
recoins possibles, la petite bête , et ce, à l'aide de tests en boîte noire . Ce
travail a été renforcé par l'apport, comme signalé plus haut, des sondés, qui, en
utilisant le logiciel, jouent en quelque sorte le rôle de béta-testeurs.
10.7 Tests en boîte blanche 10.7.1 Tests mémoire
Puisque le logiciel est programmé en C++, il est nécessaire de tester la
gestion de la mémoire. Pour cela, nous utilisons l'outil Valgrind. D'autres outils
ont été testés (ccmalloc entre autres), mais les résultats n'ont pas été probants
(ccmalloc faisait planter le programme).
La chasse aux fuites mémoire s'est faite en deux temps : dans un premier
temps les modules séparés, puis dans un second temps sur le programme complet.
Lors de la recherche de fuites mémoire dans les modules, nous avons testé
toutes les fonctions une à une, même si le programme en lui-même n'avait aucun
sens, le but étant de tester la mémoire. Nous avons lors de cette étape supprimé
quelques fuites mémoire. Cette étape a été rapidement terminée.
La deuxième étape a été beaucoup plus problématique. En eet, nous avons
eu la désagréable surprise de découvrir que QT n'est pas un modèle en ce qui
concerne les fuites mémoire. Cela rend la recherche de fuites mémoire très fastidieuse car il faut aller ltrer celles de QT an de trouver les nôtres, ce qui n'est
pas une mince aaire malgré la possibilité qu'ore Valgrind de ltrer les résultats. En tournant seulement 5 minutes, la sortie de Valgrind dépasse les 1200
lignes. Nous avons malgré tout repéré des fuites mémoire que nous avons corrigées. Cependant, le doute demeure parfois quant à la provenance de certaines
fuites mémoire.
Le deuxième problème vient de la mémoire encore atteignable en n de
programme. En eet, QT est là aussi problématique. Cependant, il n'est pas
le seul fautif. En eet la STL utilise un système de cache pour ne pas avoir
besoin de réallouer un objet. La mémoire est vidée uniquement lorsque le cache
est plein ; ainsi il arrive que les classes utilisant la STL aient de la mémoire
encore atteignable à la n du programme. De la même manière, QT utilise
certaines bibliothèques (fontcong notamment) qui ne libèrent pas la mémoire.
Cependant, la mémoire encore atteignable à la fermeture du programme est
moins problématique que les fuites mémoire. En eet, le système d'exploitation
va récupérer la mémoire à la n du programme.
64
Chapitre 11
Extensions et améliorations
possibles
11.1 Extensions
11.1.1 Acquisition
Nous n'avons pas eu le temps d'implémenter l'acquisition par photos. Cependant, cette extension peut être ajoutée dans l'architecture existante en écrivant une classe héritant de la classe abstraite Acquisition. Une solution possible
consisterait à écrire un constructeur prenant en paramètre le chemin d'accès au
répertoire contenant les images des faces. Celles-ci porteraient un nom prédéni (up.ext, down.ext... où ext seraient les formats gérés par le programme).
Le constructeur lirait les images et les stockerait dans un tableau. La fonction
getFrame (servant à acher le ux vidéo) renverrait une image grise, tandis
que getPicture réaliserait l'analyse des images (la méthode de détection n'est
pas encore déterminée, probablement une méthode utilisant la transformée de
Hough).
11.1.2 Résolution
Pour la résolution, il y a plusieurs extensions possibles :
Rubik's Cube 3*3*3 : Ajouter un algorithme plus performant. On pourrait
en eet ajouter l'algorithme de Kociemba.
Autre taille de Rubik's Cube : Ajouter des algorithmes pour les autres
tailles de Rubik's Cube. En eet, les diérents modules de notre programme sont capables de gérer des cubes de tailles quelconques (y compris l'interface Solver). On doit donc ré-implémenter un algorithme pour
chaque taille.
65
11.2 Améliorations
11.2.1 Acquisition
L'acquisition par Webcam, bien que fonctionnelle si les conditions d'éclairage sont susantes, pourrait être améliorée en rendant la détection des couleurs
dynamique. Cette méthode pourrait permettre de mieux détecter les couleurs
dans un environnement sombre. Cela peut se faire en modiant le code de la
classe Webcam (ou en en héritant). Lors du lancement de la Webcam, il sut
de récupérer les premières images du ux et d'en calculer la moyenne. Suivant
le résultat, on décide si l'on est en dessous du palier jour, et on bascule sur le
mode nuit qui contient des valeurs diérentes pour la détection des couleurs.
Cela peut être ané en proposant plusieurs paliers. Il faudrait également relancer la détection de l'environnement à intervalles réguliers ou à la demande de
l'utilisateur an de s'adapter tout seul aux changements d'éclairage.
On pourrait également améliorer la gestion des résolutions diérentes. En
eet, pour l'instant seul le 320x240 est géré. Cependant, ceci pourrait être amélioré facilement : la classe en elle-même est déjà capable de travailler dans des
résolutions diérentes, le seul changement à faire est dans le constructeur de la
classe Webcam. Il faut initialiser la classe CameraEngine (sur laquelle s'appuie
la classe Webcam) avec la résolution voulue et regarder si cela est autorisé. Si la
demande est refusée, il sut de lancer la Webcam en 320x240. Bien que facile,
ce changement n'a pas été fait car pour le moment les Webcams gérant nativement des résolutions plus élevées sont inexistantes (ou presque), la plupart font
une interpolation, ce qui ne sert à rien dans notre cas (à part peut-être dégrader l'image) ; de plus, au début du projet, cela n'était pas une priorité donc le
nécessaire a été fait mais nous ne nous sommes pas focalisés dessus.
11.2.2 Visualisation 3D
La visualisation 3D est le seul module (hormis l'interface) à ne pas être
générique,puisqu'il ne gère que des Rubik's de taille 3*3*3. Il est donc possible
de l'améliorer en le rendant capable de gérer des cubes de taille quelconque.
De plus, la visualisation ne possède pas de gestion du nombre d'images par
seconde, ce qui est relativement ennuyeux : la vitesse dépend de la puissance
du matériel. La présence d'une fonction permettant de gérer la vitesse n'est pas
susante. Sur un vieil ordinateur, la vitesse d'achage du Rubik's Cube serait
lente même avec le réglage de vitesse le plus élevé. A l'inverse, sur un ordinateur
trop puissant, même la vitesse la plus lente serait trop rapide. Cependant, sur
tous les ordinateurs testés, cela n'a pas été gênant.
11.2.3 Interface graphique
L'interface graphique est fonctionnelle ; cependant elle est orientée vers un
Rubik's Cube de taille 3*3*3. Cela n'est pas gênant pour le moment car certains
modules ne sont pas totalement génériques, mais à terme, cela sera un handicap. Certaines parties de l'interface graphique sont déjà génériques : la capture
manuelle, l'achage d'une face (utilisée par la capture manuelle ainsi que pour
la correction de l'acquisition), et l'achage du cube déplié. La ligne de com-
66
mande est également générique. D'autres parties sont pratiquement génériques
(sauvegarde et chargement d'un cube). Le plus gros problème vient du fait que
l'on ne propose pas à l'utilisateur la taille du Rubik's Cube qu'il veut manipuler.
Cependant, les modications nécessaires dans le code ne sont pas importantes
(changement dans le code de chargement d'un nouveau Rubik's Cube, chargement à partir d'un chier ou par acquisition, où il sut de créer un nouveau
Rubik's Cube de taille voulue).
11.2.4 Divers
Certaines parties de code ne sont pas à l'endroit approprié. En eet plusieurs
fonctions dans l'interface graphique ne devraient pas y gurer : le parser de la
ligne de commande doit soit être dans la classe Structure soit dans une classe
parser séparée. La gestion de l'historique des commandes doit être dans une
classe séparée, la fonction mix doit être dans la classe Structure, ainsi que les
fonctions de chargement et sauvegarde.
67
Bilan
Si nous avions du temps supplémentaire
Si nous avions eu du temps supplémentaire, nous aurions pu apporter les
améliorations et extensions décrites précédemment.
Nous aurions pu également porter plus d'attentions aux nitions du logiciel,
améliorations des aides, meilleur organisation de l'interface...
Nous aurions souhaité pouvoir porter plus d'attention à la portabilité sous
MacOSX et Windows.
Si nous devions reprendre de zéro
Si nous devions reprendre le projet depuis le début, nous aurions porté plus
d'attentions à respecter les délais impartis par nous-même. De plus, nous aurions
veillé à améliorer non seulement la communication entre les membres du groupe
mais aussi l'organisation des tâches.
Pour conclure
Côtoyer un domaine comme celui du Rubik's Cube était une expérience très
agréable, mais il est clair qu'il mérite bien sa réputation de casse-tête parfait.
Ce sujet nous a permis de voir diérents aspects techniques de l'informatique : interface, traitement d'images, gestion de matériel, génie logiciel...
Nous avons appris durant ce projet que travailler en groupe n'est pas chose
aisée. En eet, selon nous, la plus grande diculté pour mener à bien un projet
comme celui-ci incombe plus à l'organisation du travail et à la gestion du groupe,
plutôt qu'à la partie technique du projet elle-même.
Nous sommes satisfaits d'avoir pu mener notre projet à bien en ayant atteint
nos objectifs principaux, tout en favorisant l'apprentissage de nouveaux outils
ainsi que de nouvelles méthodes de travail.
68
Glossaire
Algorithme de Dieu : Il s'agit du meilleur algorithme de résolution de Rubik's Cube en théorie. Il a été calculé grâce à la relation qui existe entre Rubik's
Cube et théorie des groupes, que cet algorithme peut résoudre n'importe quel
Rubik's Cube en 22 mouvements maximum.
Cubic : Un des neuf petits cubes composant une face.
Cubiste : Amateur(trice) de la pratique du Rubik's Cube.
Framework : Un framework est un ensemble de bibliothèques permettant le
développement rapide d'applications. Par exemple, un framework peut fournir toutes les fonctions nécessaires à l'utilisation d'une Webcam dans un programme, sans qu'on ait besoin de s'en préoccuper.
Pattern : Un pattern est généralement employé pour désigner un modèle, un
motif ou une structure. Ainsi, en informatique, les design patterns sont des
modèles de conceptions types. Dans le cas du Rubik's Cube, le mot pattern
est employé pour décrire une suite de mouvements permettant d'eectuer une
opération pouvant servir à résoudre le cube.
SpeedCubing : Discipline consistant à résoudre un Rubik's Cube le plus rapidement possible.
SpeedCuber : Personne qui pratique le SpeedCubing.
69
Annexe A
Questionnaire
Voici le questionnaire utilisé pour le sondage :
Quel est votre niveau en informatique :
¤ 1 (aucune connaissance)
¤ 2 (faible)
¤ 3 (moyen)
¤ 4 (bon, conrmé)
¤ 5 (expert)
Quel est votre intérêt pour le Rubik's Cube :
¤ 1 aucun
¤ 2 peu d'intérêt
¤ 3 intéressé
¤ 4 cubiste
Veuillez classer ces logiciels (de 1 à 4 par ordre de préférence) :
Esthétisme général
Manipulation
Ergonomie
Installation
Citer une qualité
Citer un défaut
Note globale
JADA's Cube
CubeTwister
CubeExplorer
Esp
Quels éléments de notre logiciel vous déplaisent et pourquoi ?
Que rajouteriez-vous a notre programme an de le rendre plus intéressant ?
70
Remarques, bugs détectés... :
71
Annexe B
Informations insolites sur le
Rubik's Cube
Découvrons dans cette partie quelques faits divers ou anecdotes concernant
le Rubik's Cube. La majorité des informations est issue de l'excellent site [Jar01]
qui traite du Rubik's Cube de manière assez originale.
B.1 Il existe un timbre hongrois à l'egie du Rubik's Cube. Crédits :
[Jar01]
Fig.
En 1982, d'après des calculs très sérieux, environ un foyer sur trois avait en
sa possession au moins un Rubik's Cube dans l'Ouest Américain.
Deux nouvelles pathologies médicales se sont répandues chez les plus accrocs
au Rubik's Cube. Ces aections sont localisés au pouce et au poignet du cubiste
du fait des mouvements fréquents eectués durant les parties. La fréquence de
ces mouvements peut aller jusqu'à trois et demi par seconde.
Le Cube, grâce à sa renommée internationale et son exportation, a été l'un
des facteurs contribuant à la réforme et à la libéralisation de l'économie hongroise entre 1981 et 1985, et qui a nalement mené au passage d'un régime
communiste à un régime capitaliste.
72
Un jeune cinéaste canadien s'est inspiré
du Rubik's Cube pour écrire son premier
long métrage : Cube, lm fantastique. Il reprend le principe du Rubik's Cube. Les six
personnages du lm sont enfermés à l'intérieur d'un cube dont chaque face donne sur
d'autres cubes, le tout constituant un cube
gigantesque. Le problème est que certains
cubes sont trués de pièges diaboliques et
ultra-sophistiqués, évidemment, des personnages meurent et le lm se concentre ensuite
sur un quatuor composé par un architecte
taraudé par la culpabilité (il a participé à la
construction du cube), une jeune mathéma- Fig. B.2 L'ache du lm Cube
ticienne, un autiste et un policier macho et
violent.
Cube (Canada 1997) de Vincenzo Natali avec Maurice Dean Wint, Nicole
DeBoer. Durée : 1h28. Distribué par Métropolitan FilmExport.
Andreas Mezey, grand auteur hongrois de sa génération, a écrit une pièce à
succès entièrement consacrée au Cube. La pièce a durée trois saisons consécutives dans un grand théâtre de Budapest.
Un match de football américain aux Etats Unis a été retardé quand un des
joueurs, Bob Blake, n'a pas rejoint le terrain. Il a été trouvé dans le vestiaire en
train de s'amuser avec son cube.
En 1992, a la conférence d'Edimbourg des chefs d'états européens, John Major,
le Premier Ministre britannique de l'époque, a utilisé le Cube pour expliquer
à son audience télévisée la complexité du Traité de Maastricht.
73
Annexe C
Howto
C.1 Chargement
Sur le dépôt svn du projet 1 , ou sur le wiki du projet 2 , on peut trouver
des binaires pour Windows, Mac OS X, et Linux (32 bits et 64 bits, testés sur
Ubuntu). Il sut de décompresser l'archive téléchargée et de lancer l'exécutable.
Pour une aide à l'utilisation, consulter la section Utilisation. Si vous décidez de
compiler le programme, vous pouvez charger les sources sur le dépôt ou sur le
wiki. Les instructions pour la compilation sont données dans la partie suivante.
C.2 Compilation
Informations sur les dépendances du projet :
Sous Windows :
Il faut charger QT4 OpenSource Edition [Tro07], ainsi que le patch [Q..07].
Des indications sur l'application du patch et la compilation sont disponibles sur
cette page 3 . Il faut compiler QT4 avec les options suivantes : -exceptions -rtti
-stl -static -release.
Sous Linux :
Nous utilisons la boite à outils graphique QT4.De plus, le projet requiert
que les bibliothèques suivantes soient installées (version devel) : libraw1394 et
libdc1394. Pour l'installation de ces dépendances, nous vous renvoyons au manuel de votre distribution.
Sous Mac OS X :
Nous utilisons QT4. Nous vous renvoyons au manuel de Mac OS X pour
l'installer.
Les programmes de tests ne sont compilés que si CppUnit est trouvé.
En ce qui concerne la compilation, l'outil qmake (fourni avec QT4) doit être
dans le chemin d'accès (variable PATH sur les systèmes UNIX), sinon le chemin
1 https ://services.emi.u-bordeaux1.fr/projet/savane/svn/ ?group=rubikproject
2 http ://projet.rubik.free.fr/pmwiki-2.1.27/pmwiki.php
3 http ://arb.developpez.com/qt4/vc++/compilation/
74
d'accès à qmake doit être fourni à CMake lors de la conguration. Dans le cas
où QT4 et QT3 sont installés (ce qui est fort probable), qmake et moc doivent
pointer sur la version 4 (utiliser l'option -v pour connaître la version). Dans
le cas où ce n'est pas le cas, il faut eectuer les opérations nécessaires (voir le
manuel du système ; sinon ln -s fera l'aaire ; sur les systèmes basés sur Debian,
il existe update-alternatives) ou donner le chemin d'accès à qmake (dans sa
version 4) dans ccmake.
Pour la compilation, nous utilisons donc CMake, qui existe sur Windows,
UNIX et Mac OS X. Quelque soit le système, CMake propose l'exécutable cmake
qui permet de paramétrer la compilation à partir de la ligne de commande.
Cependant, sous Windows, CMake propose CMakeSetup.exe, et sur les autres
systèmes, ccmake. Ce sont des interfaces qui permettent une utilisation plus
intuitive de CMake. Dans ce tutoriel, nous utiliserons ccmake (ou CMakeSetup
sous Windows).
Pour compiler le logiciel, il faut de placer dans le répertoire src, créer un
répertoire build et aller dans celui-ci, puis lancer ccmake .. (ou CMakeSetup).
Les commandes suivantes sont pour les systèmes proposant une console avec sh
(ou un de ses dérivés).
$cd src;
$mkdir build;
$cd build
$ccmake ..
ccmake supporte la complétion avec la touche tabulation. Sous Windows, il
vous est demandé quel système utiliser ; il faut répondre Visual Studio 2003.
Les indications sont données en bas de la fenêtre. Faites congure ( = tapez
'c' dans ccmake). Si les indications sur les dépendances ont été respectées, vous
ne devriez pas avoir de message d'erreur. Si qmake n'est pas trouvé (ou la
mauvaise version), il faut donner le chemin d'accès.
Dans cette fenêtre, vous pouvez régler le type de compilation avec
(CMAKE_BUILD_TYPE), généralement Release ou Debug et le répertoire d'installation (CMAKE_INSTALL_PREFIX). Pour régler plus de détails, vous pouvez passer en mode avancé (tapez 't' dans ccmake). L'option
CMAKE_CXX_FLAGS permet notamment de rajouter des options à la compilation, -Wall par exemple. Pour accéder aux fonctions expérimentales du logiciel, rajoutez dans ce champs -DEXPERIMENTAL.
Refaites un congure ('c' dans ccmake) puis lancez la génération ('g' dans
ccmake). Vous disposez enn dans le répertoire build soit des chiers Visual
Studio, soit des Makeles. Nous vous renvoyons au manuel de ces applications.
Normalement la compilation devrait bien se passer. En cas de problème, make
VERBOSE=1 permet de voir ce qu'il se passe.
Il ne reste maintenant plus qu'à installer le programme. Pour cela faites :
make install (ou sudo make install, ou su ; make install suivant le répertoire
d'installation).
C.3 Utilisation
Lancez l'application. Sous Linux, le périphérique d'acquisition peut être
fourni sur la ligne de commande. Lorsque que cela est proposé, lancez l'acquisi75
tion en 320x240. L'interface ne permet pas de gérer une résolution diérente.
Le logiciel respecte un standard : la bleu est la face up, orange la face left,
blanche front, rouge right, jaune back et verte down. Vous arrivez sur la fenêtre
principale de l'application. Vous avez donc la vue 3D ainsi que la vue dépliée
du cube. Une description des icones est disponible dans la barre de statut.
Pour manipuler le cube, vous avez deux solutions :
Les raccourcis claviers sont les suivants :
U : eectue la rotation Up
Shift+U : eectue la rotation Up'
D :eectue la rotation Down
Shift+D : eectue la rotation Down'
L : eectue la rotation Left
Shift+L : eectue la rotation Left'
R : eectue la rotation Right
Shift+R : eectue la rotation Right'
F : eectue la rotation Front
Shift+F : eectue la rotation Front'
B : eectue la rotation Back
Shift+B : eectue la rotation Back'
La ligne de commandes : les lettres U, D, F, B, L, R réalisent les mouvements up, down, front, back, left, right. Le mouvement inverse se fait avec
2
un ' (U', D', F', B', L', R'). Un double moment se fait avec le caractère .
Pour les acquisitions, il y a deux types d'acquisition possibles :
Manuelle : vous pouvez remplir le Rubik's Cube à l'aide de la souris, les
boutons gauche et droit de la souris et/ou la molette permettent de faire
déler les couleurs des cubics. La barre en bas de la fenêtre permet de
remplir le Rubik en rentrant les couleurs (R=rouge, W=blanc, B=bleu,
G=vert, O=orange, Y=jaune). L'ordre des faces est le suivant : up, left,
front, right, back, down. Les faces sont entrées ligne par ligne.
Vidéo : l'acquisition vidéo permet de créer un rubik à partir d'une Webcam. L'ordre des faces et l'orientation sont indiqués au fur et à mesure.
L'utilisateur doit centrer les cubics de la face dans les carrés prévus à cet
eet. Un appui sur le bouton capture, ou le raccourci ctr+c, permettent
de lancer l'acquisition. Après la capture de la face, une fenêtre permettant
de corriger l'acquisition apparaît.
Pour la résolution, il sut de cliquer sur l'icone de résolution. La solution
apparaît dans la ligne de commandes de l'interface. Il est alors possible de lancer
la résolution.
76
Annexe D
Valgrind
==8841== Memcheck, a memory error detector.
==8841== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==8841== Using LibVEX rev 1658, a library for dynamic binary translation.
==8841== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==8841== Using valgrind-3.2.1-Debian, a dynamic binary instrumentation framework
==8841== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==8841== For more details, rerun with: -v
==8841==
unable to open 2: No such file or directory
==8841== Invalid read of size 4
==8841==
at 0x4014618: (within /lib/ld-2.5.so)
==8841==
by 0x400CFA5: (within /lib/ld-2.5.so)
==8841==
by 0x40108ED: (within /lib/ld-2.5.so)
==8841==
by 0x4E59031: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x400CFA5: (within /lib/ld-2.5.so)
==8841==
by 0x4E591E4: __libc_dlopen_mode (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D74049: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D7356A: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D73C63: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6C52B: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6B093: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6ACF9: iconv_open (in /lib/tls/i686/cmov/libc-2.5.so)
==8841== Address 0x5063218 is 48 bytes inside a block of size 49 alloc'd
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4D7412F: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D7356A: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D73C63: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6C52B: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6B093: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6ACF9: iconv_open (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4A222D3: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4A22749: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4A1D558: QTextCodec::fromUnicode(QString const&)
const
(in /usr/lib/libQtCore.so.4.2.3)
77
==8841==
by 0x498083D: QString::toLocal8Bit() const
(in /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4993EC8: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
==8841== Invalid read of size 4
==8841==
at 0x4014618: (within /lib/ld-2.5.so)
==8841==
by 0x40078D9: (within /lib/ld-2.5.so)
==8841==
by 0x4010D94: (within /lib/ld-2.5.so)
==8841==
by 0x400CFA5: (within /lib/ld-2.5.so)
==8841==
by 0x40108ED: (within /lib/ld-2.5.so)
==8841==
by 0x4E59031: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x400CFA5: (within /lib/ld-2.5.so)
==8841==
by 0x4E591E4: __libc_dlopen_mode (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D74049: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D7356A: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D73C63: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6C52B: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841== Address 0x5063218 is 48 bytes inside a block of size 49 alloc'd
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4D7412F: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D7356A: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D73C63: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6C52B: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6B093: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4D6ACF9: iconv_open (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4A222D3: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4A22749: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4A1D558: QTextCodec::fromUnicode(QString const&)
const (in /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x498083D: QString::toLocal8Bit() const
(in /usr/lib/libQtCore.so.4.2.3)
==8841==
by 0x4993EC8: (within /usr/lib/libQtCore.so.4.2.3)
==8841==
no firewire ports found
Texture not loaded
Texture not loaded
==8841==
==8841== ERROR SUMMARY: 4214 errors from 102 contexts (suppressed: 171 from 1)
==8841== malloc/free: in use at exit: 380,103 bytes in 3,450 blocks.
==8841== malloc/free: 213,733 allocs, 210,283 frees, 204,314,700 bytes allocated.
==8841== For counts of detected errors, rerun with: -v
==8841== searching for pointers to 3,450 not-freed blocks.
==8841== checked 927,188 bytes.
==8841==
==8841==
==8841== 8 bytes in 1 blocks are definitely lost in loss record 14 of 133
==8841==
at 0x402095F: calloc (vg_replace_malloc.c:279)
==8841==
by 0x4867B70: _XCBInitDisplayLock (in /usr/lib/libX11.so.6.2.0)
==8841==
by 0x4850CA4: XOpenDisplay (in /usr/lib/libX11.so.6.2.0)
==8841==
by 0x419849A: (within /usr/lib/libQtGui.so.4.2.3)
78
==8841==
by 0x4142778: QApplicationPrivate::construct(_XDisplay*,
unsigned long, unsigned long) (in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4143562: QApplication::QApplication(int&, char**,
int)
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x806306A: main (in
/home/fabien/pdp/memoire/rubikproject/
trunk/rubik/src/build/bin/Rubik)
==8841==
==8841==
==8841== 12 bytes in 1 blocks are definitely lost in loss record 20 of 133
==8841==
at 0x4021DC5: operator new(unsigned) (vg_replace_malloc.c:163)
==8841==
by 0x80878ED: init() (in
/home/fabien/pdp/memoire/rubikproject/trunk/rubik/src/
build/bin/Rubik)
==8841==
by 0x806F991: GLWidget::GLWidget(QWidget*, QGLWidget*) (in
/home/fabien/
pdp/memoire/rubikproject/trunk/rubik/src/build/bin/Rubik)
==8841==
by 0x8066CFF: MainWindow::createElements() (in
/home/fabien/pdp
/memoire/rubikproject/trunk/rubik/src/build/bin/Rubik)
==8841==
by 0x806C6A0: MainWindow::MainWindow(Rubik*) (in
/home/fabien/pdp
/memoire/rubikproject/trunk/rubik/src/build/bin/Rubik)
==8841==
by 0x806307F: main (in
/home/fabien/pdp/memoire/rubikproject/trunk/
rubik/src/build/bin/Rubik)
==8841==
==8841==
==8841== 20 (16 direct, 4 indirect) bytes in 1 blocks are definitely
lost in
loss record 33 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4C196D4: driCreateDisplay (in /usr/lib/libGL.so.1.2)
==8841==
by 0x4C033CE: __glXInitialize (in /usr/lib/libGL.so.1.2)
==8841==
by 0x4BFECA9: glXGetConfig (in /usr/lib/libGL.so.1.2)
==8841==
by 0x4BFF1BA: glXChooseVisual (in /usr/lib/libGL.so.1.2)
==8841==
by 0x4AF119D: QGLContext::tryVisual(QGLFormat const&, int)
(in /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AEFFF1: QGLContext::chooseVisual()
(in /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AF02A3: QGLContext::chooseContext(QGLContext const*)
(in /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AD42D3: QGLContext::create(QGLContext const*)
(in /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AEEF3F: QGLWidget::setContext(QGLContext*,
QGLContext const*, bool) (in /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AD52AB: (within /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
by 0x4AF0CF8: (within /usr/lib/libQtOpenGL.so.4.2.3)
==8841==
79
==8841==
==8841== 20 bytes in 1 blocks are definitely lost in loss record 35 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4DC195F: strdup (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x41983DA: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4142778: QApplicationPrivate::construct(_XDisplay*,
unsigned long, unsigned long) (in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4143562: QApplication::QApplication(int&, char**,
int)
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x806306A: main
(in /home/fabien/pdp/memoire/rubikproject/trunk/rubik/src/build/bin/Rubik)
==8841==
==8841==
==8841== 38 bytes in 2 blocks are definitely lost in loss record 52 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4805837: FcStrCopy (in /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4808D6C: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4FB43E5: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB506C: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB606D: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB6FB4: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FAE79A: XML_ParseBuffer (in /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4807E8B: FcConfigParseAndLoad (in /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4808185: FcConfigParseAndLoad (in /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4808287: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x48086F1: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
==8841==
==8841== 156 (36 direct, 120 indirect) bytes in 1 blocks are
definitely
lost in loss record 76 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4E34617: (within /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x4E34E65: __nss_database_lookup (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x65BCEEB: ???
==8841==
by 0x65BE05C: ???
==8841==
by 0x4DE2E82: getpwuid_r (in /lib/tls/i686/cmov/libc-2.5.so)
==8841==
by 0x418E23B: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x418ED65: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x474CB4C: _SmcProcessMessage (in /usr/lib/libSM.so.6.0.0)
==8841==
by 0x4760FAB: IceProcessMessages (in /usr/lib/libICE.so.6.3.0)
==8841==
by 0x4188897: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4188916: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
==8841==
==8841== 216 bytes in 1 blocks are definitely lost in loss record 82 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4889415: _XimOpenIM (in /usr/lib/libX11.so.6.2.0)
==8841==
by 0x488925F: _XimRegisterIMInstantiateCallback
80
(in /usr/lib/libX11.so.6.2.0)
==8841==
by 0x486E8A7: XRegisterIMInstantiateCallback
(in /usr/lib/libX11.so.6.2.0)
==8841==
by 0x4568FAD: (within /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4566FF0: QInputContextFactory::create(QString const&,
QObject*)
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x413AB61: QApplication::inputContext() const
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x417ADB6: QWidget::inputContext()
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x41AC106: QWidget::destroy(bool, bool)
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x417D6BB: QWidget::~QWidget()
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x441AE74: QLineEdit::~QLineEdit()
(in /usr/lib/libQtGui.so.4.2.3)
==8841==
by 0x4A02040: QObjectPrivate::deleteChildren()
(in /usr/lib/libQtCore.so.4.2.3)
==8841==
==8841==
==8841== 316 (256 direct, 60 indirect) bytes in 2 blocks are
definitely
lost in loss record 86 of 133
==8841==
at 0x4021620: malloc (vg_replace_malloc.c:149)
==8841==
by 0x4803313: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4803C06: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4803D07: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4808C50: (within /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4FB43E5: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB506C: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB606D: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FB6FB4: (within /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4FAE79A: XML_ParseBuffer (in /usr/lib/libexpat.so.1.0.0)
==8841==
by 0x4807E8B: FcConfigParseAndLoad
(in /usr/lib/libfontconfig.so.1.2.0)
==8841==
by 0x4808185: FcConfigParseAndLoad
(in /usr/lib/libfontconfig.so.1.2.0)
==8841==
==8841==
==8841== 496 bytes in 2 blocks are possibly lost in loss record 96 of 133
==8841==
at 0x4020820: memalign (vg_replace_malloc.c:332)
==8841==
by 0x402087A: posix_memalign (vg_replace_malloc.c:421)
==8841==
by 0x4F55693: (within /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F560E7: g_slice_alloc
(in /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F21368: g_array_sized_new
(in /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F21476: g_array_new
(in /usr/lib/libglib-2.0.so.0.1200.11)
81
==8841==
by 0x4F5D4E2: g_static_private_set (
in /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F2943B: g_get_filename_charsets
(in /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F294B0: (within /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F5D5B9: g_thread_init_glib
(in /usr/lib/libglib-2.0.so.0.1200.11)
==8841==
by 0x4F05709: g_thread_init
(in /usr/lib/libgthread-2.0.so.0.1200.11)
==8841==
by 0x4A17963:
QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate()
(in /usr/lib/libQtCore.so.4.2.3)
==8841==
==8841== LEAK SUMMARY:
==8841==
definitely lost: 602 bytes in 10 blocks.
==8841==
indirectly lost: 184 bytes in 14 blocks.
==8841==
possibly lost: 496 bytes in 2 blocks.
==8841==
still reachable: 378,821 bytes in 3,424 blocks.
==8841==
suppressed: 0 bytes in 0 blocks.
==8841== Reachable blocks (those to which a pointer was found) are not shown.
==8841== To see them, rerun with: --show-reachable=yes
82
Bibliographie
[Aut07a]
AutoConf.
Autoconf - gnu project - free software
foundation
(fsf),
dernière
visite
le
03/04/07,
2007.
http ://www.gnu.org/software/autoconf/.
[Aut07b] GNU Automake. Gnu automake, dernière visite le 03/04/07, 2007.
http ://sources.redhat.com/automake/.
[Bum]
Daniel Bump. The mathematics of the rubik's cube. non publié,
disponible ici : http ://match.stanford.edu/bump/newcube.pdf, dernière visite : le 05/02/2007.
[Can86]
J Canny. A computational approach to edge detection. IEEE Trans.
Pattern Anal. Mach. Intell., 8(6) :679698, 1986.
[Cou97]
Philippe Cousin.
Resoudre le rubik's cube le plus
vite
possible,
dernière
visite
le
31/01/2007,
1997.
http ://lar5.com/cubefr/indexf.html.
[DH72]
Richard O. Duda and Peter E. Hart. Use of the hough transformation
to detect lines and curves in pictures. Commun. ACM, 15(1) :1115,
1972.
[FGJM03] Jean-Pierre Buchweiller Frédéric Gardeux Jacques Marsot. Apports
et dicultés de la vision articielle. Jautomatise, (31), novembre
2003. Les auteurs sont de l'Institut National de Recherche et de
Sécurité (INRS), cet article est un extrait de la publication faite lors
du Safety of Industrial Automated Systems (SIAS) en 2003.
[GTK07a] GTK. Gtk+ the gimp toolkit dernière visite le 03/04/07, 2007.
http ://www.gtk.org/.
[GTK07b] GTKMM. gtkmm - the c++ interface to gtk+, dernière visite le
03/04/07, 2007. http ://www.gtkmm.org.
[HS88]
C Harris and M.J Stephen. A combined corner and edge detector.
In Alvey Vision Conference, pages 147152, 1988.
[Jar01]
Bruno Jarno. Univers rubik, dernière visite le 07/02/2007, 2001.
http ://wrubik.free.fr.
[Joy02]
David Joyner. Adventures in Group Theory : Rubik's Cube, Merlin's
Machine, and Other Mathematical Toys (Broché). 2002.
[Joy 7]
Professor W.D Joyner. Mathematics of the rubik's cube. non publié,
disponible ici : http ://web.usna.navy.mil/ wdj/papers/rubik.pdf,
1996-7.
[Kit07]
Kitware. Cmake cross platform make, dernière visite le 03/04/07,
2007. www.cmake.org/.
83
[Pic00]
Philippe Picart. Les mathématiques et le rubik's cube, dernière visite
le 31/01/2007, 2000. http ://trucsmaths.free.fr/rubik.htm.
[Q..07]
Q../Free. Q... windows edition, dernière visite le 03/04/07, 2007.
http ://qtwin.sourceforge.net/qt3-win32/index.php.
[Sco07]
Scons. Scons : A software construction tool, dernière visite le
03/04/07, 2007. http ://www.scons.org/.
[Tro07]
Trolltech.
Qt trolltech, dernière visite le 03/04/07, 2007.
http ://www.trolltech.com/products/qt.
[Wik07a]
Wikipedia. Les documents multimédia de wikipédia sur le rubik's cube, dernière visite le 31/01/2007, 2007. http ://commons.wikimedia.org/wiki/Category :Rubik%27s_cube ?uselang=fr.
[Wik07b] Wikipedia.
Speedcubing, dernière visite le 31/01/2007, 2007.
http ://fr.wikipedia.org/wiki/Speedcubing.
[Wik07c]
Wikipédia. Tout sur le rubik's cube, dernière visite le 31/01/2007,
2007. http ://fr.wikipedia.org/wiki/Cube_de_Rubik.
[WxW07] WxWidgets. wxwidgets homepage, dernière visite le 03/04/07, 2007.
http ://www.wxwidgets.org/.
84

Documents pareils