mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
added scripts and 2020 folder
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
## 2020 Event
|
||||
|
||||
To run days for 2020, I'm planning on using `go test -run RegExpToMatchFunctionNames .` to make it cleaner to run the examples and inputs and not requiring 189203829048024 files for main packages
|
||||
|
||||
Scripts have also been added to the outer folder to setup files for a particular day more easily
|
||||
@@ -1,5 +1,6 @@
|
||||
### Scripts
|
||||
Addition for 2020 event.
|
||||
Note: need to make folder for the year first (`mkdir 2020`)
|
||||
|
||||
path|usage
|
||||
---|---
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// determine day to fetch
|
||||
day, year, cookie := fetchers.ParseFlags()
|
||||
fmt.Println("fetching for day", day)
|
||||
|
||||
// make the request
|
||||
url := fmt.Sprintf("https://adventofcode.com/%d/day/%d/input", year, day)
|
||||
body := fetchers.GetWithAOCCookie(url, cookie)
|
||||
|
||||
// write to file
|
||||
filename := filepath.Join(util.Dirname(), "../../..", fmt.Sprintf("%d/day%02d-input.txt", year, day))
|
||||
fetchers.WriteToFile(filename, body)
|
||||
|
||||
fmt.Println("Wrote to file: ", filename)
|
||||
|
||||
fmt.Println("Done!")
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// determine day to fetch
|
||||
day, year, cookie := fetchers.ParseFlags()
|
||||
fmt.Println("fetching for day", day)
|
||||
|
||||
// make the request
|
||||
url := fmt.Sprintf("https://adventofcode.com/%d/day/%d", year, day)
|
||||
body := fetchers.GetWithAOCCookie(url, cookie)
|
||||
|
||||
// parse the dang html
|
||||
prompt := parseHTML(body)
|
||||
|
||||
// write to file
|
||||
filename := filepath.Join(util.Dirname(), "../../../", fmt.Sprintf("%d/day%02d-prompt.md", year, day))
|
||||
fetchers.WriteToFile(filename, []byte(prompt))
|
||||
|
||||
fmt.Println("Wrote prompt to file: ", filename)
|
||||
|
||||
fmt.Println("Done!")
|
||||
}
|
||||
|
||||
// uses dfsHTML function once to get the class=day-desc html nodes, then parse
|
||||
// the text inside of them
|
||||
func parseHTML(htmlIn []byte) (promptOnly string) {
|
||||
strBuilder := strings.Builder{}
|
||||
node, _ := html.Parse(bytes.NewReader(htmlIn))
|
||||
|
||||
dayDescNodes := dfsHTML(node, cbFindDayDescClass)
|
||||
dayDescNodesMap := map[*html.Node]bool{}
|
||||
|
||||
for _, ddNode := range dayDescNodes {
|
||||
dayDescNodesMap[ddNode.(*html.Node)] = true
|
||||
dfsHTML(ddNode.(*html.Node), cbParseHTMLText(&strBuilder, dayDescNodesMap))
|
||||
}
|
||||
|
||||
return strBuilder.String()
|
||||
}
|
||||
|
||||
// function takes in a node and a callback that is run on each node
|
||||
// callback returns a slice of interfaces which are returned by dfs
|
||||
func dfsHTML(node *html.Node, cb func(*html.Node) []interface{}) []interface{} {
|
||||
var sli []interface{}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
if cb(child) != nil {
|
||||
sli = append(sli, child)
|
||||
}
|
||||
sli = append(sli, dfsHTML(child, cb)...)
|
||||
}
|
||||
return sli
|
||||
}
|
||||
|
||||
func cbFindDayDescClass(node *html.Node) []interface{} {
|
||||
for _, attr := range node.Attr {
|
||||
if attr.Key == "class" && attr.Val == "day-desc" {
|
||||
fmt.Println("day-desc node found!")
|
||||
return []interface{}{node}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cbParseHTMLText(builder *strings.Builder, dayDescNodesMap map[*html.Node]bool) func(*html.Node) []interface{} {
|
||||
return func(node *html.Node) []interface{} {
|
||||
if node.Type == html.TextNode {
|
||||
builder.WriteString(node.Data)
|
||||
}
|
||||
if node.Parent != nil && dayDescNodesMap[node.Parent] {
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package fetchers
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func panicWrap(err error, str string) {
|
||||
panic(fmt.Sprintf("%s: %s", str, err))
|
||||
}
|
||||
|
||||
func ParseFlags() (day, year int, cookie string) {
|
||||
flag.IntVar(&day, "day", time.Now().Day(), "day number to fetch, 1-25")
|
||||
flag.IntVar(&year, "year", 2020, "AOC year")
|
||||
flag.StringVar(&cookie, "cookie", os.Getenv("AOC_SESSION_COOKIE"), "AOC session cookie")
|
||||
flag.Parse()
|
||||
|
||||
if day > 25 {
|
||||
panic("day out of range")
|
||||
}
|
||||
|
||||
if cookie == "" {
|
||||
panic("No session cookie set on flag or env")
|
||||
}
|
||||
|
||||
return day, year, cookie
|
||||
}
|
||||
|
||||
func GetWithAOCCookie(url string, cookie string) []byte {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panicWrap(err, "making request")
|
||||
}
|
||||
|
||||
sessionCookie := http.Cookie{
|
||||
Name: "session",
|
||||
Value: cookie,
|
||||
}
|
||||
req.AddCookie(&sessionCookie)
|
||||
|
||||
cli := http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
}
|
||||
res, err := cli.Do(req)
|
||||
if err != nil {
|
||||
panicWrap(err, "making request")
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
fmt.Println("response length is", len(body))
|
||||
|
||||
if strings.HasPrefix(string(body), "Please don't repeatedly") {
|
||||
panic("Repeated request github.com/alexchao26/advent-of-code-go error")
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func WriteToFile(filename string, contents []byte) {
|
||||
err := ioutil.WriteFile(filename, contents, os.ModePerm)
|
||||
if err != nil {
|
||||
panicWrap(err, "writing file")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/scripts/fetchers"
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
type TemplateData struct {
|
||||
Year int
|
||||
Day string // a string to include the prefixing zero
|
||||
}
|
||||
|
||||
var testTemplateString = `package aoc{{.Year}}
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
func TestDay{{.Day}}Part1(t *testing.T) {
|
||||
// Run actual problem input
|
||||
day{{.Day}}Part1(util.ReadFile("./day{{.Day}}-input.txt"))
|
||||
}
|
||||
|
||||
func TestDay{{.Day}}Part2(t *testing.T) {
|
||||
// Run actual problem input
|
||||
day{{.Day}}Part2(util.ReadFile("./day{{.Day}}-input.txt"))
|
||||
}
|
||||
`
|
||||
|
||||
var solutionTemplateString = `package aoc{{.Year}}
|
||||
|
||||
func day{{.Day}}Part1(input string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func day{{.Day}}Part2(input string) int {
|
||||
return 0
|
||||
}
|
||||
`
|
||||
|
||||
func main() {
|
||||
day, year, _ := fetchers.ParseFlags()
|
||||
data := TemplateData{
|
||||
Year: year,
|
||||
Day: fmt.Sprintf("%02d", day),
|
||||
}
|
||||
|
||||
testTemp, err := template.New("test-template").Parse(testTemplateString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
solutionTemp, err := template.New("solution-template").Parse(solutionTemplateString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
solutionFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d.go", year, day))
|
||||
testFilename := filepath.Join(util.Dirname(), "../../", fmt.Sprintf("%d/day%02d_test.go", year, day))
|
||||
|
||||
EnsureNotOverwriting(solutionFilename)
|
||||
EnsureNotOverwriting(testFilename)
|
||||
|
||||
solutionWriter, err := os.Create(solutionFilename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testWriter, err := os.Create(testFilename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
solutionTemp.Execute(solutionWriter, data)
|
||||
testTemp.Execute(testWriter, data)
|
||||
fmt.Println("templates made")
|
||||
}
|
||||
|
||||
func EnsureNotOverwriting(filename string) {
|
||||
_, err := os.Stat(filename)
|
||||
if err == nil {
|
||||
panic(fmt.Sprintf("File already exists: %s", filename))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user