Avant de commencer, je tenais à préciser que certaines parties du codes sont faussement interprétées comme étant des signes utilisée dans le langage de programmation des billets (notamment les crochets utilisés pour faire un lien). Ne pouvant pas changer ce qui était écrit dans mon code, je n'ai pas trouvé de solution à ce problème et tenais à m'en excuser.

1. Introduction

Ne vous est-t'il jamais arrivé, alors que vous en aviez subitement besoin, de ne pas avoir d'échiquier ni de logiciel permettant de jouer aux échecs sur vous? Moi non plus, mais ce n'est pas une raison pour ne pas se frotter à la programmation orienté objet. Le but de ce projet sera de réaliser un jeu d’échec informatique pour ios. Le programme devra permettre à deux humains de jouer sur la même machine entre eux en suivant les règles des échecs classiques(1) .

Je n'ai strictement aucune expérience en programmation orienté objet. Je ne sais donc pas dans quelles mesures ce projet sera réalisable. Le but de ce travail n'est pas uniquement d'écrire un programme qui fonctionne, mais aussi de m'initier à ce type de programmation en découvrant certains de ses aspects. Je pense cependant arriver à un résultat plutôt concluant avec un jeu d'échec qui fonctionne globalement.

2. Matériel et méthodes

2.1 Matériel

  • Mon ordinateur portable
  • Le logiciel Xcode

2.2 Méthode

Pour simplifier une fois pour toute la compréhension des explications, voici un schéma de l'échiquier que j'ai utilisé.

Schéma échiquier.pdf

Schéma 1 : numérotation de l'échiquier et système d'axe

L'axe x et y sont en effet inversés par rapport aux conventions mais je me sentais plus à l'aise dans ces conventions-ci. La numérotation des lignes et des colonnes ne se fait pas de 1 à 8 mais bien de 0 à 7 comme souvent en programmation.

Pour créer le jeu, j'ai commencé par décrire une série de classes (2). Premièrement, la classe mère : "piece". C'est de cette classe que sont héritées (3) l'entièreté des autres classes de pièces. J'utilise ensuite une classe "plateau" pour contenir les pièces, décrire leurs déplacements et les règles du jeu. Les classes sont agencé selon ce schéma.

Schéma classes .pdf

Schéma 2 : agencement des classes

La classe "piece" comporte plusieurs variables servant à décrire les pièces :

 class piece {
   var name : String = "/"
   var couleur : String = "B"
   var positionx : Int = 1
   var positiony : Int = 1
   var points : Int = 1
 }
  • La variable "name" définit le nom des pièces. C'est en fait la variable qui est utile pour afficher l'échiquier.
  • La variable "couleur" indique si la pièce appartient au joueur des pièces blanches ou noires.
  • Les variables "positionx" et "positiony" permettent de définir une position sur l'échiquier pour chaque pièce
  • La variable "points" n'est pas utilisée dans mon programme mais servira lorsque je voudrais développer une Intelligence Artificielle contre qui jouer.

La classe piece comporte aussi un constructeur (4) pour permettre de déclarer les pièces plus facilement.

 init(name : String, couleur : String, positionx : Int, positiony : Int, points : Int) {
           self.name = name
           self.couleur = couleur
           self.positionx = positionx
           self.positiony = positiony
           self.points = points
       }

Elle comporte aussi une fonction vide qui sera surchargée par les classes autres classes de pièces.

 func move(deplacementx : Int,deplacementy : Int) -> Bool {
       return true
 }

Dans les différentes classes de pièces, on retrouve la même structure ; les seules variables sont celles héritées de la classe piece mais la méthode "move" prend son sens dans les classes de pièces. La seule faisant exception est la classe "void" qui n'a pas de fonction "move" pour la simple et bonne raison qu'elle représente les cases vides qui ne doivent, par conséquent, pas bouger.

 class void : piece{
  
 }

Voici par exemple la classe "reine" qui regroupe, de par sa capacité à se déplacer en ligne et en diagonale, les conditions de déplacement des pièces de la classe "fou" et "tour".

 class reine : piece {
    
    override func move(deplacementx : Int,deplacementy : Int)->Bool {
        
        if (abs(deplacementx - positionx) == abs(deplacementy - positiony))  || 
             (((deplacementx - positionx != 0 && deplacementy  - positiony == 0) || 
             (deplacementx - positionx == 0 && deplacementy - positiony != 0))) {

            positionx = deplacementx
            positiony = deplacementy
            return true
        }
        return false
    }
}

La fonction "override" permet de redéfinir la fonction précédemment décrite dans la classe "piece" (Il s'agit d'une surcharge). Ici, la méthode prend deux paramètres "deplacementx" et "deplacementy". Ces deux paramètres représentent la position sur l'échiquier de la case ou le déplacement doit être effectué. La méthode renvoie une valeur booléene.

Si la reine se déplace d'autant de case sur l'axe x et l'axe y, elle a le droit de se déplacer car c'est un mouvement en diagonale. De la même manière, si la reine se déplace sur un axe uniquement, il s'agit d'un déplacement en ligne. Elle peut alors effectuer le déplacement. La méthode va alors remplacer les anciennes coordonnées de la pièce par les nouvelles et renvoyer "true" pour affirmer que le déplacement peut avoir lieu. Si les conditions ne sont pas respectées, elle renvoie "false". L'utilisation de la valeur absolue par la fonction "abs()" permet d'englober les cas où la reine se déplace vers le haut ou vers la gauche. Dans ces cas, la différence entra "position" et "deplacement" est négative.

Les différentes classes de pièces ont toujours la même structure. La seule chose qui diffère est bien évidement la condition de déplacement. Voici celle du cavalier qui, je le rappelle, se déplace de deux cases sur un axe et d'une case sur l'autre :

if ( (abs(deplacementx - positionx) == 1 && abs(deplacementy - positiony) == 2) || 
      (abs(deplacementx - positionx) == 2 && abs(deplacementy - positiony) == 1) ) { ...

On utilise à nouveau la valeur absolue pour le déplacement du roi :

 if (abs(deplacementx - positionx) == 1 || abs(deplacementx - positionx) == 0 ) && 
    (abs(deplacementy - positiony) == 1 || abs(deplacementy - positiony) == 0) {

Enfin, la dernière pièce qui n'est pas des moindres, le pion. Le déplacement du pion est plus complexes que les autres car il se comporte différemment en fonction de sa position sur le plateau, de sa couleur et de sa proximité avec d'autres pièces. Contrairement aux autres classes, j'ai dû vérifier une série de conditions pour permettre le déplacement :

       if couleur == "B" {
           if positionx == 1 && (deplacementx - positionx == 2 && deplacementy - positiony == 0) {
               positionx = deplacementx
               positiony = deplacementy
               return true
           }
           else if  deplacementx - positionx == 1 && deplacementy - positiony == 0 {
               positionx = deplacementx
               positiony = deplacementy
               return true
           }
           else if chessplate.plateaudeplacementxdeplacementy.name != "  " && 
                   deplacementx - positionx == 1 && abs(deplacementy - positiony) == 1{
               positionx = deplacementx
               positiony = deplacementy
               return true
               
           }
       }
       
       else {
           if positionx == 6 && deplacementx - positionx == -2 && deplacementy - positiony == 0 {
                   ...

Ici, le pion adopte des comportements ressemblants s'il est blanc ou noir ; les conditions pour se mouvoir sont exactement les mêmes si ce n'est que les déplacements de pions noirs sont négatifs. Les pions peuvent se déplacer de deux cases s'ils n'ont pas encore bouger. J'ai traduit cette conditions en permettant à un pion de bouger de deux cases sur l'axe x s'il était dans la bonne ligne (la deuxième en partant du haut pour les pions blancs et la deuxième en partant du bas pour les pions noirs). Ensuite, le pion peut se déplacer d'une case sur l'axe des x à conditions qu'il n'effectue aucun déplacement sur l'axe y. Enfin le pion a la possibilité de prendre une pièce en avançant en diagonale d'une case. Il peut donc se déplacer de plus ou moins une case sur l'axe y et d'une case sur l'axe x si une pièce d'une autre classe que "void" s'y trouve. Cette condition est traduite comme ceci : le nom de la pièce ne doit pas être celui de la pièce de classe "void".

Il faut ensuite déclarer l'entièreté des pièces. Pour ceci, j'ai dédié un fichier "Declaration pieces.swift". Grâce au constructeur, j'ai pu déclarer les pièces relativement simplement :

 let pionb1 = pion(name : "PB", couleur : "B", positionx : 1, positiony : 0, points : 1)
 let pionb2 = pion(name : "PB", couleur : "B", positionx : 1, positiony : 1, points : 1)
 let pionb3 = pion(name : "PB", couleur : "B", positionx : 1, positiony : 2, points : 1)
 ...
 let cavaliern1 = cavalier(name : "CN",  couleur : "N", positionx : 7, positiony : 1, points : 3)
 ...

On voit que les pions blancs ont tous le même nom, la même couleur, la même position x et valent les mêmes points. La seule variable qui change est leur position sur l'axe y. En effet, Ils sont initialement disposés sur la même ligne. Ayant initialisé les pions, notre échiquier ressemblera à ceci :

Schéma disposition pions.pdf

Schéma 3 : disposition des pions blancs sur l'échiquier

Comme je l'ai expliqué précédemment, j'utilise le nom des pièces pour les afficher dans l'échiquier.

Le cavalier diffère des pions; son nom, sa couleur, sa position et ses points sont différents mais la structure du cavalier reste la même car il s'agit aussi d'une pièce. Les noms des pièces sont :

  • K : roi
  • Q : reine
  • P : pion
  • C : cavalier
  • T : tour
  • F : fou
  • B : blanc
  • N : noir

Initialement, je n'avais pas fait de classe pour l'échiquier. Mais certains problèmes se sont révélés très complexes car l'absence d'échiquier impliquait que les pièces devait "voir" les autres pièces. L'échiquier qui contient toute les pièces permet de situer facilement les pièces par rapport aux autres. Cette approche m'était totalement inconnue ; il faut se demander qu'est ce qui est propre à quoi.

En effet, chaque pièce se déplace différemment et indépendemment des autres, il faudra donc une méthode propre à chaque classe de pièce. Les déplacement des pièces dépendent des autres pièces sur le plateau. Il faudrait donc avoir une classe qui connait la position de toute les pièces et qui peut, par conséquent les bouger, vérifier si le déplacement demandé par le joueur est correct, etc.

J'ai donc créer une classe "plateau" comportant 2 variables :

 class plateau {
 var plateau = [tourb1,cavalierb1,foub1,roib,reine...,pionb1,pionb2,pionb3,pionb4,pionb5,...,
                        void0,void0,void0,void0,void0,void0...,void0,void0,void0,void0,void0,void0...,
                        void0,void0,void0,void0,void0,void0...,void0,void0,void0,void0,void0,void0...,
                        pionn1,pionn2,pionn3,pionn4,pionn5,...,tourn1,cavaliern1,foun1,reinen,roin...]
   
  var display: [String] = [String](repeating:String(repeating:String(), count: 8), count: 8);

La variable "plateau" est un array en deux dimensions qui représente le plateau et qui contient les pièces et sur lequel on effectue les déplacements, on teste les conditions pour déplacer des pièces etc. Le plateau est initialisé de la manière classique dont une partie d'échec commence. L'array "display" est vide et permet d'afficher le plateau, de manière compréhensible pour le joueur.

La classe "plateau" comporte plusieurs méthodes utiles aux déplacement des pièces et à l'affichage du plateau.

La première est la méthode "print_plateau ()" qui sert simplement à afficher le plateau de jeu.

func print_plateau() {
       print ("     0     1     2     3     4     5     6    7")
       for i in 0...7 {
           for j in 0...7 {
               displayij = plateauij.name
           }
           print (i,displayi)
       }
   }

Elle affiche premièrement les numéros de colonnes, puis elle affiche ligne par ligne le numéro de ligne et le display du plateau qui contient les noms des pièces. J'utilise une double boucle for pour parcourir l'entièreté du tableau et copier tous les noms des variables. Les cases contenant des void affiche " " car il s'agit du nom de la pièce "void0".

Ensuite, j'ai créé une méthode pour vérifier si la pièce devant être manger n'a pas la même couleur que celle qui attaque.

 func can_eat (p_ix: Int,p_iy: Int,p_fx: Int,p_fy: Int) -> Bool{
       if plateaup_ixp_iy.couleur == plateaup_fxp_fy.couleur{
           return false
       }
       return true
   }

Dans les faits, à chaque fois qu'une pièce se déplace sur une case vide, elle mange en fait une pièce "void0" qui n'est pas de la même couleur (void0.couleur vaut " ").

Ensuite, il faut trouver un moyen d'empêcher les pièces de traverser d'autres pièces sur leur chemin. Cette règle ne s'applique ni aux cavaliers, qui sautent par-dessus les autres pièces, ni aux pions et au roi, qui eux ne peuvent se déplacer que d'une case.

Schéma méthode can_move.pdf

Schéma 4 : méthode can_move possibilité de déplacement

Ainsi, il faut décrire certaine condition pour le fou, la tour et la reine. Puisque la reine est une combinaison des deux autres déplacements, il suffit en fait de vérifier les conditions "si c'est une tour ou une reine, il n'y a aucune pièce entre la pièce et son déplacement en ligne droite" et " si c'est un fou ou une tour, il n'y a aucune pièce entre la pièce et son déplacement en diagonale". Ces conditions, c'est la méthode de la classe plateau intitulée "can_move" qui les décrits :

func can_move (p_ix: Int,p_iy: Int,p_fx: Int,p_fy: Int) -> Bool {
 
   let difx = abs(p_fx - p_ix)
   let dify = abs(p_fy - p_iy)
   var vect = (p_fx - p_ix),(p_fy - p_iy)
   if difx != 0 {
       vect0 /= difx
   }
   if dify != 0 {
       vect1 /= dify
   }
   ...

Premièrement, on définit un vecteur unitaire qui exprime la direction du déplacement souhaité. Pour ce faire on divise chaque composante par sa norme (valeur absolue du déplacement sur l'axe : "dif_x" et "dif_y"). Puisque le vecteur déplacement peut être du type (y , 0) ou (0 , x) dans le cas d'un déplacement en ligne droite, il faut préciser que "dif" ne doit pas valoir 0 avant d'effectuer la division.

Ensuite, à l'aide d'une boucle for, je teste les cases une par une dans la direction de "vect" (sans tester la dernière car il s'agit de la case dans laquelle se retrouvera la pièce après le déplacement. Si on prenait en compte cette case, les pièces n'aurait pas la possibilité de manger d'autre pièce que "void0".

Pour une reine ou un fou, on vérifie toutes les cases en diagonale, soit toutes les cases entre la position initiale est finale en ajoutant i * "vect" aux deux coordonées de la position initiale de la pièce. La méthode return "false" si la condition n'est pas respecté et "true" si elle l'est.

if type(of:plateaup_ixp_iy) is fou.Type || type(of:plateaup_ixp_iy) is reine.Type{
       if difx != 0 {
           for i in 1...difx{
               // On ne veut pas vérifier la dernière case
               if i != difx {
                   // On ajoute i * le vecteur pour vérifier toutes les cases intermédiaires
                   if type(of: plateaup_ix + i * vect[0]p_iy + i * vect[1]) is void.Type {
                   }
                   else {
                       // On return false si il y'a des pièces entre la pièce et son point d'arrivée
                       return false
                   }
               }
           }
       }

Pour une reine ou une tour, on vérifie que les cases en lignes, soit toutes les cases entre la position initiale et finale en ajoutant "i * vect" à la position initiale x lors d'un déplacement sur l'axe x ou à la position initiale y lors d'un déplacement sur l'axe y.

 ...
  // Conditions pour un déplacement en ligne droite (tour ou reine)
    if type(of:plateaup_ixp_iy) is tour.Type || type(of:plateaup_ixp_iy) is reine.Type{
        // Déplacement horizontal
        if difx == 0 {
            for i in 1...dify{
                if i != dify {
                    if type(of: plateaup_ixp_iy + i * vect[1]) is void.Type {
                    }
                    else {
                        return false
                    }
                }
            }
        }
        // Déplacement vertical
        else if dify == 0 {
            for i in 1...difx{
                 if i != difx {
                    if type(of: plateaup_ix + i * vect[0]p_iy) is void.Type {
                    }
                    else {
                        return false
                    }
                }
            }
        }
    }
    ...

La dernière méthode de la classe plateau regroupe les autres méthodes. Elle permet de bouger une pièce en vérifiant les différentes conditions avec les méthodes dont nous avons traité antérieurement.

func move_piece (p_ix: Int,p_iy: Int,p_fx: Int,p_fy: Int)  {
       if plateaup_ixp_iy.couleur != joueur &&  p_fx < 8 && p_fx < 8 && p_fy >= 0 && p_fy >= 0 && 
                  can_move(p_ix: p_ix, p_iy: p_iy, p_fx: p_fx, p_fy: p_fy) && 
                  can_eat (p_ix: p_ix, p_iy: p_iy, p_fx: p_fx, p_fy: p_fy) && 
                  plateaup_ixp_iy.move(deplacementx: p_fx, deplacementy: p_fy){
 ...

Dans les conditions, on retrouve la méthode "can_move" qui vérifie qu'il n'y a pas d'obstacle au déplacement, la méthode "can_eat" qui vérifie que la couleur des deux pièces n'est pas identique, la méthode "move" qui vérifie que la pièce en question a la capacité de se déplacer de cette manière et d'autres conditions diverses ; l'utilisateur ne peut pas demander à une pièce de se déplacer en dehors de l'échiquier et un joueur ne peut pas jouer les pièces de son adversaire. La variable "joueur" représente la couleur des pièces que le joueur a le droit de jouer. Comme "joueur"change AVANT que le joueur ait joué son coup, la condition est bien :

 if plateaup_ixp_iy.couleur != joueur

et non, comme on le penserait instinctivement,

 if plateaup_ixp_iy.couleur == joueur

Si l'entièreté des conditions sont respectées, on effectue le déplacement :

  plateaup_ixp_iy.move(deplacementx: p_fx, deplacementy: p_fy)
           plateaup_fxp_fy = plateaup_ixp_iy
           plateaup_ixp_iy = void0
           }

Sinon, on rejoue le tour sans changer de joueur et sans effectuer le déplacement :

 else {
           chessplate.print_plateau()
           print ("Déplacement impossible!")
           turn()
       }

A présent que l'intégralité de nos classes, méthodes et pièces ont été décrites, il faut permettre au joueur de jouer de façon alternée. C'est pourquoi j'utilise dans le fichier main.swift la variable "joueur" dont j'ai parlé plus haut, ainsi que la fonction "change_turn" qui, comme son nom l'indique gère le tour à tour.

func change_turn (){
   if joueur == "B" {
       print ("C'est aux Blancs de jouer.")
       joueur = "N"
   }
   else {
       print ("C'est aux Noirs de jouer.")
       joueur = "B"
   }
}

La deuxième fonction du main regroupe l'intégralité des concepts dont j'ai traité jusqu'ici, il s'agit de la fonction "turn()" qui fait se dérouler un tour entier pendant lequel un des deux joueurs va déplacer une pièce. La fonction décompose une commande entrée par le joueur en vérifiant chacun des nombres rentrés un à un. La commande pour faire bouger la pièce prend cette forme :

  • position initiale x position initiale y "espace" position finale x position finale y

Par exemple : "12 22" (Ici, la commande permettrait au joueur blanc d'avancer le pionb3 d'une case.)

Cette démarche évite de devoir taper 4 positions distinctes à chaque déplacement de pièce. Voici la fonction en question :

func turn () {
input = readLine() ?? "00 00"
let pos_i :String = input.components(separatedBy: " ")0
let pos_f :String = input.components(separatedBy: " ")1
let a = Int(pos_i.first?.description  "")  0
let b = Int(pos_i.last?.description  "")  0
let c = Int(pos_f.first?.description  "")  0
let d = Int(pos_f.last?.description  "")  0
chessplate.move_piece(p_ix: a, p_iy: b, p_fx: c, p_fy: d)
chessplate.print_plateau()
}

Après avoir stocké la commande dans une variable "input" et l'avoir décomposée, la fonction utilise la méhtode "move piece" pour le plateau de jeu "chessplate" qui est de type "plateau.Type" et admet les valeurs par défaut déclarée lors de l'initialisation de la classe. On utilise ensuite la méthode "print_plateau" pour afficher le plateau actualisé.

A présent, le programme est extrêmement simple. Il se rédige en fait en à peine 5 lignes :

chessplate.print_plateau()
for _ in 0...100 {
   change_turn()
   turn()
}

La boucle for permet d'imposer une fin à la partie. En effet, je n'ai pas encore de fonction pour annoncer l'échec et mat qui met fin à la partie. Je suis donc parti du principe qu'une partie conventionnelle ne durerait pas plus de 100 coups.

3. Résultats

Le jeu semble globalement fonctionné malgré les nombreux ajouts qu'il manque, le minimum pour mener une partie d'échec est présent.

can_eat example.png

Figure 1 : Illustration de la méthode "can_eat"

Ici, on peut voir que la méthode "can_eat" fonctionne, en effet, une pièce blanche ne peut pas manger une autre pièce blanche et inversément. De plus, toutes les pièces peuvent "manger" les cases contenant "void0".

can_move example.png

Figure 2 : Illustration de la méthode "can_move"

La méthode "can_move" fonctionne aussi, si une pièce fait obstacle, le déplacement n'a pas lieu.

Joueur noir joue une pièce blanche.png

Figure 3 : Joueur essayant de déplacer une pièce qui ne lui appartient pas

On voit que le joueur ne peut jouer que ses propres pièces.

mvt hors plateau example.png

Figure 4 : Joueur essayant en dehors du plateau

Le joueur ne peut pas effectuer un déplacement hors plateau.

Concernant le déplacement des pièces, on peut voir que la méthode "move" fonctionne. En voici quelques exemples :

Déplacement pion.png

Figure 5 : Exemple de déplacement d'un pion

Déplacement fou.png Figure 6 : Exemple de déplacement d'un fou

Déplacement cavalier.png

Figure 7 : Exemple de déplacement d'un cavalier

Déplacement reine.png

Figure 8 : Exemple de déplacement de la reine

Déplacement roi.png

Figure 9 : Exemple de déplacement du roi

Déplacement tour.png

Figure 10 : Exemple de déplacement d'une tour

4. Discussion

Bien que je sois globalement content de mon travail, j'ai conscience qu'il a ses limites et qu'il mériterait nombre d'améliorations. En effet le jeu ne contient pas toutes les règles des échecs, à commencer par la plus importante : l'échec et l'échec et mat. C'est un aspect particulièrement important que je n'ai pas réussi à implémenter dans mon code. En effet, l'échec est un aspect primordial des échecs car il oblige l'adversaire à effectuer des déplacements pour sauver son roi de l'échec.

D'un point de vue informatique, il faudrait être capable de créeer une fonction ou une méthode qui déterminerait après chaque déplacement si un des rois est menacé par au moins une pièce adverse. Tant que cette condition n'est pas levée, le joueur n'aurait pas le droit d'effectuer de déplacement, étant ainsi forcé à protéger son roi.

Le roque(5) est une règle important qui stipule que le roi et sa tour peuvent se déplacer de manière particulière sous certaine conditions. Il faudrait probablement poser une série de conditions dans la méthode "move" de la classe "roi" et "tour". (La prise en passant (6) n'est pas non plus présente. Il faudrait, encore une fois, ajouter dans la classe "pion" certaines conditions.)

Lorsqu'un pion atteint le bord adverse du plateau, le joueur peut décider de le changer en une autre pièce (généralement une reine). Il faudrait ici changer le type du pion lorsqu'il arrive sur le bord opposé ou le remplacer en créant une pièce du bon type à la place du pion.

Mis à part les différentes règles qui ne sont pas encore implémentées, j'aurai beaucoup souhaité créer une interface graphique pour le jeu d'échec. Je n'ai cependant pas pu découvrir ces deux pans de la programmation (orientée objet et les interfaces graphiques) et, comme il s'agit d'un aspect visuel, j'ai décidé de me concentrer sur la découverte du langage Swift.

J'ai conscience que mon code effectue probablement beaucoup de détours et qu'il n'est pas aussi concis qu'il pourrait l'être. En effet n'ayant jamais touché à un langage de programmation orienté objet, je n'avais pas les connaissances pour comprendre comment résoudre certains problèmes sans un savoir extérieur pour me l'expliquer. Bien que j'ai pu chercher la réponse à la plupart de mes questions sur Internet, certains aspects (je pense notamment à la création d'une classe plateau) m'ont totalement échappé par manque d'expérience.

Malgré les nombreuses imperfections, je suis satisfait de mon travail et pense avoir, au-delà de la note, eu un avant-goût de ce qui m'attendra l'année prochaine à l'EPFL. Bien qu'il ait nécessité plus d'investissement que je ne l'imaginais, mon objectif premier, à savoir la découverte d'un type de programmation jusqu'ici inconnu, est atteint.

5. Conclusion

Durant ce projet, j'ai pu m'apercevoir de la puissance des languages de programmation orientés objet et ai développé un certain intérêt pour le langage Swift en particuliers. J'ai créé un jeu d'échec, avec beaucoup de défauts et d'imperfections certes, mais un jeu qui globalement marche et que j'arriverai probablement à améliorer avec quelques heures de plus. Ma prochaine étape sera l'ajout des règles citées et la création d'une interface graphique.

Références

(1) Règles du jeu d'échec : https://fr.wikipedia.org/wiki/R%C3%...

(2) Les classes et structures : https://openclassrooms.com/fr/cours...

(3) et (4) L'héritage : https://openclassrooms.com/fr/cours...

(5) Le roque aux échecs : https://fr.wikipedia.org/wiki/Roque...

(6) La prise en passant : https://fr.wikipedia.org/wiki/En_pa...

Sources ayant répondu à la majorité de mes questions

Site Stack Overflow : https://stackoverflow.com/

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

https://stackoverflow.com/questions...

Site OpenClassroom : https://openclassrooms.com

https://openclassrooms.com/fr/cours...

https://openclassrooms.com/forum/su...