chore: initialized initial repo for 2025 aoc
This commit is contained in:
parent
4b88583d23
commit
4ca16dabaa
10 changed files with 480 additions and 3 deletions
3
.envrc
3
.envrc
|
|
@ -1,3 +0,0 @@
|
|||
watch_file flake.nix flake.lock
|
||||
|
||||
use flake . --no-pure-eval
|
||||
49
2025/cmd/generate/cmd.go
Normal file
49
2025/cmd/generate/cmd.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func handleErr(err error, folder string) {
|
||||
os.RemoveAll(folder)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var GenerateCmd = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generate a new day directory",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
day, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
folder := fmt.Sprintf("./day%02d", day)
|
||||
if err := os.Mkdir(folder, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := generateMainCode(day); err != nil {
|
||||
handleErr(err, folder)
|
||||
}
|
||||
|
||||
if err := generateTestCode(day); err != nil {
|
||||
handleErr(err, folder)
|
||||
}
|
||||
|
||||
if err := retrieveInput(day); err != nil {
|
||||
handleErr(err, folder)
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("./day%02d/test.txt", day)
|
||||
if err := os.WriteFile(filename, []byte{}, 0755); err != nil {
|
||||
handleErr(err, folder)
|
||||
}
|
||||
},
|
||||
}
|
||||
92
2025/cmd/generate/fetch_input.go
Normal file
92
2025/cmd/generate/fetch_input.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
baseURL = "https://adventofcode.com/2025/day/%d/input"
|
||||
host = "adventofcode.com"
|
||||
userAgent = "github.com/C4theBomb/advent-of-code by c4patino@gmail.com"
|
||||
cookieEnvName = "COOKIE"
|
||||
)
|
||||
|
||||
func getCookie() (string, error) {
|
||||
cookieValue := os.Getenv(cookieEnvName)
|
||||
if cookieValue == "" {
|
||||
return "", fmt.Errorf("%s environment variable not set", cookieEnvName)
|
||||
}
|
||||
|
||||
return cookieValue, nil
|
||||
|
||||
}
|
||||
|
||||
func createHTTPClient(cookieValue string) (*http.Client, error) {
|
||||
jar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create cookie jar: %w", err)
|
||||
}
|
||||
|
||||
domainURL := &url.URL{Scheme: "https", Host: host}
|
||||
|
||||
client := &http.Client{Jar: jar}
|
||||
jar.SetCookies(domainURL, []*http.Cookie{{Name: "session", Value: cookieValue}})
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func fetchInput(client *http.Client, day int) ([]byte, error) {
|
||||
url := fmt.Sprintf(baseURL, day)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func retrieveInput(day int) error {
|
||||
cookieValue, err := getCookie()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := createHTTPClient(cookieValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body, err := fetchInput(client, day)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("./day%02d/input.txt", day)
|
||||
if err := os.WriteFile(filename, []byte(body), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
66
2025/cmd/generate/main_template.go
Normal file
66
2025/cmd/generate/main_template.go
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const mainCodeTemplate = `package day%02d
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
||||
func Part1() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func Part2() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func Run(filename string) (any, any) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
fmt.Println(line)
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
part1 := Part1()
|
||||
part2 := Part2()
|
||||
|
||||
return part1, part2
|
||||
}
|
||||
`
|
||||
|
||||
func generateMainCode(day int) error {
|
||||
testCode := fmt.Sprintf(mainCodeTemplate, day)
|
||||
|
||||
filename := fmt.Sprintf("./day%02d/day%02d.go", day, day)
|
||||
|
||||
if err := os.WriteFile(filename, []byte(testCode), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "fmt", filename)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
60
2025/cmd/generate/test_template.go
Normal file
60
2025/cmd/generate/test_template.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
const testCodeTemplate = `package day%02d
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
FileName string
|
||||
Part1 any
|
||||
Part2 any
|
||||
}
|
||||
|
||||
func TestDay%02d(t *testing.T) {
|
||||
tests := []TestCase{
|
||||
{"test.txt", -1, -1},
|
||||
// {"input.txt", -1, -1},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if _, err := os.Stat(test.FileName); os.IsNotExist(err) {
|
||||
t.Fatalf("test file does not exist: %%v", test.FileName)
|
||||
}
|
||||
|
||||
part1, part2 := Run(test.FileName)
|
||||
if test.Part1 != nil && part1 != test.Part1 {
|
||||
t.Fatalf("%%s: unexpected part1:\nwant:\t%%v\ngot:\t%%v", test.FileName, test.Part1, part1)
|
||||
}
|
||||
|
||||
if test.Part2 != nil && part2 != test.Part2 {
|
||||
t.Fatalf("%%s: unexpected part2:\nwant:\t%%v\ngot:\t%%v", test.FileName, test.Part2, part2)
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func generateTestCode(day int) error {
|
||||
testCode := fmt.Sprintf(testCodeTemplate, day, day)
|
||||
|
||||
filename := fmt.Sprintf("./day%02d/day%02d_test.go", day, day)
|
||||
|
||||
if err := os.WriteFile(filename, []byte(testCode), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "fmt", filename)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
61
2025/cmd/root.go
Normal file
61
2025/cmd/root.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"cpatino.com/advent-of-code/2025/cmd/generate"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var days = map[int]func(string) (any, any){}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "advent-of-code",
|
||||
Short: "Advent of Code 2024",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
day, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
file, _ := cmd.Flags().GetString("file")
|
||||
if file == "" {
|
||||
file = fmt.Sprintf("./day%02d/input.txt", day)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||
log.Fatalf("file does not exist: %s", file)
|
||||
}
|
||||
|
||||
log.Printf("Day: %d, Input File: %s\n", day, file)
|
||||
|
||||
part1, part2 := days[day](file)
|
||||
|
||||
log.Printf("Part 1: %v\n", part1)
|
||||
log.Printf("Part 2: %v\n", part2)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(generate.GenerateCmd)
|
||||
rootCmd.Flags().String("file", "", "Path to a file")
|
||||
}
|
||||
|
||||
func Execute() error {
|
||||
if len(os.Args) == 1 {
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
subCmd := os.Args[1]
|
||||
for _, cmd := range rootCmd.Commands() {
|
||||
if cmd.Use == subCmd {
|
||||
return cmd.Execute()
|
||||
}
|
||||
}
|
||||
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
118
2025/cmd/update/main.go
Normal file
118
2025/cmd/update/main.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const mainTemplate = `package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"cpatino.com/advent-of-code/2025/cmd/generate"
|
||||
|
||||
%s
|
||||
)
|
||||
|
||||
var days = map[int]func(string) (any, any){
|
||||
%s
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "advent-of-code",
|
||||
Short: "Advent of Code 2024",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
day, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
file, _ := cmd.Flags().GetString("file")
|
||||
if file == "" {
|
||||
file = fmt.Sprintf("./day%%02d/input.txt", day)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||
log.Fatalf("file does not exist: %%s", file)
|
||||
}
|
||||
|
||||
log.Printf("Day: %%d, Input File: %%s\n", day, file)
|
||||
|
||||
part1, part2 := days[day](file)
|
||||
|
||||
log.Printf("Part 1: %%v\n", part1)
|
||||
log.Printf("Part 2: %%v\n", part2)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(generate.GenerateCmd)
|
||||
rootCmd.Flags().String("file", "", "Path to a file")
|
||||
}
|
||||
|
||||
func Execute() error {
|
||||
if len(os.Args) == 1 {
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
subCmd := os.Args[1]
|
||||
for _, cmd := range rootCmd.Commands() {
|
||||
if cmd.Use == subCmd {
|
||||
return cmd.Execute()
|
||||
}
|
||||
}
|
||||
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
`
|
||||
|
||||
var imports, mappings strings.Builder
|
||||
|
||||
err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
|
||||
if !info.IsDir() || !strings.HasPrefix(info.Name(), "day") {
|
||||
return nil
|
||||
}
|
||||
|
||||
dayStr := strings.TrimPrefix(info.Name(), "day")
|
||||
|
||||
day, err := strconv.Atoi(dayStr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
imports.WriteString(fmt.Sprintf("\t\"cpatino.com/advent-of-code/2025/day%02d\"\n", day))
|
||||
mappings.WriteString(fmt.Sprintf("\t%d: day%02d.Run,\n", day, day))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
importsStr := strings.TrimSpace(imports.String())
|
||||
mappingsStr := strings.TrimSpace(mappings.String())
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Error walking the path:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mainCode := fmt.Sprintf(mainTemplate, importsStr, mappingsStr)
|
||||
|
||||
os.WriteFile("./cmd/root.go", []byte(mainCode), 0644)
|
||||
|
||||
cmd := exec.Command("go", "fmt", "./cmd/root.go")
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Println("Error running go fmt:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
10
2025/go.mod
Normal file
10
2025/go.mod
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module cpatino.com/advent-of-code/2025
|
||||
|
||||
go 1.23.3
|
||||
|
||||
require github.com/spf13/cobra v1.8.1
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
)
|
||||
10
2025/go.sum
Normal file
10
2025/go.sum
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
14
2025/main.go
Normal file
14
2025/main.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//go:generate go run ./cmd/update
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"cpatino.com/advent-of-code/2025/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
|
||||
cmd.Execute()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue