• # En Python, classieux

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

    #! /usr/bin/python3
    
    # Advent of Code 2022, day 2
    
    from typing import Iterable, Optional, TypeVar
    
    # '@' is not a valid item type, but it does no harm, and having it makes the
    # value of each item type equal to its index in this string. :-)
    letters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    priorities = {letter: value for (value, letter) in enumerate(letters)}
    
    
    class Rucksack:
        def __init__(self, left: str, right: str):
            self.left = left
            self.right = right
    
        def anomaly(self) -> str:
            for letter in self.left:
                if letter in self.right:
                    return letter
            raise ValueError("no anomaly in this rucksack")
    
        def __contains__(self, letter: str) -> bool:
            return letter in self.left or letter in self.right
    
    
    def import_sack(line):
        n = len(line) - 1  # do not count final '\n'
        left = line[0:n//2]
        right = line[n//2:n]
        return Rucksack(left, right)
    
    
    T = TypeVar('T')
    
    
    def group(iterable: Iterable[T], n: int) -> Iterable[list[T]]:
        result = []  # type: list[T]
        for item in iterable:
            result.append(item)
            if len(result) >= n:
                yield result
                result = []
        yield result
    
    
    def part1(lines: Iterable[str]) -> int:
        total = 0
        for line in lines:
            sack = import_sack(line)
            total += priorities[sack.anomaly()]
        return total
    
    
    def part2(lines: Iterable[str]) -> int:
        total = 0
        for line_group in group(lines, 3):
            sacks = [import_sack(line) for line in line_group]
            for letter in letters:
                if all(letter in sack for sack in sacks):
                    total += priorities[letter]
                    break
        return total
  • # Python pas classieux mais avec des set

    Posté par  . Évalué à 3.

    #! /usr/bin/python3
    
    fichier = 'input_day_3'
    
    def priority(c):
        return 26*c.isupper() + (ord(c)&31)
    
    items_p = badges_p = grp_size = 0
    badges_set = set()
    
    with open(fichier,'r') as f:
        while line := f.readline().strip():
            # part 1
            l = len(line) // 2
            items_p += sum(priority(c) for c in {*line[:l]} & {*line[l:]})
            # part 2
            if not badges_set:            
                badges_set = {*line}
            else:
                badges_set &= {*line}
            grp_size += 1
            if grp_size % 3 == 0:
                badges_p += priority(badges_set.pop())
    
    
    print(items_p, badges_p)
    • [^] # Re: Python pas classieux mais avec des set

      Posté par  . Évalué à 1. Dernière modification le 13 décembre 2022 à 09:48.

      # part 1
      print ("part1:", sum( ( ord(i)-38 , ord(i)-96) [ ord(i)>90 ]  for x in open("input").readlines() for i in set(x[:len(x)//2]).intersection(x[len(x)//2:])))
      # part 2
      def part2():
          with open("input") as infile:
              for line1 in infile:
                  line2 = next(infile)
                  line3 = next(infile)
                  for i in set(line1.strip()).intersection(line2).intersection(line3):
                      yield ( ( ord(i)-38 , ord(i)-96) [ ord(i)>90 ])
      print("part2:", sum(list(part2())))

      (oui j'arrive après la bataille ;-) )

  • # un bout de AWK

    Posté par  . Évalué à 3.

    disclamer : j'ai d'abord Ă©crit une solution en python parce que j'ai tout de suite penser Ă  utiliser les set. puis en AWK pour le plaisir :)

    part 1

    {
        split(substr($0,1,length($0)/2),arr,"")
        r = substr($0,1+length($0)/2)
        for (a in arr) {
            c = arr[a]
            if (index(r,c)>0) {
                comm = c
            }
        }
        S += index("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", comm)
    }
    END {print S}

    part 2

    NR%3==1 {split($0,arr,"");for(a in arr){A[arr[a]]=1}}
    NR%3==2 {split($0,arr,"");for(a in arr){B[arr[a]]=1}}
    NR%3==0 {
        split($0,arr,"")
        for (a in arr) {
            c = arr[a]
            if ((c in A)&&(c in B)) {comm = c}
        }
        S += index("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", comm)
        delete A
        delete B
    }
    END {print S}
  • # un bout de coquillage

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

    Quelles commande(s) allons-nous (re)découvrir aujourd'hui ?
    Voici pour la première partie.

    #!/bin/sh
    # $1: input file
    
    for c in 'grep' 'sed' 'sort' 'test'
    do
        if ! command -v "$c" >/dev/null
        then
            echo "Error: command '$c' not found" >&2
            exit 3
        fi
    done
    
    if test -z "$1"
    then
        echo "Please call me with an input file..." >&2
        exit 1
    fi
    
    if grep -Eqsv '^[a-zA-Z]+$' "$1"
    then
        echo "Found invalid line, check the file!" >&2
        exit 2
    fi
    _if="$1"
    
    _fc=$( mktemp ) # first compartiment
    _sc=$( mktemp ) # second compartiment
    _si='' # shared items
    while IFS= read -r line <&3
    do
        printf '%s' "$line" | cut -c -$(( ${#line}/2 )) |
            sed 's/./&\n/g' | sort -uo "$_fc"
        printf '%s' "$line" | cut -c $(( ${#line}/2 + 1 ))- |
            sed 's/./&\n/g' | sort -uo "$_sc"
        _si="$_si $( comm -12 "$_fc" "$_sc" )"
    done 3<"$_if"
    rm "$_fc" "$_sc"
    #echo "$_si" | cat -vet
    
    _ps=0 # priority sum
    _ac=0 # ASCII code
    for character in $( echo "$_si" )
    do
        _ac=$( printf '%d' "'$character" )
        case "$character" in
            [a-z]) # a is 97 but should translate to 1
                _ps=$(( _ps + _ac - 96 )) ;;
            [A-Z]) # A is 65 but should translate to 27
                _ps=$(( _ps + _ac - 38 )) ;;
            *) echo "$character=$_ac=??" >&2 ;;
        esac
    done
    echo "$_ps"

    La grande difficulté est que l'écriture suivante (à laquelle j'ai initialement pensée) n'est pas POSIX (c'est une facilité de (ba|k|z)sh mais pas reconnue dans ash par exemple)

    _fc='' # first compartiment
    _sc='' # second compartiment
    _si='' # shared items
    while IFS= read -r line
    do
        _fc="$( printf '%s' "$line" | cut -c -$(( ${#line}/2 )) |
            sed 's/./&\n/g' | sort )"
        _sc="$( printf '%s' "$line" | cut -c $(( ${#line}/2 + 1 ))- |
            sed 's/./&\n/g' | sort )"
        _si="$_si $( comm -12 <( printf '%s' "$_fc" ) <( printf '%s' "$_sc" ) )"
    done <"$_if"

    Pas grave, on troque l'utilisation de RAM (dont la machine où j'ai testé manque un peu) contre des fichiers (j'ai des E/S sur disque assez performantes pour que ce ne soit pas problématique.)

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

    • [^] # Re: un bout de coquillage

      Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 12 décembre 2022 à 01:47.

      La seconde partie m'a fait pensé à split pour les groupes de trois… Mais bon, ça fait pléthore de fichiers à gérer ensuite, et puis l'adaptation de la solution précédente n'est pas vraiment difficile (le truc en sus est d'arriver à compter …modulo trois.)

      #!/bin/sh
      # $1: input file
      
      for c in 'cat' 'fold' 'grep' 'sort' 'test'
      do
          if ! command -v "$c" >/dev/null
          then
              echo "Error: command '$c' not found" >&2
              exit 3
          fi
      done
      
      if test -z "$1"
      then
          echo "Please call me with an input file..." >&2
          exit 1
      fi
      
      if grep -Eqsv '^[A-Za-z]+$' "$1"
      then
          echo "Found invalid line, check the file!" >&2
          exit 2
      fi
      _if="$1"
      
      if test $(( $( cat "$_if" | wc -l ) % 3 )) -ne 0
      then
          echo "Number of lines not multiple of 3" >&2
          exit 2
      fi
      
      _fc=$( mktemp ) # becomes first rucksack
      _sc=$( mktemp ) # becomes second rucksack
      _tc=$( mktemp ) # third rucksack
      _si='' # shared items
      _gc=0 # group counter
      _bl='' # badges list
      while IFS= read -r line <&3
      do
          _gc=$(( _gc + 1 ))
          case $(( _gc % 3 )) in
              1) # 1st member of group
                  printf '%s' "$line" | fold -w 1 | sort -uo "$_fc"
                  ;;
              2) # 2nd member of group
                  printf '%s' "$line" | fold -w 1 | sort -uo "$_sc"
                  _si="$( comm -12 "$_fc" "$_sc" )"
                  ;;
              0) # 3rd member of group
                  printf '%s' "$line" | fold -w 1 | sort -uo "$_tc"
                  _bl="$_bl $( printf '%s' "$_si" | comm -12 "$_tc" - )"
                  ;;
              *) echo "?!?$_gc!?!" >&2 ;;
          esac
      done 3<"$_if"
      rm "$_fc" "$_sc" "$_tc"
      #echo "$_bl" | cat -vet
      
      _ps=0 # priority sum
      _ac=0 # ASCII code
      for character in $( echo "$_bl" )
      do
          _ac=$( printf '%d' "'$character" )
          case "$character" in
              [a-z]) # a is 97 but should translate to 1
                  _ps=$(( _ps + _ac - 96 )) ;;
              [A-Z]) # A is 65 but should translate to 27
                  _ps=$(( _ps + _ac - 38 )) ;;
              *) echo "$character=$_ac=??" >&2 ;;
          esac
      done
      
      echo "$_ps"

      Le vice avait été poussé jusqu'à éviter grep -o car cette option n'est pas POSIX (bien que je la trouve un peu partout ceci dit.) Ici, je propose une autre approche que j'avais mentionnée dans l'un de mes journaux. En terme de perfs, faut voir.

      $ time echo "split" | sed 's/./&\n/g'
      s
      p
      l
      i
      t
      
      
      real    0m0.014s
      user    0m0.002s
      sys     0m0.004s
      $ time echo "split" | grep -o '.'
      s
      p
      l
      i
      t
      
      real    0m0.006s
      user    0m0.002s
      sys     0m0.004s
      $ time echo "split" | fold -w1
      s
      p
      l
      i
      t
      
      real    0m0.008s
      user    0m0.002s
      sys     0m0.007s

      Il y a certainement des optimisations possibles, mais comme on le sait faut pas s'y lancer prématurément.

      “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.