Le troisième volet de cette série le jeu de la vie en 7 langages sera consacré à Racket, un dialecte de Lisp. Télécharger le ici: http://download.racket-lang.org/ et installez avec bash ./nom-du-fichier.sh

On commence par un smoke test pour être sûr que Racket est bien installé et accessible. Dans un fichier game-of-life-test.rkt, chargez le framework de test et le futur fichier d’implémentation.

#lang racket

(require rackunit
         "game-of-life.rkt")

Puis executez le :

$ racket game-of-life-test.rkt
game-of-life-test.rkt:4:9: cannot open module file

Cool, Racket est là et nous dit qu’il ne peut pas ouvrir le fichier game-of-life.rkt. Créons le :

touch game-of-life.rkt
#lang racket

Premier test maintenant, la fonction create-generation doit renvoyer une liste.

#lang racket

(require rackunit
         "game-of-life.rkt")

(check-pred list? (create-generation 3 4))
$ racket game-of-life-test.rkt 
game-of-life-test.rkt:6:19: create-generation: unbound identifier in module

Ok, on renvoie donc une liste vide '(). Notez aussi provide, qui permet de définir en quelque sorte les fonctions publiques du fichier.

#lang racket

(define (create-generation width height)
  '())

(provide create-generation)

rackunit, le framework de test shippé avec Racket peut aussi documenter les tests:

(check-equal? (length (create-generation 3 4)) 4
              "It builds a list with the right height")

On crée une liste de la bonne taille, et comme on se fiche pour l’instant de ce qu’elle contient, on peut l’initialiser avec des zéros.

(define (create-generation width height)
  (make-list height 0))

Chaque élément de la liste doit aussi être une liste (la dimension x).

(check-equal? (length (first (create-generation 3 4))) 3
              "It builds a list with the right width")
$ racket game-of-life-test.rkt 
length: contract violation
  expected: list?
  given: 0

J’utilise for/list pour construire cette fameuse liste à deux dimensions. Les différentes variantes de for me semble très utilisées en Racket.

(define (create-generation width height)
  (for/list ([i (make-list height 0)])
            (make-list width 0)))

Finalement, je veux que ma liste contiennent des 0 (cellule morte) et des 1 (cellule vivante).

(let ([cell (first (first (create-generation 3 4)))])
  (check-true (or (= cell 0) (= cell 1))
              "It populates generation with 0s or 1s"))
(define (create-generation width height)
  (for/list ([i (make-list height 0)])
            (make-list width (random 2))))

Ce dernier bout de code contient un bug qui n’est pas attrapé par les tests (vous l’avez vu ?). Je fixerais ça dans le prochain article.