120 lines
2.0 KiB
Go
120 lines
2.0 KiB
Go
|
package q03
|
||
|
|
||
|
import (
|
||
|
_ "embed"
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"text/template"
|
||
|
|
||
|
"github.com/hhhapz/codequest/models"
|
||
|
"github.com/hhhapz/codequest/question"
|
||
|
)
|
||
|
|
||
|
type weightedChoice struct {
|
||
|
weight int
|
||
|
value int
|
||
|
}
|
||
|
|
||
|
func weightedRandom(choices []weightedChoice, r *rand.Rand) int {
|
||
|
var total int
|
||
|
for _, c := range choices {
|
||
|
total += c.weight
|
||
|
}
|
||
|
|
||
|
rnd := r.Intn(total)
|
||
|
for _, c := range choices {
|
||
|
if rnd < c.weight {
|
||
|
return c.value
|
||
|
}
|
||
|
rnd -= c.weight
|
||
|
}
|
||
|
panic("unreachable")
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
t := template.New("dragon")
|
||
|
var err error
|
||
|
t, err = t.Parse(q03Text)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
question.Register(
|
||
|
&question.Question{
|
||
|
ID: "dragon",
|
||
|
Name: "The Dragon Festival",
|
||
|
Text: t,
|
||
|
Level: question.Level1,
|
||
|
Generate: func(u *models.User) string {
|
||
|
inp := generate(u)
|
||
|
res := make([]string, rows)
|
||
|
|
||
|
for i, row := range inp {
|
||
|
for _, n := range row {
|
||
|
res[i] += strconv.Itoa(n)
|
||
|
}
|
||
|
}
|
||
|
return strings.Join(res, "\n")
|
||
|
},
|
||
|
Validate: func(u *models.User, part question.Part, solution string) bool {
|
||
|
return Validate(u, part, solution)
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
rows = 120
|
||
|
cols = 80
|
||
|
)
|
||
|
|
||
|
var numWeights = []weightedChoice{
|
||
|
{weight: 1, value: 0},
|
||
|
{weight: 4, value: 1},
|
||
|
{weight: 4, value: 2},
|
||
|
{weight: 4, value: 3},
|
||
|
{weight: 4, value: 4},
|
||
|
{weight: 4, value: 5},
|
||
|
{weight: 4, value: 6},
|
||
|
{weight: 2, value: 7},
|
||
|
{weight: 2, value: 8},
|
||
|
{weight: 1, value: 9},
|
||
|
}
|
||
|
|
||
|
func generate(u *models.User) [][]int {
|
||
|
res := make([][]int, rows)
|
||
|
|
||
|
r := question.UserRandom(u)
|
||
|
|
||
|
for i := 0; i < rows; i++ {
|
||
|
res[i] = make([]int, cols)
|
||
|
for j := 0; j < cols; j++ {
|
||
|
res[i][j] = weightedRandom(numWeights, r)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return res
|
||
|
}
|
||
|
|
||
|
func Validate(u *models.User, p question.Part, sol string) bool {
|
||
|
inp := generate(u)
|
||
|
|
||
|
var n int
|
||
|
switch p {
|
||
|
case question.Part1:
|
||
|
n = solveP1(inp)
|
||
|
case question.Part2:
|
||
|
n = solveP2(inp)
|
||
|
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
fmt.Println("submitted", sol)
|
||
|
fmt.Println("actual", n)
|
||
|
return strconv.Itoa(n) == sol
|
||
|
}
|
||
|
|
||
|
//go:embed q03.md
|
||
|
var q03Text string
|