UFR de Mathématiques et d'Informatique |
IUP 1, DEUG 2, 2002/2003 |
Algorithmique et programmation orientées objets |
Contrôle continu |
Exercice de programmation |
CUBE
Rapport à rendre le vendredi 9 mai 2001.
Binomes autorisés.
La séance de TP de la semaine du 28 avril sera consacrée
à programmer pour cet exercice :
les encadrants de TP pourront y répondre
aux questions éventuelles.
Il est donc recommendé d'avoir commencé la programmation
avant cette semaine.
1 Le sujet, en bref
Il s'agit de réaliser une implémentation orientée objets,
en Java, du Rubik's cube.
Les sorties se feront sur la sortie standard.
Deux choses sont à réaliser :
- construire le cube ;
- pouvoir tourner chacune de ses faces,
dans le sens des aiguilles d'une montre.
Cette implémentation sera ensuite utilisée pour
compter le nombre de répétitions
d'une séquence, nécessaires pour retrouver l'état de départ.
En effet, une des propriétés du cube est que si,
en partant d'un certain état de départ,
on applique une certaine séquence de manipulations de faces,
alors pour retrouver l'état de départ il suffit
de réappliquer autant de fois que nécessaire cette séquence.
Le nombre de répétitions nécessaires est quant à lui
facilement calculé par une simulation par ordinateur, d'où le présent projet.
(Il est possible d'essayer à la main,
mais il faut savoir que jusqu'à 1260 répétitions
peuvent être nécessaires ....)
2 Le Rubik's cube
Le Hongrois Ernö Rubik a lancé le cube en Hongrie en 1980.
Le cube a ensuite été exporté, via la firme américaine Ideal Toy Company.
Il a connu un succès considérable au début des années 1980.
Aujourd'hui, le cube revient, sur Internet.
Vous pouvez trouver plusieurs applets sur le net.
Par exemple : http://www.npac.syr.edu/projects/java/magic/Magic.html
.
La plupart de ces applets sont programmées, cependant,
de façon assez directe, et pas très orientée-objets,
car leur code n'est pas destiné à servir à autre-chose qu'à animer l'applet.
Le présent projet, par contraste,
met l'accent sur le cube lui-même, et son fonctionnement.
C'est pourquoi nous nous contentons dans ce projet de la sortie standard.
Une fois que votre programme fonctionnera,
vous pourrez facilement lui adjoindre une applet
pour une manipulation graphique du cube.
3 Choix de conception
Il vous est demandé d'implanter le cube en utilisant
la modélisation suivante :
on s'inspire de la façon dont fonctionne le cube <<concret>>,
et on choisit de considérer le cube
comme constitué de 27 petits cubes
(que nous appelerons <<pièces>> dans la suite),
assemblés de façon à former le cube.
Votre programme devra donc comporter au moins les deux classes suivantes :
la classe publique RubiksCube, et la classe Piece.
3.1 Pour parler du cube
Afin que vous puissiez discuter du cube entre vous,
et avec l'examinateur de votre programme,
il est demandé que tout le monde
utilise le même placement initial du cube dans l'espace.
Étant donné le cube initialement posé sur un support horizontal
comme une table, 3 faces sont visibles : la face du devant
(<<front>>), la face du dessus (<<top>>), et la face de droite (<<right>>).
Dans ce projet on ne considère pas de <<basculements>> du cube,
et donc ces trois faces resteront, au cours des transformations du cube,
celles observées depuis le point d'observation initial.
Initialement, les couleurs sont disposées comme suit sur les faces du cube :
face |
colour |
top |
blue |
down |
green |
front |
red |
back |
orange |
left |
white |
right |
yellow |
Les vocables anglais ici utilisés sont ceux utilisés d'habitude
pour parler du cube.
Pour les faces, en particulier, il constituent un standard,
ce qui fait que pour tout cubiste, <<TFL>> signifie :
<<quart de tour dans le sens des aiguilles d'une montre de la face du dessus,
puis
quart de tour dans le sens des aiguilles d'une montre de la face du devant,
puis
quart de tour dans le sens des aiguilles d'une montre de la face de gauche>>.
3.2 La classe RubiksCube
3.2.1 Les méthodes publiques
La classe RubiksCube devra fournir les méthodes publiques suivantes :
- RubiksCube () : le constructeur.
- void setInitialState () : remet le cube dans
son état initial (face <<front>> en rouge, etc.---voir ci-dessus).
- void T() :
effectue un pivotage de la face du dessus (<<top>>)
dans le sens des aiguilles d'une montre.
- void D() :
effectue un pivotage de la face du dessous (<<down>>)
dans le sens des aiguilles d'une montre.
- void F() :
effectue un pivotage de la face du devant (<<front>>)
dans le sens des aiguilles d'une montre.
- void B() :
effectue un pivotage de la face de derrière (<<back>>)
dans le sens des aiguilles d'une montre.
- void L() :
effectue un pivotage de la face de gauche (<<left>>)
dans le sens des aiguilles d'une montre.
- void R() :
effectue un pivotage de la face de gauche (<<right>>)
dans le sens des aiguilles d'une montre.
- boolean isInInitialState () : teste
si le cube est dans son état initial (face <<front>> en rouge,
etc.---voir ci-dessus).
- String toString() :
fournit une description de l'état courant du cube.
3.2.2 L'implantation
Pour l'implantation, l'idée est d'utiliser les tableaux
à plusieurs dimensions de Java, et d'avoir le champ privé suivant :
private Piece[][][] cube ;
où cube est un tableau à trois
dimensions, de longueur 3 dans chaque dimension---i.e.,
le constructeur définira :
cube = new Piece[3][3][3] ;
3.3 La classe Piece
Une pièce est un petit cube.
Ainsi, un coin du cube, dans l'état initial,
peut être vu comme un petit cube
avec trois faces colorées et trois faces non colorées (disons, grises).
3.4 Le principe d'implantation
Le fait d'avoir, pour représenter un cube,
un tableau à trois dimensions de petits cubes,
permet d'implémenter l'opération de pivotage d'une face de
façon simple.
Faire pivoter la face de devant, par exemple (<<front>>),
d'un quart de tour dans le sens des aiguilles
d'une montre (ce que fait la méthode <<F()>>) consiste à :
-
déplacer les pièces des coins, dans le sens des aiguilles
d'une montre ; i.e., par exemple, la pièce du coin <<front-left-top>>
vient au coin <<front-right-top>> du cube ;
- idem pour les pièces en arête : par exemple,
la pièce en <<front-top>> vient en <<front-right>>.
- demander à chacune des pièces de la face
(sauf éventuellement celle du centre) de pivoter sur elle-même,
d'un quart de tour dans le sens des aiguilles d'une montre,
par rapport à sa face <<front>>.
3.5 Repère dans l'espace
L'association suivante devra être suivie pour situer
les pièces dans le tableau à trois dimentions constituant le cube :
la première dimension
correspond à l'axe <<left ® right>>,
la deuxième à l'axe <<down ® top>>, et
la troisième à l'axe <<front ® back>>.
Ainsi, la pièce cube[0][2][0] est le coin <<front-top-left>>.
De façon plus générale,
vous pouvez utiliser un repère pour situer
les faces dans l'espace à trois dimensions.
Dans ce cas, il vous est demandé de suivre
l'association suivante :
l'axe x correspond à l'axe <<left ® right>>,
l'axe y à l'axe <<down ® top>>, et
l'axe z à l'axe <<front ® back>>.
(Ainsi, la première dimension du tableau
suit l'axe x, la deuxième l'axe y, et la troisième l'axe z.)
4 Comment devrait se comporter votre programme
Le test suivant devrait pouvoir fonctionner
avec votre code :
public class TestRubiksCube {
// Test de la classe RubiksCube :
public static void main( String [] args)
{
RubiksCube cube = new RubiksCube() ;
System.out.println(cube) ;
cube.F() ;
System.out.println("\n") ;
System.out.println(cube) ;
System.out.println("\n") ;
System.out.println("Returned to initial state after " +
+ countFTTBDDLL()
+ " instances of FTTBDDLL.") ;
}
public static int countFTTBDDLL() {
RubiksCube c = new RubiksCube() ;
c.F() ; c.T() ; c.T() ; c.B() ; c.D() ; c.D() ; c.L() ; c.L() ;
int k = 1 ;
while (!c.isInInitialState())
{
c.F() ; c.T() ; c.T() ; c.B() ; c.D() ; c.D() ; c.L() ; c.L() ;
k++ ;
}
return k ;
}
}
Une sortie possible pour l'exécution du test précédent
est la suivante :
|OOO|
|OOO|
|OOO|
---
|BBB|
|BBB|
|BBB|
---
WWW|RRR|YYY
WWW|RRR|YYY
WWW|RRR|YYY
---
|GGG|
|GGG|
|GGG|
|OOO|
|OOO|
|OOO|
---
|BBB|
|BBB|
|WWW|
---
WWG|RRR|BYY
WWG|RRR|BYY
WWG|RRR|BYY
---
|YYY|
|GGG|
|GGG|
Returned to initial state after 140 instances of FTTBDDLL.
5 Conseils pour la méthodologie
Conseil pour l'écriture du code :
testez régulièrement votre code.
I.e., écrivez, testez, écrivez, ....
Ainsi, s'il y a un bug à un moment, il devrait être rapidement trouvé.
6 Ce qu'il faut rendre
Il est demandé de rendre un petit rapport comprenant :
Le listing du programme, avec des commentaires.
- Un petit jeu d'essai, comprenant
au moins le cas du test testFTTBDDLL() ci-dessus.
La notation se fera d'une part à partir de ce rapport,
et d'autre part à partir
d'une soutenance rapide (5 à 10 minutes) devant machine,
qui sera faite après le 9 mai,
après que le correcteur aura examiné votre rapport.
Pour cette soutenance devant machine,
l'examinateur disposera d'une batterie de tests (du type de celui ci-dessus),
faisant appel à la classe RubiksCube,
et aux méthodes de cette classe qui ont été demandées,
avec les noms donnés ci-dessus (par exemple : setInitialState).
Il est donc important que vous ne changiez pas
le nom et/ou le prototype des méthodes demandées.
La lisibilité et la compréhensibilité
du listing jouera une part importante dans la note.
Veillez donc, d'une part,
à commenter toute partie non forcément évidente
de votre code ;
et d'autre part à respecter les
conventions de codage standard de Java :
classes:
CapitalizedWithInternalWordsAlsoCapitalized
constants (finals):
UPPER_CASE_WITH_UNDERSCORES
private or protected: (pick one!)
firstWordLowerCaseButInternalWordsCapitalized OR
trailingUnderscore_, OR
thisVar (i.e. prefix with this), OR
myVar (i.e. prefix with my), OR
fVar (i.e. prefix with f)
static private or protected:
firstWordLowerCaseButInternalWordsCapitalized OR
twoTrailingUnderscores__
local variables:
firstWordLowerCaseButInternalWordsCapitalized OR
lower_case_with_underscores
methods:
firstWordLowerCaseButInternalWordsCapitalized()
(Extrait de :
http://gee.cs.oswego.edu/dl/html/javaCodingStd.html,
par Doug Lea.)
Cette convention n'est pas une camisole de force,
mais un moyen de s'assurer, si vous la suivez,
que non seulement votre correcteur lira facilement votre code,
mais également vos camarades,
si vous faites appel à eux en cas de problème sur un point particulier,
puisqu'ils se seront eux-mêmes familiarisés avec la même convention.
N'oubliez pas non plus d'indenter et d'espacer,
de façon à rendre explicite la structure de votre programme.
Par exemple, l'examinateur ne sera pas mis de bonne humeur
du tout si votre code ressemble au suivant :
class Colour{private String name;private Colour(String s){name=s;}
public static final Colour WHITE=new Colour("W");
public static final Colour YELLOW=new Colour("Y");
public static final Colour RED=new Colour("R");
public static final Colour ORANGE=new Colour("O");
public static final Colour BLUE=new Colour("B");
public static final Colour GREEN=new Colour("G");
public static final Colour GREY=new Colour("*");
public boolean equals(Colour col2){return name.equals(col2.name);}
public String toString(){return name;}}
(Une version préférable peut être vue ci-dessous.)
7 Indications
On pourra utiliser les classes suivantes,
en les modifiant si nécessaire :
Ces classes peuvent être téléchargées à partir de la page
http://dpt-info.u-strasbg.fr/~gerner
.
This document was translated from LATEX by
HEVEA.