Calendrier de l'avent 🎄 (mais sans chocolats)

image

On repasse sur des choses un peu plus simples, qui devraient nous rappeler le début du mois de décembre.
Ma solution en Python sur GitHub, j’ai rien optimisĂ© et tant que le buffer est petit (25) je ne pense pas que ça vaille vraiment le coup. On pourrait maintenir une liste des sommes existantes plutĂŽt que de les recalculer Ă  chaque fois dans mon cas, mais lĂ  le code prend 8ms, j’ai un peu la flemme d’écrire plus de code :slight_smile:

1 « J'aime »

hello je viens de lire la part1, ca n’a pas l’air trop mĂ©chant. A voir s’il y a un twist part2 :slight_smile:

Non, mĂȘme pas. On verra si ça se corse demain !

Hop j’ai rĂ©ussi. Il a fallu faire un tout petit peu d’optimisation (streams) pour s’arrĂȘter dĂšs qu’on trouve une solution convenable. Sinon calculer toutes les combinaisons peut prendre jusqu’à 5 secondes.

Part1 / Part2

J’ai fait part 1, mais bourrinement, je calcule les sum nĂ©cessaires et je cherche dans le tableau de resultat

Mais je pense que Day5 devrait nous aider à aller plus vite


Day 9 part 1 PHP
    /**
     * @return int
     */
    public function day9part1(): int
    {
        $lines = $this->getFile('day9.txt');
        $max = count($lines)-25;

        for($i=25; $i<$max; $i++)
        {
            if (!$this->isSumOfPrevious($i, $lines)) {
                return $lines[$i];
            }
        }


        return 0;
    }


    /**
     * @param int $index
     * @param array $entries
     *
     * @return bool
     */
    private function isSumOfPrevious(int $index, array $entries): bool
    {
        $valueToFind = (int)$entries[$index];
        $values = array_splice($entries, $index-25, 25);
        sort($values);
        for($i=0; $i<25; $i++)
        {
            for($j=$i+1; $j<25; $j++)
            {
                if ((int)$values[$i]+(int)$values[$j] === $valueToFind) {
                    return true;
                }
            }
        }
        return false;
    }

Tain j’ai bloquĂ© je sais pas combien de temps sur ce problĂšme aussi.
Je voyais pas ce qui clochait dans mon algo et comme j’avais pensĂ© Ă  faire le copy() je me suis pas mĂ©fiĂ©.

1 « J'aime »

j’ai fait cette premiĂšre version, puis j’ai utilisĂ© l’API de stream d’Elixir (j’imagine que php Ă  un Ă©quivalent ?) qui permet, en ne demandant Ă  consommer qu’un seul Ă©lĂ©ment du stream, d’arrĂȘter de calculer les combinaisons dĂšs qu’on a un rĂ©sultat.

Je dis n’importe quoi, c’était ma premiĂšre idĂ©e, mais c’était trop bourrin donc je m’arrĂȘte dĂ©sormais au premier calcul trouvĂ©.

hop, Jour 9 completĂ©. Par contre c’est hyper rapide chez moi sans optimisation, je suis Ă  0.089s pour sortir les deux Ă©toiles. La combinatoire n’est pas si forte je trouve.

@Donjohn : pourquoi tu calcules toutes les sommes necessaires ? Il suffit de tester les sommes deux à deux en commencant dans le range (preamble-25 : end) et de t’arreter à la premiere. C’est ce que j’ai fais et c’est super rapide.

Jour 9 (Python)
def testNumber(liste, testNumber):
    for i in range(len(liste)):
        for j in range(i+1, len(liste)):
            if liste[i]+liste[j] == currentNumber:
                return True, liste[i], liste[j]
    return False, -1, -1

def testSequenceFromIndex(liste, invalideNumber, index):
    currentSum = 0
    for i in range(index, len(liste)):
        currentSum += liste[i]
        if currentSum == invalidNumber:
            return True, i+1
        elif currentSum > invalidNumber:
            return False, -1
    return False, -1

numberList = []
preamble = 25
f = open("Z:\donnees\developpement\Python\AdventOfCode\day9.txt", "r")
numberRead = 1
for line in f:
    currentNumber = int(line.rstrip("\n"))

    ## preamble numbers : initializing the list of available numbers
    if numberRead <= preamble:
        numberList.append(currentNumber)
        #print("#{0}={1} - preamble not completed, adding it to availableNumbers".format(numberRead, currentNumber))
    else:
        ## validating number : is it the sum of two numbers in the premable last number of the list
        testResult, a, b = testNumber(numberList[-preamble:], currentNumber)
        if testResult:
            numberList.append(currentNumber)
            #print("#{0}={1} - number valide - is the sum of {2} and {3}".format(numberRead, currentNumber, a, b))
        else:
            invalidNumber = currentNumber
            print("Star 1 : {1} - #{0}={1} - number NOT valide".format(numberRead, invalidNumber, a, b))
            break
    numberRead += 1
f.close()

## Star 2 : looking for a set of addition with all previous numbers :
for i in range(len(numberList)):
    testResult, shift = testSequenceFromIndex(numberList, invalidNumber, i)
    if testResult:
        listResult = numberList[i:shift]
        print("Star 2 : {1} - sublist={0}".format(listResult, min(listResult) + max(listResult)))
        break

Et le résultat :

Star 1 : 105950735 - #565=105950735 - number NOT valide
Star 2 : 13826915 - sublist=[4117189, 4154061, 4424828, 4208390, 5060031, 4391939, 8942999, 5977809, 8491671, 5334788, 8808360, 5708469, 7418529, 5800654, 9709726, 6431377, 6969915]
[Finished in 0.089s]

@anon10092024 parceque j’ai dit de la merde et que je m’arrete evidemment au premier trouvé 

Sinon trouvĂ© part2, je deplace une sorte de somme dans la liste. Je calcule une seule fois une somme et j’ajoute/enleve la fin ou le debut si c’est trop petit ou trop grand. C’est ultra rapide 0.0005ms alors que part1 me prend 0.013ms.

Day 9 part 2 PHP
        $value = $this->day9part1();
        $lines = $this->getFile('day9.txt');
        $start=0;
        $end=0;
        $removeStart=true;
        $pendingSum=0;

        while($pendingSum!==$value)
        {
            if ($pendingSum>$value)
            {
                if ($removeStart) {
                    $pendingSum-=(int)$lines[$start++];
                } else {
                    $pendingSum-=(int)$lines[--$end];
                }
                $removeStart=false;
            } else {
                $removeStart=true;
                $pendingSum+=(int)$lines[$end++];
            }

        }

        $lines = array_splice($lines, $start, ($end-$start));

        return min($lines)+max($lines);

Pas le temps de faire autre chose que du bourrin :

Résumé
def check_number(data,n):
    for i in data:
        for j in data:
            if i!=j:
                if n == i+j:
                    return True
    return False

def day9_1(data):
    buffer = 25
    subData = data[0:buffer]

    for i in data[buffer:]:
        if not check_number(subData,i):
            return i
        subData.pop(0)
        subData.append(i)
    return None

def day9_2_process(data,n):
    for i in range(0,len(data)):
        sum = n
        for j in range(i,len(data)):
            sum-=data[j]
            if sum == 0:
                return i,j
            if sum < 0:
                break
    return None, None

def day9_2(data,n):
    i,j = day9_2_process(data,n)
    if i is not None:
        return max(data[i:j])+min(data[i:j])
    return -1

if __name__ == '__main__':
    fichier = open('input.txt', 'r')
    lignes = fichier.read().splitlines()
    data = [int(i) for i in lignes]
    res = day9_1(data)
    print(res)
    
    res = day9_2(data,res)
    print(res)

Tu peux optimiser vachement ton check number en calculant seulement i+j et pas j+i .

Au lieu de deux boucle for qui testent tout les chiffres, il suffit de faire la deuxieme boucle for sur le range (i+1, len(data)). Ca t’evite aussi de tester i == j.

La combinatoire passe de nÂČ Ă  n(n-1)/2

Yep. Je fais pas semblant sur le bourrin ;).

1 « J'aime »

J’ai galĂ©rĂ© aujourd’hui avec ma programmation fonctionnelle, j’aurais rĂȘvĂ© de pouvoir utiliser une boucle T_T
C’est mĂȘme pas trĂšs joli comme code et pas optimisĂ© non plus, j’étais plus satisfait de ce que j’ai rendu les jours prĂ©cĂ©dents.
Sinon je me suis aperçu que les derniĂšres versions de nodeJS ne gĂšrent plus la tail call optimisation, donc si je fais trop d’appels rĂ©cursifs ça plante, au moins ça m’évite d’ĂȘtre trop bourrin dans mon approche.

Jour 9
let formatedData = data
.split('\n')
.map(d => parseInt(d, 10))

// get all possible addition of two values from a list of values
let getAllSumsRec = (acc) => (first) => (second) => (list) => {
    if(first >= list.length) return acc 
    if(second >= list.length) return getAllSumsRec(acc) (first+1) (first+2) (list) 
    return getAllSumsRec([...acc, list[first] + list[second]]) (first) (second+1) (list)
}

let getAllSums = getAllSumsRec([])(0)(1)

// get the first and second index from a list for which continuous sum gives the tested val
// if no match, return false
let getContiguousSumRec = (first) => (list) => (testedVal) => {
    // exit when all elements are tested
    if(first >= list.length) return false 
    
    // test sums starting from "first" index
    // return an object : {found:true, sum:1234, index:123}
    // the index is relative to first index, add first+1 to get absolute index
    let sum = list
    .slice(first+1)
    .reduce((acc,d,i) => {
        if (acc.found) return acc
        if (acc.sum + d === testedVal) return {found:true, sum:acc.val+d, index:i}
        return {...acc, sum:acc.sum+d}
    },{found:false, sum:list[first]})

    // if found, return the first and second index (translated to absolute position)
    if (sum.found) return {first:first, second:first+sum.index+1}
    return getContiguousSumRec(first+1)(list)(testedVal)
}

let getContiguousSum = getContiguousSumRec(0)

// test all indexes starting from 26 where the addition of two among any of the 25 previous numbers is the number at tested position
// return the first failed index
let result1 = 
    formatedData
    .reduce((acc,d,i,data) => {
        if (acc > 0) return acc
        if (data.slice(i-25,i).length > 0 && !getAllSums(data.slice(i-25,i)).includes(d)){
            return i
        } else {
            return 0
        }
    } ,0)

console.log(formatedData[result1])

// get the first and second index position for which 
// when we sum the elements inside the list from first to second index 
// it gives the failed number
let indexes = getContiguousSum(formatedData.slice(0,result1))(formatedData[result1])

// get the min and max value from the list between first and second index included
let result2 = formatedData
.slice(indexes.first, indexes.second+1)
.reduce((acc,d,i) => {
    if (i === 0) return {min:d, max:d}
    if (d > acc.max) return {...acc, max:d}
    if (d < acc.min) return {...acc, min:d}
    return acc
},{})

console.log(result2.min + result2.max)
2 « J'aime »

J’ai fait mon geek, j’ai créé une petite tache mix (un script Elixir) pour me crĂ©er les fichiers du jour et tĂ©lĂ©charger le puzzle input depuis adventofcode.com :slight_smile:

le code ici

1 « J'aime »

Le Day 10 part 1 est assez trivial, mais le part 2 est intéressant !

Un moyen d’avancer pour ceux qui auraient du mal Ă  dĂ©marrer:

Le lien StackExchange qui va bien

https://math.stackexchange.com/questions/284700/maximum-number-of-path-for-acyclic-graph-with-start-and-end-node

1 « J'aime »

Tu es bien matinal :slight_smile:

part1 est ptet pas bien compliquĂ© mais il faut relire l’énoncĂ© 10x quand mĂȘme !

Pas vraiment, disons que chez moi il est 13h quand les challenges arrivent, ça aide Ă  ĂȘtre bien rĂ©veillĂ© :slight_smile:

1 « J'aime »

haha alors c’est moi qui suis matinal :sweat_smile:
bon j’ai rĂ©ussi part1 et part2 fais mal Ă  la tĂȘte,j’'y reviendrai plus tard !

Allez zou, mon code pour la Part 2.

Soyez indulgents, c’est du Kotlin et j’en ai Ă©crit ma premiĂšre ligne il y a 2 jours quand j’ai commencĂ© cet Advent of Code.

Day 10 Part 2
fun main() {

    val valuesFromFile = File("c:\\Temp\\input10.txt").readLines().map { it.toInt() }.sorted()
    // Adding initial 0 for outlet and last max adapter + 3 value for built-in device adapter
    val jolts: List<Int> = listOf(0) + valuesFromFile + (valuesFromFile.last() + 3)
    val nodes = jolts.map { JoltNode(it) }

    // Building Edges
    nodes.forEachIndexed { i, joltNode ->
        for (j in 1..3) {
            val nextIndex = i + j
            if (nextIndex < nodes.size) {
                val nextJoltNode = nodes[nextIndex]
                if (nextJoltNode.value - joltNode.value <= 3) {
                    joltNode.addChild(nextJoltNode)
                }
            }
        }
    }

    // Summing weights along backtracking path, last node starts with weight 1
    nodes.last().weight = 1L

    for (i in nodes.size - 2 downTo 0) {
        val joltNode = nodes[i]
        joltNode.children.forEach {
            joltNode.weight += it.weight
        }
    }

    println(nodes.first().weight)
}

class JoltNode(_value: Int) {
    var value = _value
    var weight: Long = 0
    val children = mutableListOf<JoltNode>()
    fun addChild(child: JoltNode) {
        children.add(child)
    }
}