Maison > interface Web > js tutoriel > Réparation de pont

Réparation de pont

Mary-Kate Olsen
Libérer: 2024-12-22 04:17:09
original
124 Les gens l'ont consulté

Bridge Repair

Avènement du Code 2024 Jour 7

Partie 1

Première récursion de l'année

C'est du moins comme ça que j'ai l'intention de gagner une étoile d'or aujourd'hui :

  • Commencez par la liste complète
  • Vérifiez l'addition et la multiplication
  • Pour chaque résultat, continuez avec le reste de la liste
  • Jusqu'à ce que j'aie dépassé ou égalé le total

La difficulté sera dans les détails.

Faisons ça !

Créer mon algorithme

Tout d'abord, je dois analyser chaque ligne en une liste de nombres :

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le premier élément est le total souhaité.

Le reste sont les opérandes ordonnés de l'équation.

Je devrai en tenir compte dans ma fonction récursive.

Voici ma fonction récursive :

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et voici la réduction qui l'utilise :

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme je l'espérais mais ne m'y attendais jamais, cela génère la bonne réponse pour l'exemple d'entrée !

Est-ce que le traitement de ma saisie de puzzle sera terminé ?

Et si oui, cela générera-t-il la bonne réponse ?

Honnêtement, je ne suis pas sûr...

C'EST FAIT !!!

Waouh !!!

Aussi excité que je sois, je crains que la prochaine partie ajoute plus d'opérateurs ou nécessite du CS avancé pour que la récursion ne soit plus une solution viable.

Partie 2

Totalement inattendu ! Et bien plus difficile

Comment vais-je faire ça ?

...

Quelques jours plus tard...

Un récapitulatif de mon processus de réflexion :

  • Est-ce aussi simple que d'ajouter une troisième clause à ma condition de retour ? Non
  • Ma fonction récursive de la partie 1 est-elle correctement configurée pour réussir ? Non
  • Oh non, est-il même possible d'accumuler un montant résultant d'opérations antérieures ? Non
  • Est-ce que je vais vraiment devoir aborder cela avec une nouvelle stratégie ? Ouais

Compte tenu de toutes les nouvelles variantes

Pour cette équation :

292: 11 6 16 20
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ce sont toutes les équations possibles étant donné les trois opérateurs :

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 
Copier après la connexion
Copier après la connexion
Copier après la connexion

Peut-être que je peux créer une chaîne de chaque équation et l'évaluer manuellement dans ma fonction récursive.

Par exemple :
Je commence par une chaîne vide dans l'appel de fonction le plus externe :

""
Copier après la connexion
Copier après la connexion
Copier après la connexion

À partir de là, je crée trois variantes en utilisant le numéro suivant :

"" + "+N"
"" + "*N"
"" + "N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

Hmm, mais cela ne fonctionnera pas pour le premier numéro.

Je dois démarrer mon premier appel de fonction avec le premier numéro, pas une chaîne vide :

"N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

Même chose à partir de là :

"N" + "+N"
"N" + "*N"
"N" + "N"
Copier après la connexion
Copier après la connexion

Ouais, ça devrait marcher.

À la fin, j'aurai ces exemples de variations, tous évaluables :

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})
Copier après la connexion
Copier après la connexion
Copier après la connexion

Passer à : Je l'ai codé... et j'ai découvert un problème plus important

J'ai écrit du code qui génère avec succès toutes les variantes de l'équation.

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
  • j'ai l'habitude de parcourir la liste des numéros
  • La dernière clause ne se poursuit que si i est avant ou à l'avant-dernier index

La fonction obtient quatre valeurs :

  1. Une copie de la liste des numéros, moins le total attendu
  2. Le prochain indice
  3. La chaîne d'équation avec l'une des trois chaînes concaténées
  4. Le même numéro de test

J'appelle la fonction en utilisant presque la même signature que dans la partie 1 :

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)
Copier après la connexion
Copier après la connexion
Copier après la connexion

La différence réside dans ce que je passe comme arguments :

  1. La liste sans le montant total attendu
  2. Commencer à l'index 0
  3. Une chaîne contenant le premier nombre
  4. Le montant total attendu

Excellente nouvelle :

  • Il génère toutes les variations d'équation

Mauvaise nouvelle :

  • Il évalue toutes les équations en utilisant PEMDAS, et non de gauche à droite

J'aurais dû savoir mieux... que l'évaluateur JavaScript intégré utiliserait par défaut le bon ordre des opérations, et non de gauche à droite.

Cela met vraiment une clé encore plus grande dans mon algorithme :

  • Je vais devoir décomposer chaque équation et l'évaluer partie par partie

Uggghhh.

Heureusement, je pense que je sais exactement comment faire ça.

Faire des calculs manuellement

J'ai besoin d'obtenir du JavaScript pour évaluer une équation comme celle-ci :

292: 11 6 16 20
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet ordre :

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 
Copier après la connexion
Copier après la connexion
Copier après la connexion

J'aimerais diviser cette équation en plusieurs parties :

""
Copier après la connexion
Copier après la connexion
Copier après la connexion

La seule façon pour moi de voir comment, c'est avec cette expression à triple chaîne :

"" + "+N"
"" + "*N"
"" + "N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

Je remplis chaque opérateur avec un espace blanc uniquement pour l'utiliser comme séparateur.

Un fait sur cette liste de parties d'équation :

  • Il contiendra toujours une quantité impaire d'éléments égale ou supérieure à 3

Comment puis-je exploiter ce fait dans une boucle qui parcourt chaque paire opérande-opérateur-opérande ?

Voici mon idée :

  • Supprimez les trois premiers éléments
  • Rejoignez-les sous forme de chaîne et évaluez-la comme une expression mathématique
  • Rattachez le résultat au début de la liste d'équations
  • Répétez jusqu'à ce que la liste des équations soit vide

J'espère que ça marchera !

Mon simulateur de mathématiques de travail en JavaScript :

"N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

Excellente nouvelle :

  • Il me montre les valeurs calculées attendues

Mauvaise nouvelle :

  • Je n'obtiens toujours pas la bonne réponse pour une équation dans l'exemple d'entrée

L'exemple de réponse ne peut pas être faux... n'est-ce pas ??

La réponse que je continue de générer est environ 7k inférieure à la réponse attendue.

Cela me fait penser que mon algorithme n'identifie pas cette équation comme correcte :

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans l'explication de l'exemple de saisie, voici l'équation gagnante :

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Mon algorithme évalue cette équation et génère ce résultat :

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est parce que mon algorithme fonctionne comme ceci :

292: 11 6 16 20
Copier après la connexion
Copier après la connexion
Copier après la connexion

Je ne vois pas comment cela pourrait être un autre numéro.

Alors... j'ai cherché sur Google.

Et j'ai trouvé ma réponse, qui se cachait en clair dans l'explication, comme toujours :

Tous les opérateurs sont toujours évalués de gauche à droite.

Je pré-concaténais les valeurs à chaque appel de fonction récursive.

Au lieu de cela, mon algorithme devrait faire ceci :

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant que je comprends ce qui est censé se produire, puis-je ajuster mon algorithme pour qu'il corresponde à ce comportement de traitement ?

De gauche à droite... pour de vrai cette fois

Heureusement, ajuster mon algorithme a été relativement simple.

J'ai ajouté une clause replaceAll() pour tenir compte de ||.

La nouvelle boucle while dans laquelle je traite tous les trois éléments ressemble à ceci :

""
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et j'ai ajusté le || de ma déclaration de retour. clause pour inclure ces caractères, au lieu de concaténer instantanément les deux nombres.

Tests et re-tests

J'ai exécuté l'algorithme sur l'exemple d'entrée.

Il enfin a généré la bonne réponse !!

Quel soulagement !!

Je me demande s'il va finir de fonctionner et générer la bonne réponse sur ma saisie de puzzle.

Appuyer sur courir...

...

...

J'ai une réponse !

C'est énorme, donc c'est probablement bon signe.

Est-ce la bonne réponse ?

...

Non. Trop haut.

Déception.

Est-ce qu'il me manque un cas limite ?

Ma condition pour une équation gagnante est simplement que le résultat mathématique traité soit égal au montant du test.

Mais que se passe-t-il si l'une des variantes d'équations permet à un sous-ensemble de nombres de générer une réponse correcte ?

Pour détecter et exclure ce scénario, j'ai mis à jour ma condition if pour inclure une clause supplémentaire :

"" + "+N"
"" + "*N"
"" + "N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

De cette façon, ce n'est que si tous les nombres sont traités et que le montant résultant est égal au numéro du test que l'équation sera comptée.

La grande question :

  • Est-ce que cela change la réponse que j'obtiens ?

Appuyer à nouveau sur Exécuter...

...

Hmm, cela ressemble toujours à la même réponse.

Oh, attendez, il y a deux chiffres vers la fin qui sont différents !

Ma nouvelle réponse est exactement 80 de moins qu'avant.

Existe-t-il une équation avec 80 comme montant attendu ?

Oui !

"N"
Copier après la connexion
Copier après la connexion
Copier après la connexion

Existe-t-il un moyen d'obtenir 80 sans utiliser tous les nombres ?

Oui !

"N" + "+N"
"N" + "*N"
"N" + "N"
Copier après la connexion
Copier après la connexion

Était-ce le seul cas limite que je devais exclure ?

Envoi de ma nouvelle réponse...

C'EST CORRECT !!!

Woohoo!!!

Je l'ai fait !!!

Ça. Était. Épuisant. Et exaltant. Et vraiment courir. Et un défi.

Et toutes les raisons pour lesquelles j'aime faire ces puzzles.

En avant le suivant !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal