Forum Programmation.autre Avent du Code, jour 2

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
6
2
déc.
2022

Suite de l'Avent du Code, jour 2.

Les lutins et le Père Noël jouent à pierre-feuille-ciseaux pour déterminer qui dormira le plus près de la réserve de nourriture. Un lutin nous a donné un genre d'antisèche pour optimiser notre façon de jouer, et on doit compter les scores que ça donnerait.

  • # En Python bref

    Posté par  (site web personnel) . Évalué à 4.

    Toujours en Python, mais aujourd'hui, point de modélisation objet, c'est du concis, plus en mode calcul :

    from typing import Iterable, Tuple
    
    def solve_both(lines: Iterable[str]) -> Tuple[int, int]:
        # Symbol -> value for part 1
        values1 = {'A': 1, 'B': 2, 'C': 3, 'X': 1, 'Y': 2, 'Z': 3}
        # Symbol -> value for part 2
        values2 = {'A': 1, 'B': 2, 'C': 3, 'X': -1, 'Y': 0, 'Z': 1}
        score1 = 0  # for part 1
        score2 = 0  # for part 2
        for line in lines:
            char1, char2 = line.split()
            # Values for part 1
            value1_1, value1_2 = values1[char1], values1[char2]
            outcome1 = ((value1_2 - value1_1 + 1) % 3) * 3
            # Values for part 2
            value2_1, result2 = values2[char1], values2[char2]
            value2_2 = (value2_1 + result2 - 1) % 3 + 1
            outcome2 = ((result2 + 1) % 3) * 3
            # We are player 2!
            score1 += value1_2 + outcome1
            score2 += value2_2 + outcome2
        return score1, score2
    • [^] # Re: En Python bref

      Posté par  (Mastodon) . Évalué à 3.

      Sur celui-là, j'ai vachement modélisé au contraire :

      class chifumi(int):
          lose = 1
          draw = 2
          win = 3
      
          def __init__(self, chifumi):
              self.chifumi = chifumi
              self.chifumi = ~self
      
          def __invert__(self):
              """~chifumi returns value in [1, 2, 3]"""
              return (self.chifumi % 3) or 3
      
          def __eq__(self, other):
              return ~self == ~other
      
          def __lt__(self, other):
              return +self == ~other
      
          def __gt__(self, other):
              return -self == ~other
      
          def __neg__(self):
              return ((self.chifumi - 1) % 3) or 3
      
          def __pos__(self):
              return ((self.chifumi + 1) % 3) or 3
      
          def __mod__(self, other):
              """score of self against other"""
              if self == other:
                  return ~self+3
              if self > other:
                  return ~self+6
              return ~self
      
          def __matmul__(self, other):
              """score when result is self, against other"""
              if ~self == self.win:
                  return +other+6
              if ~self == self.lose:
                  return -other
              return ~other+3

      Et la résolution est triviale derrière :

      import sys
      input = [l.split(" ") for l in sys.stdin.read().strip().split("\n")]
      values = dict(
          A=chifumi(1),
          B=chifumi(2),
          C=chifumi(3),
          X=chifumi(1),
          Y=chifumi(2),
          Z=chifumi(3),
      )
      
      score1 = sum(values[me] % values[you] for you, me in input)
      score2 = sum(values[me] @ values[you] for you, me in input)
      
      print(f"Strategy 1 = {score1}")
      print(f"Strategy 2 = {score2}")
      • Yth.
      • [^] # Re: En Python bref

        Posté par  (site web personnel) . Évalué à 3. Dernière modification le 07 décembre 2022 à 14:52.

        Waouh. C'est pour le moins original ça.

            def __invert__(self):
                """~chifumi returns value in [1, 2, 3]"""
                return (self.chifumi % 3) or 3

        Si je comprends bien, ça fait de ~ une opération pour récupérer la valeur normalisée. Bien joué le (valeur % 3) or 3, c'est bien plus lisible que (valeur - 1) % 3 + 1.

            def __pos__(self):
                return ((self.chifumi + 1) % 3) or 3
        
            def __neg__(self):
                return ((self.chifumi - 1) % 3) or 3

        La valeur qui me vainc et la valeur que je vaincs, si je ne m'abuse.

            def __lt__(self, other):
                return +self == ~other
        
            def __gt__(self, other):
                return -self == ~other

        Je suis plus inférieur à un autre si la valeur qui me vainc est la même que la valeur normalisée de l'autre. Et mutatis mutandis pour la supériorité. Tu aurais pu utiliser functool.total_ordering().

        Ensuite, le reste est assez simple à comprendre, une fois ces bases posées. La réutilisation des opérateurs est… intéressante. Je ne peux pas dire que je suis fan, c'est un peu bizarre à lire quand même.

        values = dict(
            A=chifumi(1),
            B=chifumi(2),
            C=chifumi(3),
            X=chifumi(1),
            Y=chifumi(2),
            Z=chifumi(3),
        )

        Tiens, j'ignorais la possibilité d'instancier un dictionnaire avec des mots-clefs. C'est amusant, ça aussi.

        • [^] # Re: En Python bref

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          Bien joué le (valeur % 3) or 3, c'est bien plus lisible que (valeur - 1) % 3 + 1.

          C'est étrange ; c'est l'inverse pour moi …qui ne pense pas assez en Phyton (et ai pratiquement beaucoup de langages où on retrouve la dernière forme)

          La réutilisation des opérateurs est… intéressante. Je ne peux pas dire que je suis fan, c'est un peu bizarre à lire quand même.

          On dirait que c'est écrit par quelqu'un qui pratique/réfléchi le/en OCaml ou peut-être Lisp ou Scheme…

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

          • [^] # Re: En Python bref

            Posté par  (Mastodon) . Évalué à 3.

            J'ai fait du Caml, j'ai joué un peu avec OCaml, et même un poil de Lisp Jadis, mais je ne code pas régulièrement dans ces langages là.

            Réutiliser les opérateurs, c'est bien pour jouer, mais ça peut péter complètement la lisibilité, donc il faut faire très très attention quand on veut partager le code…

            Bien fait c'est génial par contre.

            • Yth.
        • [^] # Re: En Python bref

          Posté par  (Mastodon) . Évalué à 3.

          J'aime bien réutiliser les opérateurs, mais j'ai fait ça assez rapidement, donc la pertinence est celle d'un truc pondu en vingt minutes.
          Le ~chifumi est pratique et plutôt lisible, comme ça on normalise tout le temps.

          Par contre réutiliser la classe chifumi pour qu'elle représente une choix ou un résultat d'affrontement, c'est plutôt moche, ça rendrait illisible un code plus gros, et c'est totalement lié à la présentation de la seconde partie du problème après la résolution de la première : comment bricoler vite fait du code qui répond à la question. C'était plus simple de rajouter un opérateur à une classe existante que de gérer une nouvelle classe.

          Mais en plus propre on pourrait avoir une classe resultat d'affrontement, qui sait se multiplier (par exemple) avec une classe chifumi, avec __mul__ et __rmul__, pour pouvoir faire chifumi * resultat = resultat * chifumi = "mais qu'a donc joué mon adversaire ?"
          On apprends Ă  resultat Ă  se multiplier dans les deux sens avec chifumi sans que celle-ci sache comment se multiplier avec resultat.

          On pourrait garder le même opérateur partout, et faire du __mod__ et __rmod__ sur resultat. Sachant que dans tous les cas on retourne un score qui est un entier et n'a rien à voir avec aucune des deux classes.

          Pour le total_ordering, c'est vrai, mais en pratique j'ai implémenté __lt__ qui n'est jamais utilisé. J'aurais pu nettoyer ça du code avant de le poster.

          • Yth.
  • # if vs modulo

    Posté par  . Évalué à 3.

    J'avoue que je suis passé à côté de la subtilité du modulo et que j'ai bouriné en énumérant les cas possible (nimage).

    • [^] # Re: if vs modulo

      Posté par  (site web personnel, Mastodon) . Évalué à 1. Dernière modification le 08 décembre 2022 à 11:04.

      Y a que neuf cas équitablement répartis, donc on peut se permettre d'énumérer au lieu de sortir l'artillerie lourde àmha.

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

  • # petit bout de AWK

    Posté par  . Évalué à 5.

    #loose
    $0=="A Z"{S+=3}
    $0=="B X"{S+=1}
    $0=="C Y"{S+=2}
    #draw
    $0=="A X"{S+=3+1}
    $0=="B Y"{S+=3+2}
    $0=="C Z"{S+=3+3}
    #win
    $0=="A Y"{S+=6+2}
    $0=="B Z"{S+=6+3}
    $0=="C X"{S+=6+1}
    END{print S}
  • # en shell bref

    Posté par  (site web personnel, Mastodon) . Évalué à 1.

    Juste pour la première partie

    #!/bin/sh
    # $1: input file
    
    if test -z "$1"
    then
        echo "Please call me with an input file..." >&2
        exit 1
    fi
    _if="$1"
    
    if ! command -v grep >/dev/null
    then
        echo "Cannot locate 'grep' command in $PATH" >&2
        exit 2
    fi
    
    _ts=0 # total score
    _nr=0 # number of round
    
    # loose
    _nr=$( grep -cE '^ *B +X *$' "$_if" ) _ts=$(( _ts + 1*_nr ))
    _nr=$( grep -cE '^ *C +Y *$' "$_if" ) _ts=$(( _ts + 2*_nr ))
    _nr=$( grep -cE '^ *A +Z *$' "$_if" ) _ts=$(( _ts + 3*_nr ))
    
    # draw
    _nr=$( grep -cE '^ *A +X *$' "$_if" ) _ts=$(( _ts + 4*_nr ))
    _nr=$( grep -cE '^ *B +Y *$' "$_if" ) _ts=$(( _ts + 5*_nr ))
    _nr=$( grep -cE '^ *C +Z *$' "$_if" ) _ts=$(( _ts + 6*_nr ))
    
    # win
    _nr=$( grep -cE '^ *C +X *$' "$_if" ) _ts=$(( _ts + 7*_nr ))
    _nr=$( grep -cE '^ *A +Y *$' "$_if" ) _ts=$(( _ts + 8*_nr ))
    _nr=$( grep -cE '^ *B +Z *$' "$_if" ) _ts=$(( _ts + 9*_nr ))
    
    # end
    echo "$_ts"

    C'est une bête énumération exhaustive des cas, un peu comme la solution en AWK, mais en étant un peu plus lâche sur le formatage du fichier.

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

    • [^] # Re: en shell bref

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Juste pour la seconde partie

      #!/bin/sh
      # $1: input file
      
      if test -z "$1"
      then
          echo "Please call me with an input file..." >&2
          exit 1
      fi
      _if="$1"
      
      if ! command -v grep >/dev/null
      then
          echo "Cannot locate 'grep' command in $PATH" >&2
          exit 2
      fi
      
      _ts=0 # total score
      _nr=0 # number of round
      
      # +0=loose
      _nr=$( grep -cE '^ *A +X *$' "$_if" ) _ts=$(( _ts + 3*_nr )) # AC RS
      _nr=$( grep -cE '^ *B +X *$' "$_if" ) _ts=$(( _ts + 1*_nr )) # BA PR
      _nr=$( grep -cE '^ *C +X *$' "$_if" ) _ts=$(( _ts + 2*_nr )) # CB SP
      
      # +3=draw
      _nr=$( grep -cE '^ *A +Y *$' "$_if" ) _ts=$(( _ts + 4*_nr )) # AA
      _nr=$( grep -cE '^ *B +Y *$' "$_if" ) _ts=$(( _ts + 5*_nr )) # BB
      _nr=$( grep -cE '^ *C +Y *$' "$_if" ) _ts=$(( _ts + 6*_nr )) # CC
      
      # +6=win
      _nr=$( grep -cE '^ *A +Z *$' "$_if" ) _ts=$(( _ts + 8*_nr )) # AB RP
      _nr=$( grep -cE '^ *B +Z *$' "$_if" ) _ts=$(( _ts + 9*_nr )) # BC PS
      _nr=$( grep -cE '^ *C +Z *$' "$_if" ) _ts=$(( _ts + 7*_nr )) # CA SR
      
      # end
      echo "$_ts"

      MĂŞme principe, juste qu'on calcule autrement.

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

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.