package main import ( "embed" "fmt" "html/template" "io/fs" "log" "net/http" "strconv" "bookworm/internal/solver" ) //go:embed web/templates/index.html web/static/styles.css var webAssets embed.FS type pageData struct { Letters string MinLength int Best *solver.Result Results []solver.Result Error string } func main() { engine, err := solver.NewEngine("words/words.txt") if err != nil { log.Fatalf("load dictionary: %v", err) } tmpl := template.Must(template.ParseFS(webAssets, "web/templates/index.html")) staticFS, err := fs.Sub(webAssets, "web/static") if err != nil { log.Fatalf("load static assets: %v", err) } mux := http.NewServeMux() mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS)))) mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { data := pageData{MinLength: 3} letters := request.URL.Query().Get("letters") if letters != "" { data.Letters = letters } if rawMinLength := request.URL.Query().Get("min"); rawMinLength != "" { minLength, convErr := strconv.Atoi(rawMinLength) if convErr != nil || minLength < 2 || minLength > 12 { data.Error = "Minimum length must be between 2 and 12." } else { data.MinLength = minLength } } if data.Letters != "" && data.Error == "" { results, solveErr := engine.FindMatches(data.Letters, data.MinLength, 20) if solveErr != nil { data.Error = solveErr.Error() } else if len(results) > 0 { data.Best = &results[0] data.Results = results[1:] } else { data.Error = "No words matched those letters in the current dictionary." } } if err := tmpl.Execute(writer, data); err != nil { http.Error(writer, fmt.Sprintf("render page: %v", err), http.StatusInternalServerError) } }) address := ":8080" log.Printf("Bookworm solver running at http://localhost%s", address) if err := http.ListenAndServe(address, mux); err != nil { log.Fatal(err) } }