• # un petit peu plus (de divisions)

    Posté par (site web personnel, Mastodon) . En réponse au journal résoudre "trouve 24". Évalué à 4. Dernière modification le 24 février 2022 à 03:44.

    Wordle est mort. Racheté par le capitalisme et blindé de tackers et de pubs.

    C'est ballot ...parce que, justement dans un lien posté récemment, que l'absence de pisteurs est un des ingrédients du succès.
    https://linuxfr.org/users/gilcot/liens/wordle-is-pretty-damn-smart-in-many-subtle-ways

    J'ai joué un peu puis me suis dis "c'est un boulot pour une machine".

    Ou pas... Ce genre de jeux (le compte est bon) est une façon d'évaluer l'aptitude de calculs mentaux et l'intuition (plutôt la capacité d'estimation) face aux combinaisons de nombres. Évaluer une machine, ou tricher, a peu d'intérêt ici.
    Ceci dit, l'informatique y est utile pour évaluer des conjectures mathématiques ou explorer certains aspects algorithmiquement (notamment tout ce qui touche aux arbres de décision, dont il n'est pas question ici puisqu'on emploie la force brute.) Il me semble d'ailleurs avoir vu passer deux articles sur le sujet, dont un dans Tangente si j'ai bonne mémoire.

    À noter que le programme donne des solutions invalides qui n'utilisent pas tous les nombres, il faut filtrer. Je n'ai pas non plus implémenté la division qui me paraissait plus compliquée qu'utile à l'époque pour le compte est bon.

    Du coup, je vais relever le défi, histoire de me changer les idées après une journée harassante de travail. Et pour épicer un peu la chose, l'implémentation sera en shell POSIX...

    Bien, je passe sur l'étape de la saisie des nombres et du contrôle des entrées (toujours.)
    Je ne vais pas non plus stocker les solutions, mais plutôt les sortir au fil de l'eau.
    Comme on n'a pas de structure de tableau (en KSh, BASh et probablement ZSh, oui) je vais utiliser une variable par nombre (mais il n'y en a heureusement que quatre) !

    Mon idée est qu'on va faire une boucle sur la liste de nombres.
    Dans un langage comme RPL, on va juste faire quatre tours en décalant...

    \<<
     1 4 FOR i
     4 ROLL
     @process
     NEXT
    \>>
    

    Pour la plupart des autres langages, non Forth-like on va utilier un tableau et décaler le curseur dans la boucle (tout en prenant tous les éléments, c'est juste pour changer l'ordre à chaque itération.)
    Bon, on ne gère pas de tableau et heureusement il n'y a que quatre nombres.

    process0 $number1 $number2 $number3 $number4
    process0 $number2 $number3 $number4 $number1
    process0 $number3 $number4 $number1 $number2
    process0 $number4 $number1 $number2 $number3

    Ces quatre lignes sont trompeuses (ça m'a servi à valider le fonctionnement, mais) il y a en fait vingt-quatre permutations (prises en compte dans la version finale.)

    Le processus va consister à appliquer les quatre opérateurs... de sorte à couvrir tous les cas...
    On peut les énumérer, mais par peur d'oublier, je boucle pareillement pour les quatre opérations... (l'optimisation serait de déboucler ...parce que sinon on aura des doublons du fait la commutativité, mais cet exercice se fera plus tard.)

    process0() {
     for o1 in '+' '-' '*' '/'
     do
     for o2 in '+' '-' '*' '/'
     do
     process1 "$o1" "$o2" "$@"
     done
     done
    }
    process1() {
     local o1="1ドル"
     local o2="2ドル"
     local n1="3ドル"
     local n2="4ドル"
     local n3="5ドル"
     local n4="6ドル"
     for o3 in '+' '-' '*' '/'
     do
     test $(( (n1 $o1 n2) $o3 (n3 $o2 n4) )) -eq 24 &&
     solution1 "$n1" "$o1" "$n2" "$n3" "$o2" "$n4" "$o3"
     done
    }
    solution1() {
     local r1=$(( 1ドル 2ドル 3ドル ))
     local r2=$(( 4ドル 5ドル 6ドル ))
     echo "1ドル2ドル3ドル=$r1; 4ドル5ドル6ドル=$r2; $r17ドル$r2=24"
    }

    Bon, c'est pas tout ça. Dans ce truc brutalement automatique, il ne faut pas oublier de gérer la division par zéro...

     test "$o1" = '/' && test $n2 -eq 0 && break
     test "$o2" = '/' && test $n4 -eq 0 && break
     test "$o3" = '/' && test "$o2" = '/' && test $n3 -lt $n4 && continue

    En plus du second processus, on va appeler un troisième dans la même boucle (c'est du « quick and dirty » et il doit être possible de fusionner les deux...)

    process2() {
     local o1="1ドル"
     local o2="2ドル"
     local n1="3ドル"
     local n2="4ドル"
     local n3="5ドル"
     local n4="6ドル"
     test "$o3" = '/' && test $n2 -eq 0 && return
     for o3 in '+' '-' '*' '/'
     do
     test "$o2" = '/' && test "$o3" = '/' && test $n2 -lt $n3 && continue
     test $(( n1 $o1 (n2 $o3 n3) $o2 n4 )) -eq 24 &&
     solution2 "$n1" "$o1" "$n2" "$n3" "$o2" "$n4" "$o3"
     done
    }
    solution2() {
     local r3=$(( 3ドル 7ドル 4ドル ))
     local r4=$(( 1ドル 2ドル $r3 ))
     echo "3ドル7ドル4ドル=$r3; 1ドル2ドル$r3=$r4; $r45ドル6ドル=24"
    }

    Enfin, on pense à ajouter les compteurs.

    $ trouve24.sh 1 2 3 8
    1/2=0; 3*8=24; 0+24=24
    1/2=0; 8*3=24; 0+24=24
    1+3=4; 8-2=6; 4*6=24
    2-1=1; 3*8=24; 1*24=24
    2-1=1; 8*3=24; 1*24=24
    3+1=4; 8-2=6; 4*6=24
    2-1=1; 3*1=3; 3*8=24
    2-1=1; 3/1=3; 3*8=24
    3*8=24; 1/2=0; 24+0=24
    3*8=24; 1/2=0; 24-0=24
    3*8=24; 2-1=1; 24*1=24
    3*8=24; 2-1=1; 24/1=24
    8-2=6; 1+3=4; 6*4=24
    2-1=1; 8*1=8; 8*3=24
    2-1=1; 8/1=8; 8*3=24
    8-2=6; 3+1=4; 6*4=24
    8*3=24; 1/2=0; 24+0=24
    8*3=24; 1/2=0; 24-0=24
    8*3=24; 2-1=1; 24*1=24
    8*3=24; 2-1=1; 24/1=24
    20 solutions for 2832 computed.

    Comme c'est bête/brute et méchant/truand, il m'annonce vingt réponses qui pourraient se ramener à 10 du fait des symétries et on a exploré deux mille huit cents combinaisons dont on aurait pu se passer du quart je pense.
    J'ai exploré ici les formes (A x B) y (C z D) (c'est (8-5)*(7+1) ou (1+3)*(2-8) par exemple) et A x (B y C) z D (c'est 3*(2-1)*8 par exemple) ; mais pas A x B y (C z D) et (A x B) y C z D ! Il s'agit d'une part d'un jet rapide, et d'autre part ce ne serait pas pertinent en shell car je soupçonne qu'il y aura des doublons et/ou même des triplons. Cependant, avec ces ajouts, on devrait arriver aux trois mille septante douze...

    Petit bémol cependant : les calcul ici sont fait sur des entiers et c'est problématique pour les divisions car le hollandais volant l'entend flottant... (si j'en crois la fonction randomizeNumbers() qui pourtant fait un Math.floor(), à moins que ce ne soit à cause du evalMath(cell1, operator, cell2) dans la fonction evalResultat() ?) Je pense pouvoir corriger cela facilement, ce qui réduira le nombre de solutions proposées.

    "It is seldom that liberty of any kind is lost all at once." ― David Hume