package q01 import ( _ "embed" "fmt" "strconv" "strings" "text/template" "github.com/hhhapz/codequest/models" "github.com/hhhapz/codequest/question" ) func init() { t := template.New("directions") var err error t, err = t.Parse(q01Text) if err != nil { panic(err) } question.Register( &question.Question{ ID: "directions", Name: "No Time for Directions!", Text: t, Level: question.Level1, Generate: func(u *models.User) string { return strings.Join(generate(u), "\n") }, Validate: func(u *models.User, part question.Part, solution string) bool { return Validate(u, part, solution) }, }) } func total(a, b int) int { if a < 0 { a = -a } if b < 0 { b = -b } return a + b } const ( // totalSteps in the input totalSteps = 100 // stepRange is the range of steps within each step stepRange = 30 // randRage is the range of steps between where the duplicate will be // present randRange = 20 // earliestCandidate the earliest step where the duplicate candidate is earliestCandidate = 10 // earliestDupe is the earliest step where the candidate is visited earliestDupe = 35 // directions for a step directions = "NSWE" ) func generate(u *models.User) []string { res := make([]string, 0, totalSteps) r := question.UserRandom(u) // known is used to disallow duplicate steps before the chosen dupe known := make(map[int]map[int]bool) var x, y int for len(res) != cap(res) { dir := directions[r.Intn(4)] steps := r.Intn(stepRange) + 1 newX, newY := move(x, y, dir, steps) if known[newX] == nil { known[newX] = make(map[int]bool) } if known[newX][newY] { continue } known[newX][newY] = true x, y = newX, newY res = append(res, fmt.Sprintf("%c%d", dir, steps)) } // the location of the candidate for the duplicate n := r.Intn(randRange) + earliestCandidate locX, locY := solveP1(res[:n]) // the location where the candidate is revisited n = r.Intn(randRange) + earliestDupe lastX, lastY := solveP2(res[:n]) // jump to the candidate if locX > lastX { res[n] = fmt.Sprintf("E%d", locX-lastX) n++ } else if locX < lastX { res[n] = fmt.Sprintf("W%d", lastX-locX) n++ } if locY > lastY { res[n] = fmt.Sprintf("N%d", locY-lastY) } else if locY < lastY { res[n] = fmt.Sprintf("S%d", lastY-locY) } return res } func Validate(u *models.User, p question.Part, sol string) bool { inp := generate(u) var t int switch p { case question.Part1: t = total(solveP1(inp)) case question.Part2: t = total(solveP2(inp)) default: return false } return strconv.Itoa(t) == sol } //go:embed q01.md var q01Text string