Le « Plus / Moins » le plus horrible du siècle !

a marqué ce sujet comme résolu.

Je reviens avec un code en Java 8 qui m'a été inspiré par un code que j'ai croisé ailleurs. Le concept, c'est que pour faire un traitement en fonction d'une valeur, on crée un lien valeur --> méthode de traitement (ici avec une Map et des lambda).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package info.kisai.plusmoins;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;

public class PlusMoins {

    private interface PossibleValue {
        void guess(int nbAttempts);
    }

    private Map<Integer, PossibleValue> possibleValues = new HashMap<>();

    public static void main(String[] args) {
        new PlusMoins().run();
    }

    private void run() {
        System.out.println("Devinez le nombre entre 0 et 99 en le moins d'essais possible");

        Random random = new Random();
        int answer = random.nextInt(100);

        for (int i = 0; i < answer; i++) {
            possibleValues.put(i, nbAttempts -> {
                System.out.println("C'est plus !");
                askAnswer(nbAttempts + 1);
            });
        }
        possibleValues.put(answer, nbAttempts -> System.out.println("Vous avez gagné en " + nbAttempts + " coups !"));
        for (int i = answer + 1; i < 100; i++) {
            possibleValues.put(i, nbAttempts -> {
                System.out.println("C'est moins !");
                askAnswer(nbAttempts + 1);
            });
        }
        askAnswer(1);
    }

    private void askAnswer(int nbAttempts) {
        System.out.println("Coup n°" + nbAttempts + " :");
        try (Scanner in = new Scanner(System.in)) {
            int guess = in.nextInt();
            possibleValues.get(guess).guess(nbAttempts);
        }
    }
}

Problèmes de ce code :

  • Utilisation de cette technique là où elle n'est clairement pas adaptée.
  • On re-crée les lambdas à chaque entrée de la Map alors qu'on pourrait avoir un seul objet pour les traitements « plus » et un autre pour les « moins ».
  • Aucun contrôle d'entrée, mettre autre chose qu'un nombre entre 0 et 99 crashera le programme.
  • Récursion cachée : askAnswer() appelle une implémentation de PossibleValue.guess(), et toutes les implémentations qui ne gagnent pas appellent askAnswer(). Donc, selon l'implémentation de la JVM, il risque d'y avoir un problème à plus ou moins long terme…

eh c'est l'idée du code python que j'ai posté en début de topic !

artragis

C'est un pattern ultra courant en Python parce que c'est la seule façon pythonique (i.e. sexy et flexible) qu'on ait d'implémenter un switch. Sauf qu'en Python on fait plutôt ça en créant un décorateur :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Handler:
    callbacks = {}

    @classmethod
    def register(cls, key):
        'Register a callback'
        def wrap(func):
            cls.callbacks[key] = func
            return func
        return wrap

    @classmethod
    def process(cls, data):
        cls.callbacks[data.type](cls, data)

@Handler.register('spam')
def process_spam(handler, data):
    # ...

@Handler.register('eggs')
def process_eggs(handler, data):
    # ...

@Handler.register('bacon')
def process_bacon(handler, data):
    # ...

C'est puissant ce truc, mais comme le montre SpaceFox dans son exemple, faut pas l'utiliser à tort et à travers.

+0 -0

Nouvelle bizarrerie à base de descripteurs :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import random

class Counter:
    def __init__(self, n):
        self._max = n
        self._i = 0
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self._i
    def __set__(self, instance, value):
        if instance is None:
            return
        if value > self._max:
            raise StopIteration()
        else:
            self._i = value

class Oracle:
    counter = Counter(10)
    def __init__(self):
        self._guess = None
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self._guess == instance.secret
    def __set__(self, instance, value):
        if instance is None:
            return
        try:
            self.counter += 1
        except:
            print("desole, vous avez perdu")
            raise
        if value < instance.secret:
            print("c'est plus")
        elif value > instance.secret:
            print("c'est moins")
        else:
            print("bravo, vous avez trouve")
        self._guess = value

class PlusOuMoins:
    guess = Oracle()
    def __init__(self):
        self.secret = random.randint(0, 100)
    def __iter__(self):
        while not self.guess:
            self.guess = int(input('Entrez un nombre: '))
            yield
    def run(self):
        for fail in self:
            pass

game = PlusOuMoins()
game.run()
  • Le compteur (qui se trouve imbriqué dans l'oracle) lance une StopIteration lorsqu'il arrive au bout.
  • L'oracle sert à valider les essais de l'utilisateur (les valeurs du __set__ et du __get__ sont d'ailleurs différentes), et à afficher les messages du jeu.
  • La classe PlusOuMoins utilise le protocole d'itération pour le contrôle du jeu (cf. __iter__ et run

Bon, je ne maîtrise pas le Pascal au bout des doigts mais voici ce que j'ai fait :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
program plusoumoins;

type
    TNombre = 0..100; {TNombre est un intervale de [0;100]}
    TConditions = (Gagne, Perds); {enumération}
    TFonctionCondition = function(a, b : TNombre) : TConditions;
    TLogiqueJeu = function(cond : TConditions) : boolean;

var nbrAlea, nbrEntre : TNombre;

function ConditionVictore(nbrEntre, nbrAlea : TNombre) : TConditions;
begin
    if nbrEntre < nbrAlea then
    begin
        writeln('Plus grand.');
        ConditionVictore := TConditions.Perds
    end
    else if nbrEntre > nbrAlea then
    begin
        writeln('Plus petit');
        ConditionVictore := TConditions.Perds
    end
    else ConditionVictore := TConditions.Gagne;
end;

function Jeu(condition : TConditions) : boolean;
begin
    if condition = TConditions.Gagne then
        Jeu := true
    else
    begin
        writeln(nbrAlea);
        readln(nbrEntre);
        Jeu := false
    end
end;

procedure LancerJeu(nbrMax : TNombre);
    function BoucleJeu(nbrAlea : TNombre ; Logique : TLogiqueJeu) : boolean;
    begin
        repeat
            BoucleJeu := Logique(ConditionVictore(nbrEntre, nbrAlea));
        until BoucleJeu = true
    end;
begin
    randomize;
    nbrAlea := Random(High(nbrMax));
    BoucleJeu(nbrAlea, @Jeu)
end;

begin
    LancerJeu(High(TNombre)); {La plus grande valeur de l'intervale TNombre}
    writeln('Tu as gagné !')
end.

Ici je me venge de l'abus de types (tout ce qui commence pas 'T') que je retrouve souvent dans certains code, et même dans celui du compilateur (FreePascal 2.6.2), ou encore le fait de découper le code en trop de petites fonctions ; exemple :

1
2
DWord    = LongWord;
Cardinal = LongWord;

C'est bien joli mais c'est pas forcément plus clair.

Donc ici j'ai essayé de faire un code modulable grâce à l'utilisation de types. Je suis un peu déçu parceque au final, l'idée n'est pas si mauvaise. Mais cela reste tout de même peu lisible.

  • Déclaration de quelques types :
    • Un intervale ;
    • Une énumération ;
    • Une fonction qui renvoie l'énumération plus haute et qui prends deux arguments ;
    • Une fonction qui renvoie un booléen et qui prend une valeur de l'énumération.
  • ConditionVictore: fonction qui regarde si le joueur a gagné ou non ;
  • Jeu : Logique de jeu, qui fait jouer le personnage en fonctions de ConditionVictoire ;
  • LancerJeu : Procédure qui initialise tout
    • BoucleJeu : Et oui, on peut imbriquer des procédures et des fonctions. Là, pas besoin d'expliquer c'est simple ;
  • On lance le jeu avec la plus grande valeur de l'intervalle.

Et c'est tout ^^ !

Bon, c'est pas si horrible que ça :( . Je vais essayer avec des classes et des types génériques. L'utilisation de dll est autorisée ? (Parceque j'ai une jolie surprise ;) .)

salut,

du ±, comme c’est original. :-° j’avais commis ça lors d’un atelier sur le forum C du Site du Zéro (cf. ici pour le contexte et quelques explications). mon objectif n’était pas le même, je voulais faire le truc le plus lourdingue et kikoo possible (voir le module Extra) ; mais je trouve rigolo de le poster ici, et il y a quand même quelques cradeurs :

  • dépendance inutile sur la bibliothèque SDL (utilisée seulement pour faire des chronomètres et des threads…)
  • utilisation intentionnelle d’overflows arithmétiques (cf. _log2 dans Utils.c)
  • illustration de la laideur du C pour gérer plus que l’ASCII (wchar_t…)
  • c’est… long… (on dirait du Java™)

et certainement d’autres trucs qui ont échappé à ma relecture rapide.

je ferai peut-être quelque chose pour cet atelier si j’en trouve le temps :-)

+2 -0

Bonjour.

Je viens juste de découvrir cet atelier et je viens de terminer mon code Rust.

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#![feature(asm, braced_empty_structs, core_slice_ext, lang_items, libc, no_std, start)]
#![no_std]

extern crate libc;

use core::slice::from_raw_parts_mut;
use libc::{ETIME, atoi, calloc, c_char, c_void, fflush, fgets, fputs, free, rand, srand, strlen};
use libc::types::common::c95::FILE;

extern "C" {
    static stdin: *mut FILE;
    static stdout: *mut FILE;
}

static ENTREZ: [i8; 10] = [69, 110, 116, 114, 101, 122, 58, 32, 10, 0];
static PLUS: [i8; 14] = [67, 39, 101, 115, 116, 32, 112, 108, 117, 115, 32, 33, 10, 0];
static MOINS: [i8; 15] = [67, 39, 101, 115, 116, 32, 109, 111, 105, 110, 115, 32, 33, 10, 0];

static mut input_number: i32 = 0;

fn read() -> *const c_char {
    const MAX_SIZE: usize = 10;
    unsafe {
        // Useless usage of the C standard library.
        let mut buffer = calloc(1, MAX_SIZE as u64) as *mut i8;
        fgets(buffer, MAX_SIZE as i32, stdin)
    }
}

fn print(string: *const c_char) {
    unsafe {
        fputs(string, stdout);
        let mut slice: &mut [u8] = from_raw_parts_mut(string as *mut u8, strlen(string) as usize);
        let mut needs_flushing = false;
        // Useless use of mutable iterator.
        for character in slice.iter_mut() {
            if(*character as char == '\0') {
                needs_flushing = true;
            }
        }
        if(needs_flushing) {
            fflush(stdout);
        }
    }
}

struct String {
    value: *mut i8,
}

impl String {
    fn new(chars: *const i8) -> String {
        String {
            value: chars as *mut i8,
        }
    }

    // Moves the value instead of borrowing it.
    fn as_ptr(self) -> *const i8 {
        self.value
    }

    fn delete(self) {
        unsafe {
            free(self.value as *mut c_void);
        }
    }

    fn to_int(self) -> i32 {
        unsafe {
            atoi(self.value) as i32
        }
    }
}

impl Clone for String {
    fn clone(&self) -> String {
        String {
            // Only copy the pointer, does not copy the referenced values.
            value: self.value
        }
    }
}

// Use of an empty struct for no reason.
struct Random {}

// Random number generator.
impl Random {
    fn new() -> Random {
        unsafe {
            // Use of a fake time.
            srand(ETIME as u32);
        }
        Random {}
    }

    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    fn random_int(self, max: i32) -> i32 {
        unsafe {
            let mut number = rand();
            let mut result: i32;
            // Use of inline assembly because the modulo operator gives a compile time error.
            asm!("
            mov eax, $0
            cdq
            idiv ecx
            mov eax, edx
            "
            : "={eax}"(result)
            : "0"(number) "{ecx}"(max)
            : "{edx}"
            : "intel");
            result
        }
    }
}

// Use of start instead of main.
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    let mut random = Random::new();
    let mut random_number = random.random_int(100);
    // Useless use of parentheses.
    while(random_number != unsafe { input_number }) {
        // Need to create a new String each time we print because String methods moves the value.
        let mut string = String::new(ENTREZ.as_ptr());
        print(string.as_ptr());
        let mut line = String::new(read());
        unsafe {
            input_number = line.clone().to_int();
        }
        if(random_number < unsafe { input_number }) {
            let mut string = String::new(MOINS.as_ptr());
            print(string.as_ptr());
        }
        else if(random_number > unsafe { input_number }) {
            let mut string = String::new(PLUS.as_ptr());
            print(string.as_ptr());
        }
        line.delete();
    }
    0
}

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

Pour ceux qui ne sont pas familiers avec Rust, il y a une séparation du code qui est sécuritaire et celui qui ne l’est pas (variable muable globale, pointeur brut, fonction étrangère, …).

Le but de mon code est d’avoir quelque chose d’assez proche du C (manipulation de pointeurs et allocations dynamiques) ce que l’on essaie d’éviter en Rust pour de simples programmes utilisateurs comme celui-ci.

Explications

  • Je n’utilise pas la bibliothèque standard de Rust (#[feature(no_std)]). J’utilise plutôt directement la bibliothèque standard du C.
  • J’utilise la fonction start au lieu de main.
  • J’utilise une variable globale muable (non sécuritaire (unsafe) en Rust).
  • J’utilise des tableaux d’entiers au lieu de litéraux de chaînes de caractères.
  • J’utilise des variables muables quasiment tout le temps alors que c’est souvent inutile.
  • Je fais l’écriture et la lecture dans la console en utilisant fputs et fgets avec stdout et stdin.
  • Je gère manuellement la mémoire (rarement nécessaire en Rust grâce à l’appartenance (ownership) et au type Box).
  • J’utilise un itérateur muable quand un immuable ferait l’affaire.
  • Je place des parenthèses autour des expressions pour les boucles et les conditions (ce n’est pas nécessaire en Rust).
  • Les méthodes de la structure String déplace (sémantique de déplacement) au lieu d’emprunter (référence) la String en question (self étant l’équivalent de this dans certains langages) ce qui fait que je ne peux plus réutiliser l’objet suite à un appel de méthode qui ne fait qu’un accès à une variable sans la modifier ou la déplacer.
  • J’utilise pleins de conversions inutiles (souvent avec des pointeurs), parfois de *const vers *mut :o .
  • J’appelle plusieurs fonctions non sécuritaires (unsafe) pour rien.
  • J’utilise une constante pour le seed pour l’appel à srand (pas très aléatoire).
  • Mon implémentation de Clone (pour copier une String) ne copie pas le contenu de la chaîne de caractères (elle ne copie que le pointeur).
  • J’utilise une structure vide Random pour rien.
  • J’utilise de l’assembleur dans le code Rust parce que l’utilisation de l’opérateur module (%) me donne une erreur de compilation1.
  • J’abuse de la méthode as_ptr() (converti un truc en pointeur brut).
  • Je dois copier (clone) ma chaîne de caractères (fausse copie :p ) pour pouvoir appeler deux méthodes (to_int() et delete()) dessus.

Je vais essayer d’améliorer ( :D ) ce code au fur et à mesure de ma lecture du Rustonomicon.


  1. L’erreur est référence indéfinie vers « rust_begin_unwind ». Au fait, est-ce que quelqu’un sait pourquoi j’ai cette erreur et ce qu’elle signifie ? 

+0 -0

Joli!

L’erreur est référence indéfinie vers « rust_begin_unwind ». Au fait, est-ce que quelqu’un sait pourquoi j’ai cette erreur et ce qu’elle signifie ?

Que le linker ne trouve pas la fonction rust_begin_unwind. Cette fonction doit être liée aux panic!, où il faut "dépiler" la pile d'appels. Je ne vois pas pourquoi % peut paniquer, mais il doit être à l'origine de l'appel de cette fonction. Et je pense que rust_begin_unwind est défini dans la lib standard, c'est pour ça que rustc ne la trouve pas.

+0 -0

@SpaceFox : j'ai peut-être parcouru ton code un peu trop rapidement mais il me semble manquer un élément essentiel à toute sur-ingénierie qui se respecte : la définition d'une flopée d'exceptions maison aux noms tarabiscotés qui finissent presque par remplacer le moindre test conditionnel.

On est à la limite (ténue) entre abus de bonne pratique et (très) mauvaise pratique donc c'est quasiment hors scope. Mais ça pourrait presque le faire. Un p'tit OutOfGameRangeException avec un message i18nisé, et bien évidemment pour la fonctionnalité manquante, le NotImplementedYetException.

Il manque aussi la valise de tests unitaires mal pensés (avec quelques faux-positifs en @Ignore, bien entendu), c-a-d qui cassent au moindre changement.

Du multi-threading pour aller sauvegarder dans les fichiers me paraît également essentiel. Avec une ou deux race conditions indémerdables, cela va sans le dire.

Bon boulot en tout cas. Félicitations.

+7 -0

Trop top ! Je viens de découvrir ce topic ! xD Voilà ma participation en c !

1
2
3
4
5
6
7
#include/*    /$$           */<stdlib.h>
#include/*   | $$           */<stdio.h>
#include/* /$$$$$$$$ /$$$$$$*/<time.h>
#define /*|__  $$__/|______/*/p putchar
#define /*   | $$           */s scanf
#define /*   |__/           */r rand
c;i;t;main(a,b,d)char**b;char**d;{srand(time(0));for(;;){c=c&&!**d?**d=0,s("%d",&i),c-i?p((c-i<0)[*b]),p(!!c<<3|!!c<<1),main(a,b,d):(t=~i-c),0:((c*538%36)[*b]=!!c<<c|00053,**d=0,*(*b+!!a)=~c&0x2d+(~**b&(~!a<<8)*c),c[b][c[b][c+1]-**b]=10,r()%0x64);if(!p-t||c==!b)break;else main(a,b,d);}}

Des explications… ? xD

Bonjour je suis nouveau sur le forum et j'ai été conquis par l'idée à la fois drôle et pédagogique. Voici mon code en VB.NET (langage pas encore proposé) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
' Importation de System.Threading
Imports System.Threading

' Module 1
Module Module1

    ' Fonction principale
    Sub Main()

        ' Déclaration de 2 variables :
        Static N, X

        ' Affichage d'un titre accrocheur :
        Console.WriteLine("____,,,...----°°°° LE JE DU + OU DU MOIN (V1.37.896.21b) °°°°----...,,,____")

        Thread.Sleep(2800)

        Console.Clear()

        ' Affichage d'un chargement, ça fait plus pro :
        For i = 0 To 100000

            Console.WriteLine("Chargemand d'kernel de l'aplicassion an cour : " & (i / 1000) & " %")

            Select Case ((i Mod 3))
                Case 0
                    Console.WriteLine("    |")
                Case 1
                    Console.WriteLine("    /")
                Case 2
                    Console.WriteLine("    --")
            End Select

            Console.Clear()
        Next

        ' RESTE DU CODE :

        Thread.Sleep(1000)

        Console.WriteLine("========== LOADING KERNEL TERMINATED | Chargemand de l'interfasse grafik...")

        Thread.Sleep(2700)

        Console.Clear()

        Console.WriteLine("Tapée un nonbre de 0 a 99 !")

        Static D = Integer.Parse(Date.Now.Millisecond.ToString().Substring(1).ToString()).ToString()
        X = D
        N = -1

        While (AssignayValeure(N, Integer.Parse(Console.ReadLine())) <> X)

            If Not N >= 0 Or Not N <= 99 Then
                Console.WriteLine("Le nonbre tapez n'ai pa compris antres 0 ai 99, recommansser a tapait :")
            Else
                Console.Clear()
                If N < X Then
                    Console.WriteLine("Plu gran !")
                    Console.WriteLine("Tapée un nonbre de 0 a 99 !")
                End If

                If N > X Then
                    Console.WriteLine("Plu pti !")
                    Console.WriteLine("Tapée un nonbre de 0 a 99 !")
                End If
            End If
        End While

        Console.Clear()
        Console.WriteLine("Braveaux ! sa va, c ganié !!!")
        Console.ReadKey()

    End Sub

    Public Function AssignayValeure(ByRef DESTINASSION As Object, ByVal VALUE As Object) As Object
        DESTINASSION = VALUE
        Return DESTINASSION
    End Function
End Module

N'hésitez pas à l'essayer, c'est une simple class en mode console.

Explications :

  • Commentaires inutiles puis absence de commentaire

  • Déclaration en Static inutile car les variables ne doivent pas être accédées depuis une autre class

  • Non respect de la norme des nommages variables (écriture en majuscule)

  • Pas de typage

  • Splash screen avec des fioritures inutiles

  • Système de chargement fictif complètement gadget

  • Integer.Parse(Date.Now.Millisecond.ToString().Substring(1).ToString()).ToString() au lieu de simplement faire un rand de 0 à 99

  • Assignation dans le while (via une fonction)

  • Not N >= 0 Or Not N <= 99 au lieu de simplement N < 0 Or N > 99

  • Deux conditions sans utiliser le else, la deuxième est testée même si la première a été réussie

  • Pas de gestion des exceptions (Try/Catch)

  • Orthographe

Hello,

Je déterre un peu, mais je viens de faire une version en Vala.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using GLib;

/* Textes du jeu

Plus
Moins
Gagné

*/

namespace PlusOuMoins {
    public enum Resultat {
        PLUS,
        MOINS,
        GAGNE;

        public string foo () {
            string bar;
            int l = 0;
            if (this == 1) {
                l = 6;
            } else {
                if (this == 0) {
                    l = 5;
                } else {
                    l = 7;
                }
            }
            try {
                FileUtils.get_contents ("plusmoinsmoche.vala", out bar);
            } catch {
                stdout.printf ("Il faut les sources.\n");
            }
            return bar.split ("\n")[l - 1];
        }
    }

    public class MsgManager : Object {

        public string msg_0 { get; set; default = "Bienvenue dans le jeu du plus ou du moins\n";}
        public string msg_1 { get; set; default = "Entre un nombre :\n"; }
        public string msg_2 { get; set; default = "Le nombre doit être compris entre 0 et 99 inclus"; }
        public string msg_3 { get; set; default = "GAGNÉ !!!!!"; }

        public uint8[] get_msg (int i) {
            Value v = Value (typeof (string));
            get_property ("msg-%s".printf (i.to_string ()), ref v);
            return v.get_string ().data;
        }
    }

    public class Jeu : Object {

        Resultat r;

        MsgManager m = (Object.new (typeof (MsgManager)) as MsgManager);

        int i = take_int ()()()()();

        public static void main () {
            stdout.printf ((string)(new Jeu ().m.get_msg (0)));
            Jeu? jeu = null;
            (jeu = (Object.new (typeof (Jeu)) as Jeu)).tour (jeu.tour);
            Process.exit ((int)(42 < (42 * 42)));
        }

        public delegate void Next (owned Next next);

        public void tour (owned Next next) {
            var self = this;
            stdout.printf ((string)self.m.get_msg (1));
            int c = 0;
            stdin.read_line ().scanf ("%d", ref c);
            bool m = c > i,
                 p = c < i,
                 e = c == i,
                 b = c < 0 || c > 99;
            if (m) {
                r = Resultat.MOINS;
            } else {
                if (p) {
                    r = Resultat.PLUS;
                } else {
                    if (e) {
                        r = Resultat.GAGNE;
                    } else {
                        if (b) {
                            stdout.printf ((string)self.m.get_msg (2));
                        }
                    }
                }
            }

            if (r.foo () == "Plus") {
                stdout.printf ("%s", "C'est %s\n".printf ("plus !"));
            } else {
                if (r.foo () == "Moins") {
                    string azerty = (string)(new uint8[] { 109, 111, 105, 110, 115 });
                    StringBuilder w = new StringBuilder ();
                    w.append ("C");
                    w.append ("'");
                    w.append ("est");
                    w.append (" ");
                    w.append (azerty);
                    stdout.printf ("%s !\n", (string)(((string)(w.data)).data));
                } else {
                    string baz = r.foo ();
                    if (!(!(!(!(baz == "Gagné"))))) {
                        stdout.printf ("%s\n", (string)(self.m.get_msg (3)));
                        return;
                    } else {
                        stdout.printf ("Lol, un bug");
                        Process.exit ('\0' + 1);
                    }
                }
            }

            next (self.tour);
        }

        public static Baz1 take_int () {
            return () => {
                return () => {
                    return () => {
                        return () => {
                            int foo = Random.int_range (0, 42);
                            for (int g = 0; g < foo; g++) {
                                Random.set_seed (Random.next_int ());
                            }
                            return (int)Random.int_range (0, 99);
                        };
                    };
                };
            };
        }
    }

    [CCode (has_target = false)]
    public delegate Baz2 Baz1 ();
    [CCode (has_target = false)]
    public delegate Baz3 Baz2 ();
    [CCode (has_target = false)]
    public delegate Baz4 Baz3 ();
    [CCode (has_target = false)]
    public delegate int Baz4 ();
}

Voici la liste des horreurs.

  • Le using en haut du fichier ne sert strictement à rien, puisqu’il est de toute façon là par défaut ;
  • Je nomme mal mes variables ;
  • Pour créer des nouvelles instances d’objets j’utilise Object.new (typeof (Foo)) as Foo, alors qu’on fait normalement new Foo ;
  • J’utilise différents moyens pour stocker les chaînes de caractère de mon programme :
    • J’ai une classe qui a des propriétés contenant certains textes, avec une méthode get_msg qui utilise de la réflexion pour récupérer la valeur de ces propriétés ;
    • Pour obtenir une version textuelle des valeurs de l’énumération Resultat, le programme lis son propre code source dans lequel il y a un commentaire avec les valeurs possibles ;
  • Les namespace et la classe Jeu ne servent strictement à rien ;
  • La méthode pour obtenir un nombre aléatoire retourne un délégué qui retourne lui-même un délégué, qui retourne lui-même un délégué qui retourne un int (je crois).
  • Pour définir la seed du générateur de nombre aléatoire, j’utilise un nombre aléatoire de fois des nombres aléatoires ;
  • La méthode qui correspond à un tour de jeu s’appelle récursivement tant qu’on a pas gagné, grâce à un délégué qu’on lui passe en argument ;
  • Je crée un « alias » de this qui devient self dans la méthode tour ;
  • J’utilise stdout.printf, alors que print fait exactement la même chose ;
  • Je fais pas mal de petits trucs inutiles qui rendent le code compliqué pour rien, entre autres :
    • J’utilise des uint8[] pour stocker du texte ;
    • Plutôt que de simplement écrire 0, je converti une expression booléenne qui est toujours vraie (42 < (42 * 42)) en entier ;
    • !(!(!(!(baz == "Gagné")))).
  • Je ne connais pas les else if, je mets d’autres if/else dans les else ;
  • Je crée une énumération Resultat qui ne sert à rien : une variable de ce type stocke bien le résultat (plus, moins ou gagné) d’un tour, mais je pourrais très bien m’en passer et utiliser directement les conditions à partir desquelles je donne justement une valeur à cette variable.
  • Et sûrement plein d’autres chose que j’ai oublié ;

Bref, je me suis bien amusé ! :D

Et en bonus, un code encore plus horrible, l’équivalent en C de mon programme généré par le compilateur Vala.

+0 -0

Voici une modeste contribution en C++ (ça doit être faisable en C en changeant les fonctions d’input et de random).

Le concept est simple, pourquoi faire soit même ce qu’un autre programme peut faire pour nous? Et si un programme pour générer un nombre aléatoire n’existe pas, créons le nous même… Bref, plutôt que de faire le travail lui même, ce programme code (littéralement) un autre programme qui le fera a sa place. C’est moche, c’est lent, mais ça marche (en tout cas sous Linux avec mon gcc 5.4).

Vous noterez les horribles appels a system et la communication qui se fait via les return de main a grand coup de WEXITSTATUS

Sans plus attendre, le code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <fstream>
#include <iostream>
#include <string>

int get_random_number(int min, int max)
{
    std::ofstream output("get_random_number.cpp");

    output << "#include<random>\n";
    output << "int main(){\n";
    output << "std::random_device rd;\n";
    output << "std::mt19937 gen(rd());\n";
    output << "std::uniform_int_distribution<> dis(" << min << "," << max << ");\n";
    output << "return dis(gen);\n";
    output << "}" << std::endl;

    output.close();

    system("g++ -std=c++11 -o random_gen get_random_number.cpp");
    int ret_value = system("./random_gen");
    system("rm ./random_gen");
    system("rm get_random_number.cpp");

    return WEXITSTATUS(ret_value);
}


int print_message(std::string const &message)
{
    std::ofstream output("print_message.cpp");

    output << "#include<iostream>\n";
    output << "int main(){\n";
    output << "std::cout <<\"" << message << "\"<<std::endl;\n";
    output << "return 0;\n";
    output << "}" << std::endl;

    output.close();

    system("g++ -std=c++11 -o print_message print_message.cpp");
    int ret_value = system("./print_message");
    system("rm ./print_message");
    system("rm print_message.cpp");

    return WEXITSTATUS(ret_value);
}

int get_user_input(std::string const &message)
{
    print_message(message);

    std::ofstream output("get_user_input.cpp");

    output << "#include<iostream>\n";
    output << "int main(){\n";
    output << "int input = 0;\n";
    output << "std::cin >> input;\n";
    output << "return input;\n";
    output << "}" << std::endl;

    output.close();

    system("g++ -std=c++11 -o user_input get_user_input.cpp");
    int ret_value = system("./user_input");
    system("rm ./user_input");
    system("rm get_user_input.cpp");

    return WEXITSTATUS(ret_value);
}

int main()
{  
    bool rejouer = false;

    do
    {
        int number = get_random_number(1, 100);
        print_message("Devinez le nombre mystere (entre 0 et 100)");
        int res = 0;
        do
        {
            res = get_user_input("Votre proposition?");
            if(res > number)
            {
                print_message("Un peu trop haut");
            }
            else if(res < number)
            {
                print_message("Un peu trop bas");
            }
        }
        while(res != number);
        print_message("Bravo!");
        rejouer = get_user_input("Rejouer? (1 pour oui, autre chose pour non") == 1;  
    }
    while(rejouer);

    return 0;
}

Ah oui, en plus du procédé douteux, le code a été fait a l’arrache et risque de faire preuve de mauvaises pratiques… Mais bon…

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte