Comme j'ai déjà eu l'occasion d'en parler : jouer ou créer un jeu est particulièrement didactique pour apprendre à programmer.
c'est BonusCAD qui s'y colle encore.
Il a créé un clone du jeu 2048, bien connu paraît-il car j'avoue en ignorer l'existence aussi je suis allé me renseigner et le beauté du code m'a donné envie de le diffuser, avec l'autorisation explicite de l'auteur ne vous en inquiétez pas.
Je ne vais pas vous faire l'affront d'expliquer les règles du jeu et je vous laisse aller sur la toile vous éduquer le cas échéant.
Tout ce qui suit (en italique) est ce que m'a expliqué l'auteur.
Si ce n'est pas suffisant pour jouer utilisez le formulaire de CONTACT et j'irai chercher les informations.
Les seules touches actives sont sur le pavé numérique
- la touche 8 (up) vers le haut,
- la touche 4 (left) à gauche,
- la touche 6 (right) à droite,
- la touche 2 (down) vers le bas.
En appuyant sur l'une de ces touches, toutes les tuiles présentes vont se déplacer dans la direction choisie s'il y a de la place de libre et si elle rencontre une autre tuile de la même valeur, elle va s'additionner.
Imaginons qu'une tuile de valeur 4 apparaisse au même endroit que la précédente.
Si tu appuies sur touche 8 la tuile va se déplacer aussi vers le bord du haut et comme elles ont la même valeur, cela va former une SEULE tuile de valeur 8.
Si ça avait une tuile de valeur 2 elle se serait collée juste en dessous de la tuile de valeur 4.
Si on utilise un portable sans pavé numérique, il faudra utiliser les chiffres du clavier alpha-numérique (moins pratiques) ou reprogrammer les touches dans le code pour en choisir d'autres...
Le jeu est un peu plus difficile que l'original car cet algorithme peut cumuler plusieurs additions en une seule fois, je m'explique:
Tu as par exemple quatre tuiles de valeur 2 dans une même colonne, si tu appuies sur 8 ou 2 cela va donner directement une tuile de valeur 8 en haut ou en bas, alors qu'avec le vrai jeu cela donnerait d'abord deux tuiles de valeur 4 et si tu rappuies sur la même touche, une tuile de valeur 8.
Donc ça peut laisser plus de stratégie dans le déplacement des tuiles.
Je gagne moins souvent avec mon jeu qu'avec le jeu original.
La tactique (au bout d'un moment) est d'arriver à garder une tuile de grande valeur dans un coin sans qu'elle puisse se déplacer et de faire monter sa valeur, donc d'avoir des tuiles de valeurs importante de valeur décroissante autour de celle ci.
Mais bon vous allez expérimenter.
;;game2048.lsp ;| Programmme écrit pas Bruno Valsecchi en décembre 2017 |; (defun randomize (v1 v2 /) (if (not v_sd) (setq v_sd (getvar "DATE")) ) ;_ Fin de if (setq v_sd (rem (+ (* 25173 v_sd) 13849) 65536)) (+ (* (/ v_sd 65536) (- (max v1 v2) (min v1 v2))) (min v1 v2) ) ;_ Fin de + ) ;_ Fin de defun (defun vl-position-multi (el l / n l_id l_n) (setq n 0 l_id (mapcar '(lambda (x) (equal x el)) l) ) ;_ Fin de setq (repeat (length l_id) (if (car l_id) (setq l_n (cons n l_n)) ) ;_ Fin de if (setq n (1+ n) l_id (cdr l_id) ) ;_ Fin de setq ) ;_ Fin de repeat (reverse l_n) ) ;_ Fin de defun (defun draw_map (statut_map / lm_col lt_col tmp lx ly dxf_m dxf_t x y) (setq lm_col '((0 . 252) (2 . 255) (4 . 53) (8 . 31) (16 . 30) (32 . 20) (64 . 22) (128 . 42) (256 . 52) (512 . 40) (1024 . 32) (2048 . 2) ) ) ;_ Fin de setq (setq lt_col '((0 . 252) (2 . 250) (4 . 250) (8 . 255) (16 . 255) (32 . 255) (64 . 255) (128 . 255) (256 . 255) (512 . 255) (1024 . 255) (2048 . 1) ) ) ;_ Fin de setq (setq tmp map) (setq lx (mapcar 'car tmp) ly (mapcar 'cdr tmp) ) ;_ Fin de setq (foreach dxf_mask lst_mask (setq dxf_m (entget (cdr dxf_mask))) (mapcar '(lambda (xi yi / x y) (setq x xi y yi ) ;_ Fin de setq (entmod (subst (cons 10 (list (cdr x) (car x) 0)) (assoc 10 dxf_m) dxf_m ) ;_ Fin de subst ) ;_ Fin de entmod (entmod (subst (cons 11 (list (1+ (cdr x)) (car x) 0)) (assoc 11 dxf_m) dxf_m ) ;_ Fin de subst ) ;_ Fin de entmod (entmod (subst (cons 12 (list (cdr x) (1+ (car x)) 0)) (assoc 12 dxf_m) dxf_m ) ;_ Fin de subst ) ;_ Fin de entmod (entmod (subst (cons 13 (list (1+ (cdr x)) (1+ (car x)) 0)) (assoc 13 dxf_m) dxf_m ) ;_ Fin de subst ) ;_ Fin de entmod (entmod (subst (cons 62 (cdr (assoc y lm_col))) (assoc 62 dxf_m) dxf_m ) ;_ Fin de subst ) ;_ Fin de entmod ) ;_ Fin de lambda (list (car lx)) (list (car ly)) ) ;_ Fin de mapcar (setq lx (cdr lx) ly (cdr ly) ) ;_ Fin de setq ) ;_ Fin de foreach (setq lx (mapcar 'car tmp) ly (mapcar 'cdr tmp) ) ;_ Fin de setq (foreach dxf_text lst_text (setq dxf_t (entget (cdr dxf_text))) (mapcar '(lambda (x y / x y) (entmod (subst (cons 11 (list (+ 0.5 (cdr x)) (+ 0.5 (car x)) 0)) (assoc 11 dxf_t) dxf_t ) ;_ Fin de subst ) ;_ Fin de entmod (entmod (subst (cons 1 (itoa y)) (assoc 1 dxf_t) (subst (cons 62 (cdr (assoc y lt_col))) (assoc 62 dxf_t) dxf_t ) ;_ Fin de subst ) ;_ Fin de subst ) ;_ Fin de entmod ) ;_ Fin de lambda (list (car lx)) (list (car ly)) ) ;_ Fin de mapcar (command "_.DRAWORDER" (cdr dxf_text) "" "_Front") (setq lx (cdr lx) ly (cdr ly) ) ;_ Fin de setq ) ;_ Fin de foreach (entmod (subst (cons 1 (itoa counter)) (assoc 1 (entget ent_count)) (entget ent_count) ) ;_ Fin de subst ) ;_ Fin de entmod ) ;_ Fin de defun (defun evaluate_push (l count / l) (setq l (reverse (vl-remove 0 l))) (if (cdr l) (cond ((and (eq (car l) (cadr l)) (<= (+ (car l) (cadr l)) count)) (setq counter (+ counter (car l) (cadr l))) (evaluate_push (reverse (cons (+ (car l) (cadr l)) (cddr l))) count ) ;_ Fin de evaluate_push ) (T (evaluate_push (reverse (cdr l)) count) (setq nwl (cons (car l) nwl)) ) ) ;_ Fin de cond (setq nwl (cons (car l) nwl)) ) ;_ Fin de if (reverse (if (car nwl) nwl '(0) ) ;_ Fin de if ) ;_ Fin de reverse ) ;_ Fin de defun ;|Fonction qui va pousser les nombres dans le sens voulu (Haut Bas Droit Gauche) évaluer éventuellement la somme fonction (evaluate_push) et mettre à jour la matrice |; (defun push (k / lst tmp nwl) (setq map-n map) (cond ((eq k 50) (setq lst '("C-U3" "C-U2" "C-U1" "C-U0")) ) ((eq k 52) (setq lst '("R-R0" "R-R1" "R-R2" "R-R3")) ) ((eq k 54) (setq lst '("R-L3" "R-L2" "R-L1" "R-L0")) ) ((eq k 56) (setq lst '("C-D0" "C-D1" "C-D2" "C-D3")) ) ) ;_ Fin de cond (foreach n lst (setq tmp (mapcar 'cdr (mapcar '(lambda (x) (assoc x map)) (eval (read n))) ) ;_ Fin de mapcar nwl nil ) ;_ Fin de setq (setq nwl (evaluate_push tmp (* (if (member (apply 'max tmp) (cdr (member (apply 'max tmp) tmp)) ) ;_ Fin de member 2 1 ) ;_ Fin de if (apply 'max tmp) ) ;_ Fin de * ) ;_ Fin de evaluate_push ) ;_ Fin de setq (if (not (eq (length (vl-remove 0 nwl)) 4)) (progn (repeat (- (length tmp) (length (setq nwl (vl-remove 0 nwl)))) (setq nwl (cons 0 nwl)) ) ;_ Fin de repeat nwl ) ;_ Fin de progn nwl ) ;_ Fin de if (setq tmp (mapcar '(lambda (x) (assoc x map)) (eval (read n)))) (foreach n (mapcar '(lambda (x y) (cons x y)) (mapcar 'car (mapcar '(lambda (x) (assoc x map)) (eval (read n))) ) ;_ Fin de mapcar nwl ) ;_ Fin de mapcar (setq map (subst n (assoc (car n) map) map)) ) ;_ Fin de foreach ) ;_ Fin de foreach ) ;_ Fin de defun (defun c:Game2048 (/ v_sd mat_game map lst_mask lst_text nw_pos key before after win loose counter num_win ) ;| Création des variables: comprendre R pour Row (Rangée) et C pour Column (Colonne) L pour Left (Gauche) et R pour Rigth (Droit) U por Up (Haut) et D pour Down (Bas) Celle-ci sont mise à vide (nil) pour débuter le jeu ou pour recommencer une nouvelle partie |; (foreach n '("R-L0" "R-L1" "R-L2" "R-L3" "R-R0" "R-R1" "R-R2" "R-R3") (set (read n) nil) ) ;_ Fin de foreach (foreach n '("C-U0" "C-U1" "C-U2" "C-U3" "C-D0" "C-D1" "C-D2" "C-D3") (set (read n) nil) ) ;_ Fin de foreach ;| ;Construction de la matrice du jeu par paire pointée, mise à zéro du compteur et déclaration du nombre gagnant. |; (setq mat_game '( (3 . 0) (3 . 1) (3 . 2) (3 . 3) (2 . 0) (2 . 1) (2 . 2) (2 . 3) (1 . 0) (1 . 1) (1 . 2) (1 . 3) (0 . 0) (0 . 1) (0 . 2) (0 . 3) ) counter 0 num_win 2048 ) ;_ Fin de setq ;Initialisation des variables sur la matrice de jeu (mapcar '(lambda (x y) (set (read (strcat "R-R" (itoa y))) (reverse x) ) ;_ Fin de set ) ;_ Fin de lambda (mapcar '(lambda (x y) (foreach n x (set (read (strcat "R-L" (itoa y))) (cons (nth n mat_game) (eval (read (strcat "R-L" (itoa y)))) ) ;_ Fin de cons ) ;_ Fin de set ) ;_ Fin de foreach ) ;_ Fin de lambda (mapcar '(lambda (x) (vl-position-multi x (mapcar 'car mat_game)) ) ;_ Fin de lambda '(0 1 2 3) ) ;_ Fin de mapcar '(0 1 2 3) ) ;_ Fin de mapcar '(0 1 2 3) ) ;_ Fin de mapcar (mapcar '(lambda (x y) (set (read (strcat "C-D" (itoa y))) (reverse x) ) ;_ Fin de set ) ;_ Fin de lambda (mapcar '(lambda (x y) (foreach n x (set (read (strcat "C-U" (itoa y))) (cons (nth n mat_game) (eval (read (strcat "C-U" (itoa y)))) ) ;_ Fin de cons ) ;_ Fin de set ) ;_ Fin de foreach ) ;_ Fin de lambda (mapcar '(lambda (x) (vl-position-multi x (mapcar 'cdr mat_game)) ) ;_ Fin de lambda '(0 1 2 3) ) ;_ Fin de mapcar '(0 1 2 3) ) ;_ Fin de mapcar '(0 1 2 3) ) ;_ Fin de mapcar ;Mise à zéro du plateau de jeu (setq map (mapcar '(lambda (n /) (cons n 0)) mat_game)) ;Construction graphique du plateau de jeu à l'écran avec la matrice (map) initialisée (entmake '( (0 . "STYLE") (100 . "AcDbSymbolTableRecord") (100 . "AcDbTextStyleTableRecord") (2 . "2048") (70 . 0) (40 . 0.0) (41 . 1.0) (50 . 0.0) (71 . 0) (42 . 0.5) (3 . "arial.ttf") (4 . "") ) ) ;_ Fin de entmake (setvar "TEXTSTYLE" "2048") (setvar "CMDECHO" 0) (command "_.zoom" "_window" "_none" '(0 0) "_none" '(4 4)) (foreach n map (entmake (list '(0 . "SOLID") '(100 . "AcDbEntity") '(67 . 0) '(410 . "Model") '(8 . "0") '(62 . 252) '(100 . "AcDbTrace") (cons 10 (list (cdar n) (caar n) 0)) (cons 11 (list (1+ (cdar n)) (caar n) 0)) (cons 12 (list (cdar n) (1+ (caar n)) 0)) (cons 13 (list (1+ (cdar n)) (1+ (caar n)) 0)) '(39 . 0.0) '(210 0.0 0.0 1.0) ) ;_ Fin de list ) ;_ Fin de entmake (setq lst_mask (cons (assoc -1 (entget (entlast))) lst_mask)) (entmake (list '(0 . "TEXT") '(100 . "AcDbEntity") '(67 . 0) '(410 . "Model") '(8 . "0") '(62 . 252) '(100 . "AcDbText") (cons 10 (list (+ (cdar n) 0.19423602) (+ (caar n) 0.25) 0)) '(40 . 0.5) '(1 . "0") '(50 . 0.0) '(41 . 0.65) '(51 . 0.0) '(7 . "2048") '(71 . 0) '(72 . 1) (cons 11 (list (+ (cdar n) 0.5) (+ (caar n) 0.5) 0)) '(210 0.0 0.0 1.0) '(100 . "AcDbText") '(73 . 2) ) ;_ Fin de list ) ;_ Fin de entmake (setq lst_text (cons (assoc -1 (entget (entlast))) lst_text)) ) ;_ Fin de foreach ;|création graphique du texte qui représentera le nombre aléatoire (2 ou 4) qui apparaitra sur le plateau |; (entmake (list '(0 . "TEXT") '(100 . "AcDbEntity") '(67 . 0) '(410 . "Model") '(8 . "0") '(62 . 256) '(100 . "AcDbText") '(10 -2.0 2.0 0.0) '(40 . 0.5) '(1 . "0") '(50 . 0.0) '(41 . 0.65) '(51 . 0.0) '(7 . "2048") '(210 0.0 0.0 1.0) '(100 . "AcDbText")) ;_ Fin de list ) ;_ Fin de entmake ;mémorisation de cette entité (setq ent_count (entlast)) ;Premier placement aléatoire sur le plateau du nombre aléatoire 1 ou 2 (setq nw_pos (cons (cons (read (rtos (randomize 0 3) 2 0)) (read (rtos (randomize 0 3) 2 0)) ) ;_ Fin de cons (* 2 (read (rtos (randomize 1 2) 2 0))) ) ;_ Fin de cons ) ;_ Fin de setq ;Mise à jour de la matrice avec ce nouveau placement (if (or (zerop (cdr (assoc (car nw_pos) map))) (eq (cdr (assoc (car nw_pos) map)) (cdr nw_pos)) ) ;_ Fin de or (setq map (subst (cons (car nw_pos) (+ (cdr nw_pos) (cdr (assoc (car nw_pos) map))) ) ;_ Fin de cons (assoc (car nw_pos) map) map ) ;_ Fin de subst ) ;_ Fin de setq ) ;_ Fin de if ;Mise à jour graphique de la matrice (draw_map map) ;| Boucle avec tant que c'est pas perdu on lit en condition la saisie clavier faite sur les touches du pavé numérique déclarées. |; (while (and (setq key (grread T 4 0)) (not loose)) ;|Si ces conditions sont bonnes, on génère une position aléatoire et un nombre aléatoire (2 ou 4) et on met à jour la matrice de jeu. |; (if (member (cadr key) '(50 52 54 56)) (progn (setq before (mapcar 'cdr map)) ;| Fonction qui va cumuler les nombres identiques dans une celulle adjacente de la matrice de jeu et mettre à jour celle-ci |; (push (cadr key)) (if (member num_win (mapcar 'cdr map)) (progn (setq win T) (alert "GAGNE") (setq num_win 4096)) ) ;_ Fin de if (setq after (mapcar 'cdr map)) ;|On vérifie que la matrice est bien différente du coup précédent, donc que la matrice n'est pas pleine et que c'est perdu |; (cond ((not (equal before after)) (while (not (zerop (cdr (assoc (car (setq nw_pos (cons (cons (read (rtos (randomize 0 3) 2 0)) (read (rtos (randomize 0 3) 2 0)) ) ;_ Fin de cons (* 2 (read (rtos (randomize 1 2) 2 0))) ) ;_ Fin de cons ) ;_ Fin de setq ) ;_ Fin de car map ) ;_ Fin de assoc ) ;_ Fin de cdr ) ;_ Fin de zerop ) ;_ Fin de not ) ;_ Fin de while ;|On vérifie que la nouvelle position aléatoire occupée dans la matrice est bien vierge (à Zéro) pour mettre à jour celle-ci |; (if (or (zerop (cdr (assoc (car nw_pos) map))) (eq (cdr (assoc (car nw_pos) map)) (cdr nw_pos)) ) ;_ Fin de or (setq map (subst (cons (car nw_pos) (+ (cdr nw_pos) (cdr (assoc (car nw_pos) map))) ) ;_ Fin de cons (assoc (car nw_pos) map) map ) ;_ Fin de subst ) ;_ Fin de setq ) ;_ Fin de if (draw_map map) ) (T (if (not (member 0 (mapcar 'cdr map))) (setq loose T) ) ;_ Fin de if ) ) ;_ Fin de cond ) ;_ Fin de progn ) ;_ Fin de if ) ;_ Fin de while (if (not win) (alert "PERDU") ) ;_ Fin de if (command "_.ERASE" "_All" "") (setvar "TEXTSTYLE" "Standard") (setvar "CMDECHO" 1) (foreach n '("R-L0" "R-L1" "R-L2" "R-L3" "R-R0" "R-R1" "R-R2" "R-R3") (set (read n) nil) ) ;_ Fin de foreach (foreach n '("C-U0" "C-U1" "C-U2" "C-U3" "C-D0" "C-D1" "C-D2" "C-D3") (set (read n) nil) ) ;_ Fin de foreach (prin1) ) ;_ Fin de defun
