diff --git a/MyIA.AI.Notebooks/Sudoku/Sudoku-08-HumanStrategies-Python.ipynb b/MyIA.AI.Notebooks/Sudoku/Sudoku-08-HumanStrategies-Python.ipynb index e38c86a017..4d1d25d14e 100644 --- a/MyIA.AI.Notebooks/Sudoku/Sudoku-08-HumanStrategies-Python.ipynb +++ b/MyIA.AI.Notebooks/Sudoku/Sudoku-08-HumanStrategies-Python.ipynb @@ -901,6 +901,19 @@ "print(\"Methodes Naked Pair ajoutees.\")" ] }, + { + "cell_type": "markdown", + "id": "d7c8d63d", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture : le contrat de sortie minimal du Naked Pair\n", + "\n", + "La cellule ne produit qu'une ligne (`Methodes Naked Pair ajoutees`) : le contrat de cette étape est l'ajout de la méthode, pas son diagnostic. Ce qui rend la lecture non triviale, c'est ce que la ligne ne dit pas et que la suite du notebook commitera : sur les cinq puzzles du benchmark (cellule de la section 8), la technique est appliquée **15 fois** — la preuve qu'elle est bien déclenchée, et non un code mort. Le Naked Pair exploite une unité (ligne, colonne ou bloc) où **deux cases n'ont exactement que les deux mêmes candidats** : ces deux valeurs ne peuvent plus apparaître ailleurs dans l'unité, donc on les retire des autres cases. C'est une déduction du « deuxième niveau » : elle ne place pas une valeur directement, elle réduit le candidat des cases voisines, ce qui ravive la chasse aux singles des sections précédentes." + ] + }, { "cell_type": "markdown", "id": "cell-05be24e4", @@ -1092,6 +1105,19 @@ "print(\"Methodes Pointing Pair ajoutees.\")" ] }, + { + "cell_type": "markdown", + "id": "af8a8e5c", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture : le Pointing Pair, un candidat verrouillé dans une unité\n", + "\n", + "La sortie minimaliste (`Methodes Pointing Pair ajoutees`) encode une étape d'architecture, pas un calcul : les techniques s'ajoutent par paquet, chacune avec son propre prédicat de recherche, et le solveur complet les compose (section 7). Le Pointing Pair — ou *locked candidates* — survient quand un candidat n'apparaît que dans une seule ligne (ou colonne) d'un bloc : puisqu'il doit nécessairement occuper cette ligne dans le bloc, il est éliminé des **autres blocs de la même ligne**. C'est la première technique où l'observation se fait sur deux unités croisées (bloc × ligne), ce qui la rend plus coûteuse à coder que les singles. Son utilité est mesurée plus bas, dans le benchmark : **17 applications** sur 5 puzzles faciles — derrière les singles, devant le X-Wing — soit une technique de milieu de gamme, fréquente sans être triviale." + ] + }, { "cell_type": "markdown", "id": "6ad47806", @@ -1197,6 +1223,19 @@ "print(\"Methodes X-Wing ajoutees.\")" ] }, + { + "cell_type": "markdown", + "id": "0b6efb70", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture : le X-Wing, première structure en croix\n", + "\n", + "Comme pour les deux sections précédentes, la sortie (`Methodes X-Wing ajoutees`) ne valide que l'ajout ; la mesure d'usage viendra du benchmark : **5 applications** sur les cinq puzzles — le X-Wing est la technique la moins utilisée de la section 8, ce qui est cohérent avec sa définition. Un X-Wing se produit quand une valeur n'a que **deux positions possibles dans deux lignes distinctes, alignées sur les deux mêmes colonnes** : les quatre cases forment un rectangle, et la valeur ne peut occuper que deux coins opposés — elle est donc éliminée des deux colonnes en dehors du rectangle. La structure est symétrique (lignes ↔ colonnes), ce qui explique les paires de méthodes row/col dans le code. Le benchmark le montre rarement utile sur des grilles faciles, mais c'est la technique qui devient indispensable sur les puzzles moyens : sa présence dans la panoplie évite au solveur de tomber dans le backtracking de la section 9." + ] + }, { "cell_type": "markdown", "id": "530a3bec", @@ -1454,6 +1493,19 @@ "print(solver)" ] }, + { + "cell_type": "markdown", + "id": "eaa1bcce", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture du test : la grille facile se résout toute seule, en 1,54 ms\n", + "\n", + "La sortie aligne le puzzle d'origine, sa solution complète, et les statistiques des techniques qui y sont parvenues. Premier fait, en haut : **Resolu: True, Temps: 1,54 ms** — ce puzzle dit « facile » est résolu sans le moindre appel au backtracking : aucune ligne d'appels récursifs n'apparaît, le solveur a tout déduit. Deuxième fait, le relevé des techniques : **Naked Single : 14, Hidden Single : 22** — sur cette grille, la déduction cachée (un chiffre n'a qu'une seule case possible dans son unité) fait plus de travail que la déduction évidente (une case n'a qu'un candidat) ; le ratio 22/14 = 1,6 est l'inverse de l'ordre habituellement présenté dans les tutoriaux (le Naked Single d'abord, le Hidden Single ensuite), d'où l'importance de ces compteurs pour la pédagogie. Troisième fait : la solution elle-même, première ligne `9 6 2 | 1 8 5 | 4 7 3` — les huit autres lignes permutent les mêmes chiffres, chaque ligne/colonne/bloc contenant exactement une fois 1 à 9 ; la vérification visuelle de ces 27 contraintes est l'exercice de lecture le plus direct du notebook." + ] + }, { "cell_type": "markdown", "id": "d02a2e63", @@ -1564,6 +1616,19 @@ "benchmark_human(easy_puzzles, num_puzzles=5)" ] }, + { + "cell_type": "markdown", + "id": "d2c71161", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire les chronos du benchmark : cinq puzzles, un rythme et des écarts\n", + "\n", + "La sortie donne enfin des chiffres que les interprétations qualitatives de la section 8 n'avaient pas encore cités. **Puzzle 1 : 0,65 ms — Puzzle 4 : 3,62 ms** : entre le plus rapide et le plus lent des cinq, le rapport atteint **5,6x** — même parmi des puzzles « faciles », la structure fait varier les temps d'un ordre de grandeur modeste, exactement le comportement que le notebook 18b quantifie sur 8 grilles comparables. Le bilan cité est cohérent : **5/5 résolus, total 11,93 ms, moyenne 2,39 ms** — une moyenne qui a du sens ici parce que tous les puzzles partagent la même fourchette (pas de valeur aberrante au-delà de 3,62 ms). Le dernier bloc donne la « balance » des techniques sur les cinq grilles confondues : **Hidden Single : 149, Naked Single : 91, Pointing Pair : 17, Naked Pair : 15, X-Wing : 5** (total 277 déductions). Trois lectures : (1) les singles font ~87 % du travail (240/277), confirmant la hiérarchie des sections 2-3 ; (2) le X-Wing, à 5, est presque de l'ordre du bruit sur des grilles faciles ; (3) la hiérarchie 149 > 91 > 17 > 15 > 5 est la courbe de fréquence à retenir : la rareté d'une technique croît avec sa complexité, de la déduction unitaire à la structure en croix." + ] + }, { "cell_type": "markdown", "id": "13a9c814", @@ -1793,6 +1858,19 @@ " print(f\" Backtracking: {solved_bt}, {t_bt*1000:.2f}ms, {bt.call_count} appels\")" ] }, + { + "cell_type": "markdown", + "id": "170c545a", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire la comparaison appariée : l'écart se creuse avec la difficulté\n", + "\n", + "La sortie compare les deux solveurs **puzzle par puzzle**, ce qui permet trois lectures exactes. La première : les chronos appariés — P1 : **0,75 ms contre 1,54 ms**, P2 : **3,14 ms contre 7,55 ms**, P3 : **2,16 ms contre 10,95 ms**. Les ratios par puzzle sont 2,1x, 2,4x puis 5,1x : l'avantage des stratégies humaines **grandit avec la difficulté** du puzzle, puisque le backtracking paie chaque retour-arrière en appels récursifs pendant que les déductions logiques coûtent un balayage de candidats. La deuxième lecture : la colonne des appels — **49, 201, 295** — croît dans le même ordre : le backtracking « simple » de la section 9 confirme être le point de comparaison honnête du notebook, celui qui justifie les stratégies humaines sans triomphalisme (sur un puzzle qu'il résout aussi, en 10,95 ms quand même). La troisième : les deux solveurs affichent tous **True** — la comparaison ne porte pas sur la résolubilité (les deux sont complets sur ces grilles), mais sur le chemin : des déductions allant de 0,75 ms (P1) à 3,14 ms (P2), contre 545 appels d'essai-erreur cumulés (49 + 201 + 295)." + ] + }, { "cell_type": "markdown", "id": "4a913e27", @@ -2002,6 +2080,19 @@ "print(\"Methode definie : find_hidden_pairs\")\n" ] }, + { + "cell_type": "markdown", + "id": "5ce66baf", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture de l'exemple résolu : Hidden Pair, la première brique avancée\n", + "\n", + "La sortie (`Methode definie : find_hidden_pairs`) valide que la cellule d'exemple guide est bien un ajout fonctionnel — l'apport de la lecture vient de la cellule de test de la section 10 : le motif détecté y est imprimé, `Hidden Pairs trouves: 1` avec `(0,7) et (1,6) = {8, 7} dans block`. Cette ligne est la lecture complète de l'exemple : deux cases dans le même bloc (intersection des lignes 0-1 et des colonnes 6-7, coin supérieur droit de la grille) sont les **seules** positions où les valeurs 8 et 7 peuvent aller dans ce bloc ; elles gardent leurs autres candidats éventuels, mais 8 et 7 sont confisquées — tout autre candidat dans ces deux cases devient éliminable. C'est le miroir exact du Naked Pair (deux cases avec deux candidats seulement → éliminer des voisins) décrit en section 3." + ] + }, { "cell_type": "markdown", "id": "08e62f62", @@ -2197,6 +2288,19 @@ "print(\"Methode definie : find_swordfish\")\n" ] }, + { + "cell_type": "markdown", + "id": "e454852f", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture de l'exemple résolu : Swordfish, un X-Wing à trois arêtes\n", + "\n", + "La sortie (`Methode definie : find_swordfish`) valide l'ajout, et le test de la section 10 la fait parler : `Swordfish trouves: 1` avec `Valeur 7, lignes=(0, 1, 3), colonnes=(1, 6, 7), orientation=row`. La ligne se lit comme une généralisation du X-Wing : au lieu de deux lignes et deux colonnes, le Swordfish aligne **trois lignes dont le candidat 7 n'occupe que trois colonnes** (1, 6 et 7) ; la valeur doit donc occuper une colonne différente à chaque ligne, et elle peut être éliminée des trois colonnes en dehors des trois lignes visées. L'orientation `row` dit le sens du balayage (le motif existe aussi par colonnes — l'exercice 2b fera coder le transposé). Sur la grille de test, la détection d'un seul motif suffit pour la cellule de validation : la rareté du Swordfish (un motif à trois niveaux sur une grille facile) est elle-même l'information — comme le X-Wing du benchmark, ces structures ne paient leur code que sur les puzzles moyens." + ] + }, { "cell_type": "markdown", "id": "a83851d6", @@ -2431,6 +2535,19 @@ "print(\"Methodes definies : _are_peers, find_xy_wings\")\n" ] }, + { + "cell_type": "markdown", + "id": "e55b3e3d", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lecture de l'exemple résolu : trois XY-Wing, un cycle de paires\n", + "\n", + "La sortie ne dit pas seulement « 3 trouvés », elle imprime les pivots : **Pivot=(7, 1), Aile1=(7, 5), Aile2=(7, 7)**, puis les deux permutations symétriques — les trois pivots forment un cycle sur la ligne 7 de la grille, chacun servant d'aile aux deux autres. Le mécanisme XY-Wing se lit dans les valeurs éliminées : **elimine=8, puis 1, puis 6** — trois valeurs distinctes, une par pivot. Un XY-Wing fonctionne avec trois cases bivaluées (deux candidats chacune) : un pivot {X, Y} et deux ailes {X, Z} et {Y, Z} ; tout candidat commun aux deux ailes (ici leur valeur partagée) peut être retiré de leurs cases voisines communes. Sur la ligne 7 de la grille de test, les trois cases (7,1), (7,5), (7,7) s'échangent ainsi leurs candidats — une chaîne fermée qui élimine trois chiffres, un par pivot ; c'est la plus coûteuse des trois structures de la section 10, et la seule qui exige de superposer trois objets bivalués pour déduire une élimination." + ] + }, { "cell_type": "markdown", "id": "d46ade0f", @@ -2649,6 +2766,19 @@ "print(solver2)" ] }, + { + "cell_type": "markdown", + "id": "d961b952", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire le test des techniques avancées : quatre faits, une grille résolue\n", + "\n", + "La cellule de validation répète les trois exemplettes précédentes sur une grille unique et imprime chaque détection — c'est le bilan chiffré de la section 10. **Hidden Pairs : 1** (le couple {(0,7), (1,6)} = {8, 7} déjà relevé), **Swordfish : 1** (valeur 7, lignes (0, 1, 3) — un seul motif suffit sur la grille de test), **XY-Wings : 3** (le cycle de pivots de la ligne 7). La deuxième moitié de la sortie change de grille : `Puzzle avant resolution` montre une grille vierge (première ligne `2 . . | . 8 . | 3 . .`) que le solveur complet attaque — et `Resolu: True` avec les neuf lignes de solution complètes, dont la première `2 4 5 | 9 8 1 | 3 7 6`. La leçon de cette lecture est la composition : les techniques de la section 10 ne servent pas seules — c'est le solveur de la section 7 qui les enchaîne (Hidden Pair d'abord, puis Swordfish, puis les XY-Wing) jusqu'à la résolution complète. Le test prouve ainsi l'objectif du notebook : un solveur « humain » qui remplace l'essai-erreur par une liste ordonnée de déductions." + ] + }, { "cell_type": "markdown", "id": "7f7e6a12", diff --git a/MyIA.AI.Notebooks/Sudoku/Sudoku-18b-Statistical-Comparison-Python.ipynb b/MyIA.AI.Notebooks/Sudoku/Sudoku-18b-Statistical-Comparison-Python.ipynb index b3c8df9c80..3ca4ed766d 100644 --- a/MyIA.AI.Notebooks/Sudoku/Sudoku-18b-Statistical-Comparison-Python.ipynb +++ b/MyIA.AI.Notebooks/Sudoku/Sudoku-18b-Statistical-Comparison-Python.ipynb @@ -181,6 +181,19 @@ "print(\"Un seul chronométrage n'est PAS une mesure fiable.\")" ] }, + { + "cell_type": "markdown", + "id": "cff52472", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire le bruit : 4 % de coefficient de variation, 1,2x entre les extrêmes\n", + "\n", + "Les trois chiffres de la sortie se complètent pour quantifier le bruit de mesure. **min=0,678 ms, max=0,832 ms** : deux chronos d'un même solveur déterministe sur un même puzzle s'écartent déjà de 22 % — le bruit vient du système et du processeur, pas de l'algorithme. **moyenne=0,726 ms, écart-type=0,029 ms** : le coefficient de variation qui s'affiche (4 %) est l'écart-type divisé par la moyenne, la métrique sans dimension qui permet de comparer ce niveau de bruit d'une mesure à l'autre, même quand les échelles changent. Enfin **ratio max/min = 1,2x** : même en prenant seulement deux extrêmes parmi 30, on ne peut pas prétendre à mieux qu'un ordre de grandeur grossier. Gardez ce chiffre (1,2x) en tête : c'est le niveau de bruit que la section 4 devra faire dépasser à une vraie différence entre solveurs." + ] + }, { "cell_type": "markdown", "id": "cell-76f29524", @@ -301,6 +314,19 @@ "print(\" Les puzzles lents (queue) tirent la moyenne vers le haut.\")" ] }, + { + "cell_type": "markdown", + "id": "cbee70b4", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire le tableau : la difficulté nominale ne dit rien du temps\n", + "\n", + "Le tableau mesure huit puzzles au même nombre de clues (37), donc de même difficulté nominale — et les médianes affichées s'étalent de **0,273 ms (P4) à 2,800 ms (P3)**, soit un facteur **10** entre le plus rapide et le plus lent. C'est le chiffre clé de la section : la structure du puzzle (la position des clues, le nombre de cases forcées tôt dans la recherche) domine largement le nombre de clues. La deuxième lecture du tableau, plus subtile, vient de la colonne de droite : **rapport moy/méd ≈ 1,00-1,02 pour chaque puzzle**. Dans un même puzzle, moyenne et médiane coïncident presque (les 15 répétitions sont resserrées, la distribution intra-puzzle est symétrique) — alors que la sortie agrégée en bas de la même cellule affiche moyenne 1,187 ms pour médiane 0,800 ms sur le pool entier. Le contraste est la leçon : la moyenne ne ment que lorsqu'on mélange des puzzles de structures différentes ; à l'intérieur d'un puzzle, elle est un résumé fiable." + ] + }, { "cell_type": "markdown", "id": "cell-fa845acc", @@ -417,6 +443,19 @@ "print(\"qui dit l'incertitude. Doubler la taille d'échantillon réduit l'IC d'environ √2.\")" ] }, + { + "cell_type": "markdown", + "id": "9f831633", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire l'intervalle : trois chiffres qui disent l'incertitude\n", + "\n", + "La ligne centrale, `Intervalle de confiance à 95 % (bootstrap, 5000 tirages) = [1,027, 1,347] ms`, se lit comme suit : si l'on répétait la mesure, 95 fois sur 100 la vraie moyenne attendue tomberait dans cette plage. De la moyenne affichée au-dessus (1,187 ms), l'intervalle s'écarte de **-13,5 % à +13,5 %** — les deux bornes sont presque symétriques ici, mais le bootstrap ne l'a pas supposé : il a mesuré la forme réelle de la distribution. La largeur (0,321 ms, soit 27 % de la moyenne) joue le rôle d'une barre d'erreur que le point seul ne possède pas : « 1,2 ms » n'aurait pas dit si la vraie valeur pouvait être 1,0 ou 1,5 ms." + ] + }, { "cell_type": "markdown", "id": "cell-e3c8e58e", @@ -556,6 +595,19 @@ "plt.show()\n" ] }, + { + "cell_type": "markdown", + "id": "1ba997c9", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire le test : huit paires, une p-value, un sens\n", + "\n", + "La sortie range les faits dans l'ordre du protocole. D'abord l'unité expérimentale : **n = 8** — pas 120, malgré les 15 répétitions — parce que chaque puzzle ne fournit qu'UNE paire de médianes. Puis les deux chiffres par solveur : **médiane des médianes 1,181 ms (naïf) contre 8,842 ms (MRV)**, et des moyennes 1,870 contre 8,807 — même image, moyenne et médiane proches, la distribution de MRV étant aussi resserrée que celle du naïf. La p-value affichée (7,81 × 10⁻³) est la plus petite valeur que Wilcoxon puisse produire pour n=8 (elle vaut exactement 2/2⁸, comme l'explique la section 5.1) : la différence passe donc le seuil de 5 %, mais sans marge." + ] + }, { "cell_type": "markdown", "id": "cell-1908be22", @@ -636,6 +688,19 @@ "print(\"c'est pourquoi on précise TOUJOURS le pool testé — ici 8 unités expérimentales.\")\n" ] }, + { + "cell_type": "markdown", + "id": "786c8717", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire la taille d'effet : un r parfait, un verdict borné\n", + "\n", + "La première ligne, `MRV est 7.5x plus lent que le naïf en médiane sur ce jeu de puzzles`, dit la taille d'effet dans l'unité des médianes (8,842 ÷ 1,181 ≈ 7,5). La seconde donne le coefficient apparié : **r = 1,000**, la valeur maximale du rank-bisérial — cela signifie que les 8 paires votent toutes dans le même sens : sur chacun des 8 puzzles pris séparément, sans exception, le naïf gagne. La note `|r| < 0,1 : négligeable ... > 0,5 : grand` ancre l'échelle : avec r = 1,0, la « significativité » de la section 4 n'est pas un artefact de puissance, c'est une séparation parfaite." + ] + }, { "cell_type": "markdown", "id": "cell-2ad2dd63", @@ -746,6 +811,19 @@ "print(\"ici le test est déjà apparié et agrégé par puzzle ; les deux se cumulent.\")\n" ] }, + { + "cell_type": "markdown", + "id": "274bcb82", + "metadata": { + "papermill": {}, + "tags": [] + }, + "source": [ + "### Lire les trois comparaisons : une seule survit à Bonferroni\n", + "\n", + "Beaucoup de choses à voir dans le tableau, dans l'ordre des colonnes. **p-values brutes** : seule la paire naïf vs MRV est significative (7,81e-03) ; naïf vs reverse (6,41e-01) et MRV vs reverse (1,48e-01) ne le sont pas. **p corrigées** : la multiplication par 3 (Bonferroni) transforme 7,81e-03 en 2,34e-02 — toujours sous 0,05, donc le verdict « OUI » tient ; les deux autres restent très au-dessus. Le sens de la ligne reverse est essentiel : le solveur qui essaie les chiffres dans l'ordre inverse est statistiquement **indistinguable** du naïf sur ce pool — l'ordre de parcours des chiffres n'y change rien, ce qui confirme que la difficulté vient de la structure du puzzle, pas du choix lexical des valeurs. La dernière note de la sortie (multiplicité + indépendance) rappelle que la correction ne répare pas une pseudo-réplication : elle s'ajoute au test apparié, elle ne le remplace pas." + ] + }, { "cell_type": "markdown", "id": "cell-pseudoreplication", diff --git a/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies.yaml b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies.yaml index 1c01b0a17b..7857ba1827 100644 --- a/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies.yaml +++ b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies.yaml @@ -8,4 +8,4 @@ known_differences: - "Socle pedagogique commun : strategies de resolution humaines (techniques d'inference -- naked/hidden singles, pointing pairs, box-line) appliquees au Sudoku, meme concept (simuler le raisonnement humain par couches d'inference successives plutot qu'un backtracking brut), meme arc pedagogique (theorie -> implementation -> benchmark)." - "Divergence d'implementation : le Python implemente les techniques d'inference from scratch + visualisation networkx du graphe de contraintes ; le C# implemente les memes strategies d'inference en stdlib avec un benchmark comparatif. Idiomes de visualisation differents (networkx cote Python)." - - "Asymetrie structurelle : Python 22 cellules code / 30 markdown ; C# 19 cellules code / 30 markdown. Arc identique (techniques d'inference + mesure de performance)." + - "Asymetrie structurelle : Python 22 cellules code / 40 markdown (recompte au disque apres la tranche densite #13410 : 30 -> 40 md, markdown-only) ; C# 19 cellules code / 30 markdown. Arc identique (techniques d'inference + mesure de performance)." diff --git a/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0007-2026-09-18-myia-po-2026-CoursIA.yaml b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0007-2026-09-18-myia-po-2026-CoursIA.yaml new file mode 100644 index 0000000000..294c4c8096 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0007-2026-09-18-myia-po-2026-CoursIA.yaml @@ -0,0 +1,6 @@ +date: '2026-09-18' +by: myia-po-2026:CoursIA +python_sha: cd06b94b57cf4c78cd082f12ec1490e57b74ab10 +csharp_sha: 52f2308a75b2d73aaa3c6a330720d25cfd38f164 +content_python_sha: 82b77cb0eb2afe151d7118172aab8e574472d2b1c2a22c5a308e888c16a3331b +content_csharp_sha: 670cfa497b37661fc2e50f7918425fa5d4fe14b61682404a18e0477a93285fb9 diff --git a/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0008-2026-09-20-myia-po-2026-CoursIA.yaml b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0008-2026-09-20-myia-po-2026-CoursIA.yaml new file mode 100644 index 0000000000..e27ccd7a8e --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/sudoku-08-humanstrategies/0008-2026-09-20-myia-po-2026-CoursIA.yaml @@ -0,0 +1,6 @@ +date: '2026-09-20' +by: myia-po-2026:CoursIA +python_sha: 4d1d25d14effbcfc5059b0651871b89d43bf4b7e +csharp_sha: 52f2308a75b2d73aaa3c6a330720d25cfd38f164 +content_python_sha: a1296853faf0ffc6bee56ffcb423a47c1c6697db71d092b31c62839d3cfca8a8 +content_csharp_sha: 670cfa497b37661fc2e50f7918425fa5d4fe14b61682404a18e0477a93285fb9