feat: add q1 and generator
parent
38ce009731
commit
9f0c677b6d
@ -0,0 +1,91 @@
|
||||
# No Time For Directions!
|
||||
|
||||
**Hermes** is the Greek god, and amongst others, he is the god of travel, trade, and athletes.
|
||||
Hermes has placed his hope in you.
|
||||
|
||||
You're dropped to a random location near Mount Cyllene in Arcadia, widely considered the birthplace
|
||||
of Hermes. After years of training, **You** are now set out on a quest. You must steal a key from
|
||||
**Hecate**, hidden near Mount Cyllene.
|
||||
|
||||
Unfortunately, "near", is as close as you know where you are. The instructions on the parchment
|
||||
Hermes gave begin from here, however, he never had the time to tell you how to follow them, or where
|
||||
they lead to.
|
||||
|
||||
The document has different markings that appear to tell you which direction to travel in. They
|
||||
indicate a direction, (`N`, `S`, `E` or `W`), and the number of steps you must take to find the
|
||||
hiding location.
|
||||
|
||||
The problem is, that there's over a 100 different directions, and there's no time following these
|
||||
directions one by one. It will take far too long! You take a moment and work out the final
|
||||
destination, so you can get more quickly. Given that you can only walk in the cardinal directions,
|
||||
what is the shortest path to the destination?
|
||||
|
||||
### Example
|
||||
|
||||
- Given the following input
|
||||
|
||||
|
||||
```
|
||||
N5
|
||||
E2
|
||||
S9
|
||||
W3
|
||||
```
|
||||
|
||||
Instructs you to to travel `5` steps North, `2` steps East, `9` steps South,
|
||||
and `3` steps West. Simplifying it, means `4` steps South, and `1` step West,
|
||||
or `5` steps away.
|
||||
|
||||
- Given the following input
|
||||
|
||||
```
|
||||
N6
|
||||
E5
|
||||
N5
|
||||
W3
|
||||
N4
|
||||
S9
|
||||
E4
|
||||
S1
|
||||
W6
|
||||
E3
|
||||
```
|
||||
|
||||
Leaves you `5` steps North, and `3` steps East, or `8` steps away.
|
||||
|
||||
Each line will have **at least 2** characters of input, the first being the direction, and
|
||||
the second being the number of steps. The number of steps on each line will
|
||||
always be between 1 and 9, inclusive, steps.
|
||||
|
||||
**How many steps away** is the key?
|
||||
|
||||
{{ if eq .Part 2 }}
|
||||
|
||||
**Congratulations! You got Part 1 correct. Your answer was `{{ .Answer1 }}`.**
|
||||
|
||||
## Part 2
|
||||
|
||||
After some more inspection of the instructions, you decipher the final clue. The final location of
|
||||
the steps lead you to a different location. However, the first location you visit **twice** is the
|
||||
location where the key is hidden.
|
||||
|
||||
### Example
|
||||
|
||||
Given the following input:
|
||||
|
||||
```
|
||||
S7
|
||||
W9
|
||||
E4
|
||||
N4
|
||||
S3
|
||||
E5
|
||||
S1
|
||||
```
|
||||
|
||||
The first location visit twice is `7` blocks away South.
|
||||
|
||||
With these new instructions, to find the key, **how many steps away is the first location you visit
|
||||
twice?**
|
||||
|
||||
{{ end }}
|
@ -1,67 +0,0 @@
|
||||
# No Time For Directions!
|
||||
|
||||
__Hermes__ is the Greek god, and amongst others, he is the god of travel, trade,
|
||||
and athletes. Hermes has placed his hope in you.
|
||||
|
||||
You're dropped to a random location near Mount Cyllene in Arcadia, widely
|
||||
considered the birthplace of Hermes. After years of training, **You** are now
|
||||
set out on a quest. You must steal a key from __Hecate__, hidden near Mount
|
||||
Cyllene.
|
||||
|
||||
Unfortunately, "near", is as close as you know where you are. The instructions
|
||||
on the parchment Hermes gave begin from here, however, he never had the time to
|
||||
tell you how to follow them, or where they lead to.
|
||||
|
||||
The document has different markings that appear to tell you which direction to
|
||||
travel in. They indicade a direction, (`N`, `S`, `E` or `W`), and the number of
|
||||
steps you must take to find the hiding location.
|
||||
|
||||
The problem is, that there's over a 100 different directions, and there's no
|
||||
time following these directions one by one. It will take far too long! You take
|
||||
a moment and work out the final destination, so you can get more quickly. Given
|
||||
that you can only walk in the cardinal directions, what is the shortest path to
|
||||
the destination?
|
||||
|
||||
### Example
|
||||
|
||||
- Given the following input
|
||||
|
||||
```
|
||||
N5
|
||||
E2
|
||||
S9
|
||||
W3
|
||||
```
|
||||
|
||||
Instructs you to to travel `5` steps North, `2` steps East, `9` steps South,
|
||||
and `3` steps West. Simplifying it, means `4` steps South, and `1` step West,
|
||||
or `5` steps away.
|
||||
|
||||
- Given the following input
|
||||
|
||||
```
|
||||
N6
|
||||
E5
|
||||
N5
|
||||
W3
|
||||
N4
|
||||
S9
|
||||
E4
|
||||
S1
|
||||
W6
|
||||
E3
|
||||
```
|
||||
|
||||
Leaves you `5` steps North, and `3` steps East, or `8` steps away.
|
||||
|
||||
Each line will have 2 characters of input, the first being the direction, and
|
||||
the second being the number of steps. The number of steps on each line will
|
||||
always be between 1 and 9, inclusive, steps.
|
||||
|
||||
**How many steps away** is the key?
|
||||
|
||||
{{ if ge .Step 2 }}
|
||||
|
||||
## Part 2
|
||||
|
||||
{{ end }}
|
@ -0,0 +1,150 @@
|
||||
package question
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hhhapz/codequest/models"
|
||||
)
|
||||
|
||||
func move(x, y int, dir byte, step int) (int, int) {
|
||||
switch dir {
|
||||
case 'N':
|
||||
return x, y + step
|
||||
case 'S':
|
||||
return x, y - step
|
||||
case 'E':
|
||||
return x + step, y
|
||||
case 'W':
|
||||
return x - step, y
|
||||
}
|
||||
return x, y
|
||||
}
|
||||
|
||||
func q1P1(steps []string) (x int, y int) {
|
||||
for _, step := range steps {
|
||||
dir := step[0]
|
||||
amt, _ := strconv.Atoi(step[1:])
|
||||
x, y = move(x, y, dir, amt)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func q1P2(steps []string) (x int, y int) {
|
||||
known := make(map[int]map[int]bool)
|
||||
|
||||
for _, step := range steps {
|
||||
dir := step[0]
|
||||
amt, _ := strconv.Atoi(step[1:])
|
||||
x, y = move(x, y, dir, amt)
|
||||
|
||||
if known[x] == nil {
|
||||
known[x] = make(map[int]bool)
|
||||
}
|
||||
if known[x][y] {
|
||||
return
|
||||
}
|
||||
known[x][y] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func q1Total(a, b int) int {
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
if b < 0 {
|
||||
b = -b
|
||||
}
|
||||
return a + b
|
||||
}
|
||||
|
||||
func init() {
|
||||
const directions = "NSWE"
|
||||
var q *Question
|
||||
q = &Question{
|
||||
ID: "directions",
|
||||
Text: q01Text,
|
||||
Level: Level1,
|
||||
Generate: func(u *models.User) string {
|
||||
res := make([]string, 0, 100)
|
||||
|
||||
r := userRandom(u)
|
||||
|
||||
known := make(map[int]map[int]bool)
|
||||
var x, y int
|
||||
for i := 0; i < 100; i++ {
|
||||
dir := directions[r.Intn(4)]
|
||||
steps := r.Intn(30) + 1
|
||||
newX, newY := move(x, y, dir, steps)
|
||||
|
||||
if known[newX] == nil {
|
||||
known[newX] = make(map[int]bool)
|
||||
}
|
||||
if known[newX][newY] {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
|
||||
known[newX][newY] = true
|
||||
x, y = newX, newY
|
||||
|
||||
res = append(res, fmt.Sprintf("%c%d", dir, steps))
|
||||
}
|
||||
|
||||
n := rand.Intn(20) + 10
|
||||
locX, locY := q1P1(res[:n])
|
||||
|
||||
dup := rand.Intn(20) + 35
|
||||
lastX, lastY := q1P1(res[:dup])
|
||||
|
||||
fmt.Println(locX, locY)
|
||||
fmt.Println(lastX, lastY)
|
||||
fmt.Println(dup)
|
||||
|
||||
dX := math.Max(float64(locX), float64(lastX)) - math.Min(float64(locX), float64(lastX))
|
||||
if locX > lastX {
|
||||
res[dup] = fmt.Sprintf("E%d", int(dX))
|
||||
dup++
|
||||
} else if locX < lastX {
|
||||
res[dup] = fmt.Sprintf("W%d", int(dX))
|
||||
dup++
|
||||
}
|
||||
|
||||
fmt.Println(res[dup-1])
|
||||
fmt.Println("!!")
|
||||
|
||||
if locY > lastY {
|
||||
res[dup] = fmt.Sprintf("N%d", int(math.Max(float64(locY), float64(lastY))-math.Min(float64(locY), float64(lastY))))
|
||||
} else if locY < lastY {
|
||||
res[dup] = fmt.Sprintf("S%d", int(math.Max(float64(locY), float64(lastY))-math.Min(float64(locY), float64(lastY))))
|
||||
}
|
||||
|
||||
return strings.Join(res, "\n")
|
||||
},
|
||||
Validate: func(u *models.User, level Part, input string) bool {
|
||||
inp := q.Generate(u)
|
||||
|
||||
lastX, lastY := q1P1(strings.Split(inp, "\n"))
|
||||
if level == Part1 {
|
||||
total := q1Total(lastX, lastY)
|
||||
return strconv.Itoa(total) == input
|
||||
}
|
||||
lastX, lastY = q1P2(strings.Split(inp, "\n"))
|
||||
if level == Part2 {
|
||||
total := q1Total(lastX, lastY)
|
||||
return strconv.Itoa(total) == input
|
||||
}
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
Register(q)
|
||||
}
|
||||
|
||||
//go:embed prompts/q01.md
|
||||
var q01Text string
|
@ -0,0 +1,29 @@
|
||||
package question
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hhhapz/codequest/models"
|
||||
)
|
||||
|
||||
func TestQ01(t *testing.T) {
|
||||
u := &models.User{
|
||||
ID: "0",
|
||||
}
|
||||
|
||||
q := QuestionByID("directions")
|
||||
|
||||
input := q.Generate(u)
|
||||
|
||||
fmt.Println("STAAART")
|
||||
x, y := q1P1(strings.Split(input, "\n"))
|
||||
fmt.Println("STAAART")
|
||||
|
||||
t.Logf("SOLUTION (P1): (%d, %d): %d", x, y, q1Total(x, y))
|
||||
x, y = q1P2(strings.Split(input, "\n"))
|
||||
t.Logf("SOLUTION (P2): (%d, %d): %d", x, y, q1Total(x, y))
|
||||
|
||||
fmt.Printf("INPUT: %v", input)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package question
|
||||
|
||||
func init() {
|
||||
Register(&Question{
|
||||
ID: "",
|
||||
Text: "",
|
||||
Level: 0,
|
||||
Generate: nil,
|
||||
Validate: nil,
|
||||
})
|
||||
}
|
@ -0,0 +1 @@
|
||||
package question
|
@ -1,13 +0,0 @@
|
||||
package question
|
||||
|
||||
import "github.com/hhhapz/codequest/models"
|
||||
|
||||
func init() {
|
||||
Register(&Question{
|
||||
ID: "directions",
|
||||
Text: ``,
|
||||
Level: 0,
|
||||
Generate: func(*models.User) string { panic("not implemented") },
|
||||
Validate: func(*models.User, string) bool { panic("not implemented") },
|
||||
})
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package question
|
||||
|
||||
import "github.com/hhhapz/codequest/models"
|
||||
|
||||
func init() {
|
||||
Register(&Question{
|
||||
ID: "",
|
||||
Text: "",
|
||||
Level: 0,
|
||||
Generate: func(*models.User) string { panic("not implemented") },
|
||||
Validate: func(*models.User, string) bool { panic("not implemented") },
|
||||
})
|
||||
}
|
@ -1,298 +0,0 @@
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: 0.1.0
|
||||
title: Swagger Hackathon
|
||||
description: A hackathon, hosted in JIS API specification created by Hamza Ali.
|
||||
contact:
|
||||
name: Hamza Ali
|
||||
email: me@hamzantal.pw
|
||||
license:
|
||||
name: MIT License
|
||||
url: "https://hamza.mit-license.org/"
|
||||
|
||||
paths:
|
||||
/auth/code:
|
||||
get:
|
||||
description: Generate oauth exchange url.
|
||||
tags: ["Auth"]
|
||||
operationId: gen oauth
|
||||
parameters:
|
||||
- name: callback
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uri
|
||||
responses:
|
||||
'200':
|
||||
description: OAuth Consent Page URI.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ConsentPage"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
/auth/authorize:
|
||||
get:
|
||||
description: Authorization response callback location.
|
||||
tags: ["Auth"]
|
||||
operationId: authorize callback
|
||||
parameters:
|
||||
- name: state
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: code
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'302':
|
||||
description: Redirect to webpage.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
format: uri
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
/auth/token:
|
||||
delete:
|
||||
tags: ["Auth"]
|
||||
operationId: delete token
|
||||
x-go-middlewares: ["token"]
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Token"
|
||||
- name: all
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: boolean
|
||||
responses:
|
||||
'204':
|
||||
description: User successfully logged out.
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
/users/me:
|
||||
get:
|
||||
description: Get self user information.
|
||||
tags: ["Users"]
|
||||
operationId: get me
|
||||
x-go-middlewares: ["token"]
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Token"
|
||||
responses:
|
||||
'200':
|
||||
description: User information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
put:
|
||||
description: Update self user.
|
||||
tags: ["Users"]
|
||||
operationId: modify user
|
||||
x-go-middlewares: ["token"]
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Token"
|
||||
requestBody:
|
||||
description: Modified user information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- grade_level
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
grade_level:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: New user data
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
/users/email:
|
||||
get:
|
||||
description: |-
|
||||
Get user info by email.
|
||||
Requires admin to get user info not equal to the owner of the token.
|
||||
tags: ["Users"]
|
||||
operationId: get user by email
|
||||
x-go-middlewares: ["token"]
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Token"
|
||||
- name: email
|
||||
in: query
|
||||
description: User email.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: email
|
||||
responses:
|
||||
'200':
|
||||
description: User information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
put:
|
||||
description: Update another user. Requires admin.
|
||||
tags: ["Users"]
|
||||
operationId: modify other user
|
||||
x-go-middlewares: ["token", "admin_token"]
|
||||
parameters:
|
||||
- name: token
|
||||
in: cookie
|
||||
description: User authentication token.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: email
|
||||
in: query
|
||||
description: User email.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: email
|
||||
requestBody:
|
||||
description: Modified user information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- email
|
||||
- picture
|
||||
- grade_level
|
||||
- teacher
|
||||
- admin
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
new_email:
|
||||
type: string
|
||||
format: email
|
||||
picture:
|
||||
type: string
|
||||
format: uri
|
||||
grade_level:
|
||||
type: integer
|
||||
teacher:
|
||||
type: boolean
|
||||
admin:
|
||||
type: boolean
|
||||
|
||||
responses:
|
||||
'200':
|
||||
description: User information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/User"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
/users/all:
|
||||
get:
|
||||
description: Get all users. Requires admin.
|
||||
tags: ["Users"]
|
||||
operationId: get all users
|
||||
x-go-middlewares: ["token", "admin_token"]
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Token"
|
||||
responses:
|
||||
'200':
|
||||
description: All user information.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/User"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultResponse"
|
||||
|
||||
components:
|
||||
parameters:
|
||||
Token:
|
||||
name: token
|
||||
in: cookie
|
||||
description: User authentication token.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
|
||||
responses:
|
||||
DefaultResponse:
|
||||
description: Unexpected server error or invalid user input.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
schemas:
|
||||
ConsentPage:
|
||||
type: object
|
||||
required:
|
||||
- url
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
format: uri
|
||||
User:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- email
|
||||
- picture
|
||||
- teacher
|
||||
- admin
|
||||
- created_at
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
picture:
|
||||
type: string
|
||||
format: uri
|
||||
grade_level:
|
||||
type: integer
|
||||
description: GradeLevel is only present if teacher is false.
|
||||
teacher:
|
||||
type: boolean
|
||||
admin:
|
||||
type: boolean
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
Error:
|
||||
type: object
|
||||
required:
|
||||
- message
|
||||
properties:
|
||||
message:
|
||||
type: string
|
Loading…
Reference in New Issue