Liens utiles
-
la liste des "Advent of Code"
Antisèches Go
Les bases
- opérations et comparaisons [AFFICHER]
-
opérations +,-,*,/pour les entiers et flottants,%(modulo) pour les entiers... ||(ou),&&(et),!(négation) pour les booléens... >>,<<(décalage),|,&(ou/et bit à bit),^(négation bit à bit et XOR bit à bit)... +(concaténation pour les chaines)comparaisons ==,!=,>,<,<=,>=pour les entiers, flottants ou chaines - types [AFFICHER]
-
types int8,int16,int32etint64entiers 8, 16, 32 ou 64 bits... variantes uint8, ...,uint64pour les entiers non signés ;byteest un synonyme deuint8... intetuintpour les entiers "machine" (32 ou 64 bits suivants l'architecture)... float32etfloat64pour les flottants 32 ou 64 bits... stringpour les chaines (non mutable, comme en Python)... []intpour les tableaux d'entiers,[][]float64pour les tableaux à 2 dimensions de flottants, etc.... map[string] intpour les dictionnaires avec chaines comme clés et des entiers comme valeurs, etc. - tableaux et dictionnaires [AFFICHER]
-
tableaux len(T)(taille),T[0]pour l'accès à une case... Attention T[i]provoque une erreur sii<0oui>=len(T)... T = append(T, 1)ouT = append(T, 1,2,3)pour ajouter des éléments à la fin d'un tableaudictionnaires D[k]renvoie la valeur associée à la clék, ou la valeur "zéro" si la clé n'est pas présente... v, ok = D[k]met la valeur deD[k]dansv, et un booléen dansok: vrai sikétait présente, faux sinoninitialisation (tableau) T := make([]int)déclare un tableau vide d'entiers... T := make([]int, 10)déclare un tableau d'entiers de taille 10, où toutes les cases ont la valeur "zéro"... T := []int{1,2,3}déclare un tableau d'entiers de taille 3, avec les éléments1,2et3initialisation (dictionnaire) D := make(map[string]int)déclare un dictionnaire vide... D := map[string]int{"un": 1, "deux": 2}déclare un dictionnaire - variables [AFFICHER]
-
variables (déclaration) var n int: déclaration sans initialisation (valeur par défaut: "zéro")... var n int = 10: déclaration avec initialisation... n := 10: déclaration simple, le type est inféré... Attention : x := 10ouvar x intpeuvent redéfinir une nouvelle variable dans un sous blocaffectation n = 10: affectation pour une variable existante... +=,-=, etc. permettent de faire une mise à joursx += 3est équivalent àx = x+3, etc.... i++eti--sont équivalents ài = i+1eti = i-1affectation multiple a,b,c = 1,2,3affectation de plusieurs variablesdéclaration multiple a,b,c := 1,2,3déclaration de plusieurs variables... Attention, dans a,b,c := 1,2,3seules les variables que l'on peut (re)déclarer sont déclarées; pour les autres, cela fait une affectation - fonctions [AFFICHER]
-
fonction func f(x float64, n int) {première ligne d'une définition de fonction à 2 arguments, sans valeur de retour... func f(n int) string {première ligne d'une définition de fonction à 1 argument, qui renvoie une chaine... func f(n int) (string, bool) {première ligne d'une définition de fonction à 1 argument, qui renvoie 2 valeurs... Attention, si frenvoie 2 valeurs, il faut utiliser 2 variables pour enregistrer le résultat :s, b := f(12).... On peut ignorer un des résultats avec _:s, _ := f(12) - boucles et conditionnelles [AFFICHER]
-
conditionnelles if <CONDITION> {...} else {...}... if <INIT>; <CONDITION> {...} else {...}permet de définir des variables (avec:=) uniquement pour la conditionnelleboucles for <INIT>; <CONDITION>; <MAJ> {...}... for <CONDITION> {...}(c'est la boucle while !)... for {...}pour une boucle infinie... continueetbreakfonctionnent comme d'habitude
Niveau 2
- compléments sur les dictionnaires / tableaux [AFFICHER]
-
sous tableaux T[debut:fin]est un tableau qui contient les valeurs deTdepuis les indices dedebut(inclu) àfin(exclu)... attention, contrairement à Python, les valeurs ne sont pas copiées, TetT[debut:fin]utilisent la même zone mémoireboucles for i := range T {...}permet de faire une boucle sur les indices du tableauxT... for i, v := range T {...}permet de faire une boucle sur les indices / valeurs du tableauT... for k := range D {...}permet de faire une boucle sur les clés du dictionnaireD... for k, v := range D {...}permet de faire une boucle sur les clés / valeurs du dictionnaireD - point virgules [AFFICHER]
-
En général, un retour chariot termine une instruction. Plus précisément :
-
le séparateur d'instruction
;est inséré à la fin d'une ligne si-
le token précédent est un identifiant,
-
le token précédent est un nombre ou une chaine (ou une "rune", càd un littéral unicode),
-
le token précédent est un des mots clé
break,continueoureturn(oufallthrough), -
le token précédent est
++,--,),},].
-
-
Un séparateur d'instruction
;peut être omis avant)ou}.
-
- structures et définitions de types [AFFICHER]
-
structures ex : struct {x int; y int; c string}type des structures à 3 champs, etc.... ex : s := struct{x int; y int; c string}{1,2,"rien"}pour définir une variable du type précédent... on accède aux champs avec s.x,s.yets.cdéfinition de type type <NOM> <TYPE>... type pointAnnot struct {x int; y int; c string}pour définir un type de structures... p := pointAnnot{1,2,"rien"}pour définir une variable dans le type correspondant... attention, il ne faut (en général) pas mettre de =entre<NOM>et<TYPE>méthodes func (p pointAnnot) m(<ARGUMENTS>) <RETOUR> {...}... le receiver est donné avant le nom de la fonction ... on peut définir des méthodes sur n'importe quel type qu'on a définit ... remarque : il n'y a pas d'héritage comme en POO - switch [AFFICHER]
-
switch <EXPR> {...}: les cas sont traités dans l'ordre et seul le premier cas égal à<EXPR>est utilisé (sauf si on utilise le mot cléfallthrough).Par exemple :
switch n { case 0: fmt.Println("zéro") case 1,2,3: fmt.Println("petit") case 4: fmt.Println("gros") case 5,6,7: fmt.Println("énorme") default: fmt.Println("???") }Comme pour
if, on peut ajouter une initialisation :switch <INIT>; <EXPR> {...}Attention, les instructions
breaketcontinueagissent sur lesswitch, on ne peut donc pas les utiliser directement pour sortir d'une boucle depuis l'intérieur d'unswitch.
Séance 1 (18-09-2025)
-
Vérifiez que go fonctionne correctement sur votre machine, par exemple en lançant la commande
$ go version -
Installez le plugin Go dans vscode, (ou un autre plugin dans un autre IDE).
-
Testez un programme de type hello world.
-
Connectez vous sur Advent of Code, par exemple avec votre compte Github.
-
Pour initialiser un nouveau module ("projet"), il faut lancer la commande
$ go mod init <NOM_DU_MODULE>dans le répertoire du module.
-
Votre fichier doit commencer par la ligne
package mainet un des fichiers du projets doit contenir une fonction
mainsans argument ni valeur de retour. -
Le mot clé pour définir une fonction est
func, et la fonction Go pour faire un affichage simple estfmt.Println. (Attention à ne pas oublier la majuscule !) Elle fonctionne comme la fonctionprintde Python. Vous pouvez aussi utiliserfmt.Printfpour avoir une fonction similaire àprintfdu langage C. Pour utiliserfmt.Println, il faut ajouterimport "fmt"en haut du du fichier. Normalement, vscode s'en chargera tout seul ! -
Si votre plugin Go est bien installé, votre code sera automatiquement formaté à chaque sauvegarde !
-
Pour lancer votre programme, il faut utiliser la commande
$ go run .ou le lancer à partir de vscode.
Écrivez un programme pour résoudre les problèmes suivants (parties 1 et 2).
| année | jours | lien |
|---|---|---|
| 2022 | 1 | Calorie Counting |
| 2020 | 2 | Password Philosophy |
| 2021 | 2 | Dive! |
Notez bien que pour obtenir vos fichier de données personnalisés, vous devez être connecté sur le site Advent of Code.
Un problème est résolu lorsque vous avez pu valider votre réponse sur le site et que vous avez obtenu les 2 étoiles "**" correspondantes. (Ou une seule étoile "*" pour les 25 décembre.)
Note : Eric Wastl, le créateur de Advent of Code, demande explicitement que les fichiers de données ne soient pas partagés sur Internet. Ne les mettez donc pas dans un dépot Git public.
Pour gagner du temps
- lecture des lignes d'un fichier
-
f, _ := os.Open(filename) sc := bufio.NewScanner(f) for sc.Scan() { line := sc.Text() ... } - conversion depuis une chaine
-
Les fonctions du module
strconvpermettent de convertir des chaines en entiers, flottants, etc. Parcourez la documentation des fonctionsstrconv.Atoi,strconv.ItoA,strconv.ParseBool,strconv.ParseFloat,strconv.ParseInt,strconv.ParseUinten cas de besoin.Attention, ces fonctions renvoient deux valeurs : le résultat et un code d'erreur. Pour ignorer ce dernier, il faut donc écrire :
var n int n, _ = strconv.Atoi(<CHAINE>) - documentation
-
Vous pouvez obtenir la documentation de la bibliothèque standard avec
$ go doc bufio $ go doc strconv.parsebool - extraction de valeurs d'une chaine formatée, à la scanf
-
var i, j int var color string fmt.Sscanf(s, "(%d,%d): %s", &i, &j, &color)Si
sest la chaine"(12,-123): rouge clair", les variablesietjauront les valeurs12et-123, et la variablecoloraura la valeur"rouge". - tri
-
La fonction
slices.Sortpermet de trier un tableau dans l'ordre croissant.
Travail à la maison
-
Commencez le tutoriel officiel
-
Parcourez les conseils de style officiels Go style guide et Go Style Decisions (notamment la partie sur les noms de variables).
-
Écrivez un programme qui utilise un dictionnaire et un programme qui utilise une structure (cf tutoriel), et réfléchissez aux différences entre ces 2 types de données.
-
Finissez les problèmes Advent of Code commencés :
2022 1 Calorie Counting 2020 2 Password Philosophy 2021 2 Dive!
Séance 2 (24-09-2025)
Écrivez des fonctions pour résoudre les problèmes suivants (parties 1 et 2).
| année | jours | lien |
|---|---|---|
| 2020 | 1 | Report Repair |
| 2016 | 1 | No Time for a Taxicab |
| 2015 | 4 | The Ideal Stocking Stuffer |
Pour chaque problème, définissez une fonction de type func (filename
string) int qui renverra la solution trouvée. Vous n'aurez qu'à
l'appeler dans votre fonction main avec le bon nom de fichier en
argument.
Pour gagner du temps
- lecture entière d'un fichier dans un tableau de
bytes -
T, _ = os.ReadFile(filename)Attention, en cas d'erreur (fichier inexistant, etc.),
Tsera vide. Pour gérer ça, il faut regarder la deuxième valeur de retour. Par exemple, le code suivant provoque une "panique" en cas d'erreur.T, err = os.ReadFile(filename) if err != nil { panic(err) } - les modules
stringsetbytes -
contiennent de nombreuses fonctions sur les chaines / tableaux d'octets :
Trim,Split,Join,HasPrefix, ...Utilisez les commandes go doc strings et go doc bytes pour avoir la liste de ces fonctions.
- l'empreinte MD5 d'un tableau
Td'octets (type[]byte) -
peut se calculer de la manière suivante
import "crypto/md5" ... E := md5.Sum(T)Econtiendra alors un tableau statique avec exactement 16 octets (type[16]byte).Attention, lors de la résolution du problème 2015-04, les "0" que vous devez chercher dans l'empreinte MD5 sont des "0" dans la représentation hexadécimale de l'empreinte. Chaque octet de l'empreinte donne deux chiffres hexadécimaux. Pour trouver cinq "0", il faut donc regarder deux octets et demi (20 bits) !
Travail à la maison
-
Finissez le tutoriel officiel, si ce n'est pas déjà fait.
-
Décrivez une manière de coder un type de tableaux dynamiques d'entiers en C pur, en utilisant
mallocetrealloc. Il s'agit d'un type avec les opérations suivantes :-
len(T): renvoie le nombre d'éléments du tableau, -
get(T, i): renvoie la case numéroi(indéterminé siine correspond pas à une case valide), -
set(T, i, v): mets la valeurv(un entier) dans la case numéroi(indéterminé siine correspond pas à une case valide), -
append(T, v): ajoute une valeurvà la fin du tableau. (La taille du tableau doit donc augmenter de 1.)
Réfléchissez également à la complexité de ces opérations.
-
-
Écrivez une méthode
showpour le typetype grid map[[2]int] byte: le dictionnaire contient des caractères ASCII (typebyte) à des coordonnées entières (type[2]int).La méthode
showdevra afficher les caractères à leur coordonnées, mais uniquement pour la boite englobante des coordonnées présentes dans le dictionnaire. Par exemple, pourG := grid(map[[2]int]byte{ {10, -7}: 'h', {11, -7}: 'e', {12, -7}: 'l', {13, -7}: 'l', {14, -7}: 'o', {14, -6}: 'w', {15, -6}: 'o', {16, -6}: 'r', {17, -6}: 'l', {18, -6}: 'd', }) G.show()on obtiendra
$ go run . hello worldVérifiez que votre code fonctionne en mettant le fichier mystere.go dans votre répertoire et en appelant
G := mystere() G.show() -
Finissez les problèmes Advent of Code commencés :
année jours lien 2020 1 Report Repair 2016 1 No Time for a Taxicab 2015 4 The Ideal Stocking Stuffer
Séance 3 (03-10-2025)
Écrivez des fonctions pour résoudre les problèmes suivants (parties 1 et 2).
| année | jours | lien |
|---|---|---|
| 2023 | 6 | Wait For It |
| 2021 | 13 | Transparent Origami |
Pour chaque problème, définissez une fonction de type func (filename
string) int (ou func (filename string) string) qui
renverra la solution trouvée. Vous n'aurez qu'à l'appeler dans votre fonction
main avec le bon nom de fichier en argument.
Pour gagner du temps
- découper une chaine
-
La fonction
strings.Splitpermet de découper une chaine à partir d'un séparateur.Lorsque le séparateur n'est pas fixe (par exemple une suite d'espaces dans le problème Wait For It), on peut parfois utiliser une expression régulière :
func main() { r := regexp.MustCompile(`[a-z]+`) fmt.Printf("résultat => %#v\n", r.Split("AbCDefGHIjklMnoQRSTuvWXYZ", -1)) }affichera
$ go run . résultat => []string{"A", "CD", "GHI", "M", "QRST", "WXYZ"}Remarque : l'utilisation des guillemets "
`" n'est pas réservé aux expressions régulières. Ils sont utilisés pour les chaines "brutes" sans interprétations des séquences d'échappement. Ils permettent, dans le cas des expressions régulières, l'utilisation de "\s" (caractères blancs), "\d" (chiffres), etc. sans que Go n'essaie de les interpréter (comme les "\n" par exemple). (Syntaxe des expressions régulières, ou go doc regexp/syntax)
Travail à la maison
-
Le problème Calorie Counting nécessitait de calculer les 3 valeurs maximales parmi une liste de nombres calculés.
-
Pour trouver les 3 valeurs maximales de
fsur les entiers0, ..., 999, on peut écrireT := []int{0,0,0} // les 3 valeurs maximales for i:=3; i<1000; i++ { // on ajoute la nouvelle valeur T = append(T, f(i)) // et on enlève la plus petite slices.Sort(T) T = T[1:4] } -
Expliquez pourquoi mon code initial ressemblait en fait à
T := []int{0,0,0} // les 3 valeurs maximales for i:=3; i<1000; i++ { // on ajoute la nouvelle valeur T = append(T, f(i)) // et on enlève la plus petite slices.Sort(T) T[0] = T[3] T = T[0:3] } -
Complétez le code suivant pour faire la même chose sans utiliser ni
slices.Sort, niappendn1, n2, n3 := 0, 0, 0 // les 3 valeurs maximales for i:=3; i<1000; i++ { // nouvelle valeur n4 := f(i) // on ne garde que les plus grandes ... } -
Pouvez vous mettre une différence de temps d'exécution en évidence ?
-
-
Comparez le temps d'exécution des 3 manières suivantes d'initialiser un tableau (dynamique) de taille
1000-
naïf :
T := make([]int, 0) for i := 0; i<1000; i++ { T = append(T, i) } -
en allouant directement un tableau de taille
1000T := make([]int, 1000) for i := 0; i<1000; i++ { T[i] = i } -
en allouant un tableau de taille
0et de capacité1000T := make([]int, 0, 1000) for i := 0; i<1000; i++ { T = append(T, i) }
-
-
Finissez les problèmes Advent of Code commencés :
année jours lien 2023 6 Wait For It 2021 13 Transparent Origami
Séance 4 (7-10-2025)
Écrivez des fonctions pour résoudre les problèmes suivants (parties 1 et 2).
| année | jours | lien |
|---|---|---|
| 2021 | 6 | Lanternfish |
| 2022 | 14 | Regolith Reservoir |
Pour chaque problème, définissez une fonction de type func (filename
string) int qui renverra la solution trouvée. Vous n'aurez qu'à
l'appeler dans votre fonction main avec le bon nom de fichier en
argument.
Pour gagner du temps
- lire les entiers dans un fichier
-
Mon fichier utils.go contient, entre autre, les fonctions
// ReadFile is a simple wrapper around os.ReadFile that panics in case of // error. func ReadFile(filename string) string { B, err := os.ReadFile(filename) if err != nil { panic(err) } return string(bytes.TrimSpace(B)) } // Atoi is a simple wrapper around strconv.Atoi that panics in case of error. func Atoi(s string) int { n, err := strconv.Atoi(s) if err != nil { panic(err) } return n } // ParseInts returns a list of integers read from the argument string `s`. // The argument `sep` is a regular expression used to match the separators. // No error checking or reporting is done and the function panics if one part // of the input string cannot be converted to an integer. func ParseInts(s, sep string) []int { var result []int sepRegex := regexp.MustCompile(sep) for _, n := range sepRegex.Split(strings.TrimSpace(s), -1) { result = append(result, Atoi(n)) } return result }Si vous les ajoutez dans votre module, vous pourrez récupérer la liste des entiers pour le premier problème avec
L := ParseInts(ReadFile(filename), ",")
Travail à la maison
-
Cherchez une solution efficace pour le problème Wait For It) de la séance précédente.
Pour tester, généralisez le problème de la manière suivante : au lieu de 2 lignes, le fichier contient plusieurs courses, chacune décrite sur 2 lignes. Vous devez faire la somme des nombres de manières de battre le record actuel pour chaque course.
Comme dans le problème original, pour la partie 2, concaténez les valeurs pour chaque paire de lignes.
Par exemple, le fichier test06_small contient les 3 courses suivantes
Time: 90 92 96 79 Distance: 1473 353 1918 413 Time: 88 63 96 87 Distance: 805 362 788 1470 Time: 87 74 92 78 Distance: 1042 599 1512 1364Pour la partie 2, vous devriez trouver les résultats suivants
-
Time = 90929679, Distance = 14733531918413 => 90605036
-
Time = 88639687, Distance = 8053627881470 => 88457784
-
Time = 87749278, Distance = 104259915121364 => 85339885
pour un total de 90605036+88457784+85339885 = 264402705.
Testez votre solution sur le fichier test06_big (1000 courses), test06_bigger (10000 courses), voir même sur le fichier test06_even_bigger (100000 courses).
-
-
Finissez les problèmes commencés en séance (parties 1 et 2) et le deuxième de la séance précédente.
année jours lien 2021 6 Lanternfish 2022 14 Regolith Reservoir -
Expliquez pourquoi le benchmark BenchmarkMax3Sort3Prefix est plus rapide que BenchmarkMax3Sort3Suffix. (Dans le fichier max3_test.go.)
Note : pour lancer le benchmark, copiez le fichier max3_test.go dans un dossier contenant un module Go, et utilisez la commande
$ go test -bench=Max3
Séances 5, 6, 7, ... (14-10-2025, ...) : mini projet
Pour les prochaines séances, chacun d'entre vous devra travailler sur un problème différent.
La colonne "objectifs" donne des pistes intéressantes à considérer. N'hésitez pas à nous demander si vous ne savez pas quoi faire.
Parmi les choses à envisager :
-
avoir une solution pour les deux parties de votre problème,
-
vérifiez que votre solution marche sur d'autres fichiers d'entrée,
-
écrire un générateur de fichiers d'entrée pour tester et comparer plusieurs solutions,
-
améliorer la complexité "pratique" de votre solution,
-
améliorer et mettre en évidence la complexité "théorique" de votre solution,
-
implémenter un algorithme connu pour le problème et le comparer à une version "naïve",
-
visualiser vos solutions de manière "sympa",
-
etc.
Chacun devra présenter son problème de manière simple et succincte (5 minutes) lors de la séance du 24 octobre.
Vous devrez également présenter votre travail lors de la dernière séance du 8 décembre. Chaque présentation devra durer une dizaine de minutes, et sera suivie de quelques minutes de questions.
| année | jours | lien | objectifs | ... | |
|---|---|---|---|---|---|
| 2024 | 7 | Bridge Repair | comparaison de plusieurs méthodes | choix d'opérateurs pour un résultat | Teva Philippe |
| 2023 | 12 | Hot Springs | solution récursive et solution automate | expression régulière "à l'envers" | Chloé Faucon |
| 2023 | 23 | A Long Walk | partie 2 en moins de 1s | plus long chemin dans un graphe | Vetea Stoll |
| 2024 | 23 | LAN Party | version "directe" et algorithme de Bron-Kerbosch | clique maximale | Gabriel Esat |
| 2024 | 20 | Race Condition | partie 2 efficace et plus générale | chemin dans un arbre | Mathieu Brunot |
| 2024 | 14 | Restroom Redoubt | partie 2 automatique et générale | découverte de motif visuel | Noah Cuneo |

