master
ALI Hamza 2022-04-29 13:56:26 +07:00
parent 8128450d54
commit 44b67f0de4
Signed by: hamza
GPG Key ID: 22473A32291F8CB6
16 changed files with 540 additions and 17 deletions

@ -19,6 +19,8 @@ import (
_ "github.com/hhhapz/codequest/question/q01" _ "github.com/hhhapz/codequest/question/q01"
_ "github.com/hhhapz/codequest/question/q02" _ "github.com/hhhapz/codequest/question/q02"
_ "github.com/hhhapz/codequest/question/q03" _ "github.com/hhhapz/codequest/question/q03"
_ "github.com/hhhapz/codequest/question/q04"
_ "github.com/hhhapz/codequest/question/q05"
) )
func run() error { func run() error {

@ -13,7 +13,7 @@ import (
) )
func init() { func init() {
t := template.New("saturnalia") t := template.New("summer")
var err error var err error
t, err = t.Parse(q02Text) t, err = t.Parse(q02Text)
if err != nil { if err != nil {
@ -21,8 +21,8 @@ func init() {
} }
question.Register( question.Register(
&question.Question{ &question.Question{
ID: "saturnalia", ID: "summer",
Name: "Saturnalia's Problem", Name: "Summer Scheduling",
Text: t, Text: t,
Level: question.Level1, Level: question.Level1,
Generate: func(u *models.User) string { Generate: func(u *models.User) string {

@ -14,7 +14,7 @@ func TestQ02(t *testing.T) {
ID: "1203120957198056", ID: "1203120957198056",
} }
q := question.QuestionByID("saturnalia") q := question.QuestionByID("summer")
raw := q.Generate(u) raw := q.Generate(u)
var input []int var input []int

@ -75,12 +75,8 @@ Using this information, the maximums of the rows and columns is `25` ad `20`.
The answer, and the dragon number, is `25*20 = 500`. The answer, and the dragon number, is `25*20 = 500`.
---
**What is the dragon number for your lake?** **What is the dragon number for your lake?**
### Example
{{ if .Part2.Completed -}} {{ if .Part2.Completed -}}
**Congratulations! You have completed both parts! The answer was `{{ .Part2.Solution }}`.** **Congratulations! You have completed both parts! The answer was `{{ .Part2.Solution }}`.**

@ -0,0 +1,23 @@
package q04
func waterCorners(grid [][]rune, x, y int) int {
isWater := func(x, y int) int {
if x < 0 || y < 0 || x >= len(grid) || y >= len(grid[x]) || grid[x][y] == ' ' {
return 1
}
return 0
}
return isWater(x-1, y) + isWater(x+1, y) + isWater(x, y-1) + isWater(x, y+1)
}
func solveP1(grid [][]rune) int {
var ps int
for x := range grid {
for y := range grid[x] {
if waterCorners(grid, x, y) == 3 {
ps++
}
}
}
return ps
}

@ -0,0 +1,37 @@
package q04
func check(x, y, n, m int) bool {
return x >= 0 && y >= 0 && x < n && y < m
}
var dirs = [][]int{{-1, 0}, {0, -1}, {1, 0}, {0, 1}}
func dfs(grid [][]rune, vis [][]bool, x, y, n, m int) {
if !check(x, y, n, m) || grid[x][y] == ' ' || vis[x][y] {
return
}
vis[x][y] = true
for _, d := range dirs {
x1, y1 := x+d[0], y+d[1]
dfs(grid, vis, x1, y1, n, m)
}
}
func solveP2(grid [][]rune) int {
var res int
n := len(grid)
m := len(grid[0])
vis := make([][]bool, n)
for i := range vis {
vis[i] = make([]bool, m)
}
for i := range grid {
for j := range grid[i] {
if !vis[i][j] && grid[i][j] == 'X' {
res++
dfs(grid, vis, i, j, n, m)
}
}
}
return res
}

@ -0,0 +1,108 @@
package q04
import (
_ "embed"
"fmt"
"math/rand"
"strconv"
"strings"
"text/template"
"github.com/hhhapz/codequest/models"
"github.com/hhhapz/codequest/question"
)
type boolgen struct {
src *rand.Rand
cache int64
remaining int
}
func (b *boolgen) Bool() bool {
if b.remaining == 0 {
b.cache, b.remaining = b.src.Int63(), 63
}
result := b.cache&0x01 == 1
b.cache >>= 1
b.remaining--
return result
}
func init() {
t := template.New("island")
var err error
t, err = t.Parse(q03Text)
if err != nil {
panic(err)
}
question.Register(
&question.Question{
ID: "island",
Name: "Island Analysis",
Text: t,
Level: question.Level2,
Generate: func(u *models.User) string {
inp := generate(u)
res := make([]string, 0, rows)
for _, row := range inp {
res = append(res, string(row))
}
return strings.Join(res, "\n")
},
Validate: func(u *models.User, part question.Part, solution string) bool {
return Validate(u, part, solution)
},
})
}
const (
rows = 90
cols = 50
)
func generate(u *models.User) [][]rune {
res := make([][]rune, rows)
b := boolgen{
src: question.UserRandom(u),
}
for i := 0; i < rows; i++ {
res[i] = make([]rune, cols)
for j := 0; j < cols; j++ {
m := 'X'
if b.Bool() {
m = ' '
}
res[i][j] = m
}
}
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", u.Name, p, sol)
fmt.Println("actual", u.Name, p, n)
return strconv.Itoa(n) == sol
}
//go:embed q04.md
var q03Text string

@ -0,0 +1,107 @@
You decide to visit the archipelagos of Indonesia. You find a map of the area near South Sulawesi,
and can see where there is land (marked with an `X`), and where the ocean is (empty space).
You and your friends decide you want to stay at the islands for the weekend.
However, there are so many islands to pick from, and you have no way to decide which one to pick to
stay at. To make a decision, you come up with a plan.
Firstly, you have decided that the location needs to be a peninsula. That means, water on 3 sides,
and land on one side.
### Note:
> When counting peninsulas, do not consider diagonal tiles. Only consider those directly to the left,
> right, above and below the tile.
> The (invisible) edges of the input all count after the water tiles.
### Example
Given the following input:
```
ABCDE
1. X XX
2. X X
3. X
4. XX X
```
Contains 4 peninsulas:
* 1D
* 3D
* 4A
* 4B
---
Given the following input:
```
ABCDEFGH
1 XXX XX
2 X XX X
3 XXXXX X
4 X X
5 X XXXX
6 XX XXXX
```
Contains 9 peninsulas:
* 1C
* 1H
* 2B
* 3A
* 4D
* 5A
* 5H
* 6B
* 6D
To get the answer for part one, **what is the total number of peninsulas you can count on your
map?**
{{ if .Part1.Completed -}}
**Congratulations! You got Part 1 correct. Your answer was `{{ .Part1.Solution }}`.**
## Part 2
With the number of peninsulas that are in the lake, you are having trouble determining which one to
pick. In order to do so, you have devised a plan to try to see which island has the most number of
peninsulas.
In order to do this, though, we first need to count how many islands we have.
An island is a contiguous set of grids, that are connected by water in at least one of the four
directions, similar to a peninsula.
### Example
Given the following input:
```
ABCDEFGH
1 XXX XX
2 X XX X
3 XXXXX X
4 X X
5 X XXXX
6 XX XXXX
```
There are 3 distinct islands.
**What is the total number of islands in your map?**
{{ if .Part2.Completed -}}
**Congratulations! You have completed both parts! The answer was `{{ .Part2.Solution }}`.**
{{- end }}
{{- end }}

@ -0,0 +1,43 @@
package q04
import (
"strconv"
"strings"
"testing"
"github.com/hhhapz/codequest/models"
"github.com/hhhapz/codequest/question"
)
func TestQ04(t *testing.T) {
u := &models.User{
ID: "123",
}
q := question.QuestionByID("island")
raw := q.Generate(u)
t.Logf("INPUT:\n\n%s\n\n", raw)
input := make([][]rune, 0, rows)
for _, row := range strings.Split(raw, "\n") {
input = append(input, []rune(row))
}
// res := solveP1(input)
// t.Logf("part 1 result: %d", res)
// if !q.Validate(u, question.Part1, strconv.Itoa(res)) {
// t.Errorf("Expected question 1 part 1(%v) to be correct!", res)
// }
res := solveP2(input)
if !q.Validate(u, question.Part2, strconv.Itoa(res)) {
t.Errorf("Expected question 2 part 2(%v) to be correct!", res)
}
if q.Validate(u, question.Part1, "") {
t.Errorf("Expected bad input to be invalid")
}
}

@ -0,0 +1,9 @@
package q05
func solveP1(nums []int) int {
var sum int
for _, v := range nums {
sum += int(float64(v)/2.5 - 2)
}
return sum
}

@ -0,0 +1,13 @@
package q05
func solveP2(nums []int) int {
var sum int
for _, v := range nums {
fuel := int(float64(v)/2.5 - 2)
for fuel > 0 {
sum += fuel
fuel = int(float64(fuel)/2.5 - 2)
}
}
return sum
}

@ -0,0 +1,81 @@
package q05
import (
_ "embed"
"fmt"
"strconv"
"strings"
"text/template"
"github.com/hhhapz/codequest/models"
"github.com/hhhapz/codequest/question"
)
func init() {
t := template.New("fuel")
var err error
t, err = t.Parse(q05Text)
if err != nil {
panic(err)
}
question.Register(
&question.Question{
ID: "fuel",
Name: "Fuel for the Farlands",
Text: t,
Level: question.Level1,
Generate: func(u *models.User) string {
inp := generate(u)
nums := make([]string, nums)
for i, num := range inp {
nums[i] = strconv.Itoa(num)
}
return strings.Join(nums, "\n")
},
Validate: func(u *models.User, part question.Part, solution string) bool {
return Validate(u, part, solution)
},
})
}
const (
nums = 350
)
func generate(u *models.User) []int {
res := make([]int, nums)
r := question.UserRandom(u)
for i := 0; i < nums; i++ {
if nums < 10 {
res[i] = r.Intn(10000-200) + 200
continue
}
res[i] = r.Intn(1000000-1000) + 1000
}
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", u.Name, p, sol)
fmt.Println("actual", u.Name, p, n)
return strconv.Itoa(n) == sol
}
//go:embed q05.md
var q05Text string

@ -0,0 +1,68 @@
The time has arrived and you need to pack things up and say goodbye. You are leaving for the
Farlands, and it's.. far!
You plan to fly solo over the continents to make it to the Farlands. This is the first time you've
ever flown for so long, and so you need to prepare a few things before leaving.
The first order of business is to determine how much fuel you're going to need to reach. To do this,
you need the empty mass of your aircraft.
With the mass, you can calculate the total required fuel.
For each each mass, the amount of fuel can be calculated using this **formula**. Take the mass,
divide it by 2.5, round down the result, and then subtract 2.
Before taking off, your friends and family have sent you hundreds of gifts, which you plan to take
with you. You'll need to know the total amount of fuel needed for your trip.
Apply the formula for each item (your input), and sum them to get the total requirement.
### Example
For a mass of `18`, divide it by `2.5` and round down to get `7`, then subtract `2` to get `5` as
the fuel requirement.
For a mass of `58`, divide it by `2.5` and round down to get `23`, then subtract `2` to get `21`.
For `2022`, the requirement is `806`
For `84942`, the requirement is `33974`
**What is the total fuel requirement for your trip?**
{{ if .Part1.Completed -}}
**Congratulations! You got Part 1 correct. Your answer was `{{ .Part1.Solution }}`.**
## Part 2
Just before you about to take off, your copilot reminded you that you completely forgot to take into
account the extra fuel needed for the fuel you already have! Just like your parting gifts, apply the
same **formula** on the fuel to obtain the fuel needed for the fuel.
So, for each gift, calculate the fuel needed, treat that fuel as the mass itself, and calculate the
fuel needed, and repeat this process **until** your fuel requirement reaches **zero or a negative
value**.
### Example
For a mass of `18`, divide it by `2.5` and round down to get `7`, then subtract `2` to get `5` as
the fuel requirement. `5` divided by `2.5` gives you `1`, and subtracting `2` gives you `-1` so the
total fuel required is still `5`.
For a mass of `58`, `21` fuel is used. Then, `21` needs `6` more fuel, and `6` requires no further
fuel. The total fuel needed is `21+6 = 27`
For `2022`, the requirement is `806+320+126+48+17+4 = 1321`
Using this new formula, **what is the fuel total fuel requirements** for all the mass, but also
including the mass of the newly added fuel?
> Calculate the requirements seperately, and them sum them together for each item.
{{ if .Part2.Completed -}}
**Congratulations! You have completed both parts! The answer was `{{ .Part2.Solution }}`.**
{{- end }}
{{- end }}

@ -0,0 +1,44 @@
package q05
import (
"strconv"
"strings"
"testing"
"github.com/hhhapz/codequest/models"
"github.com/hhhapz/codequest/question"
)
func TestQ05(t *testing.T) {
u := &models.User{
ID: "123",
}
q := question.QuestionByID("fuel")
raw := q.Generate(u)
t.Logf("INPUT:\n\n%s\n\n", raw)
input := make([]int, 0, nums)
for _, num := range strings.Split(raw, "\n") {
n, _ := strconv.Atoi(num)
input = append(input, n)
}
res := solveP1(input)
t.Logf("part 1 result: %d", res)
if !q.Validate(u, question.Part1, strconv.Itoa(res)) {
t.Errorf("Expected question 1 part 1(%v) to be correct!", res)
}
res = solveP2(input)
if !q.Validate(u, question.Part2, strconv.Itoa(res)) {
t.Errorf("Expected question 2 part 2(%v) to be correct!", res)
}
if q.Validate(u, question.Part1, "") {
t.Errorf("Expected bad input to be invalid")
}
}

@ -47,7 +47,6 @@ const (
Part2 Part2
) )
// TODO: Internal autoincrement id
func UserRandom(u *models.User) *rand.Rand { func UserRandom(u *models.User) *rand.Rand {
id := u.ID id := u.ID
if len(id) > 17 { if len(id) > 17 {

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { Difficulty, type Question } from '../pb/all.pb'; import type { Question } from '$lib/pb/all.pb';
export let q: Question; export let q: Question;
type Status = 'available' | 'partial' | 'full'; type Status = 'available' | 'partial' | 'full';
@ -24,13 +24,6 @@
<span class="title">{q.title} - {solved}/2</span> <span class="title">{q.title} - {solved}/2</span>
<div class="flex justify-between"> <div class="flex justify-between">
<span class="points">Points: {q.part1.pointsWorth + q.part2.pointsWorth}</span> <span class="points">Points: {q.part1.pointsWorth + q.part2.pointsWorth}</span>
<span class="difficulty">
{#if q.difficulty == Difficulty.Level1}
Difficulty: 1
{:else if q.difficulty == Difficulty.Level2}
Difficulty: 2
{/if}
</span>
</div> </div>
</a> </a>