online quiz is the default

This commit is contained in:
2020-06-15 00:36:11 +02:00
parent f04d475023
commit 0613f5362a
12 changed files with 200 additions and 50 deletions

View File

@@ -1,6 +1,7 @@
- deploy
- now.sh, waiting for it to be purely front end
- purely front end except for mailing list
- remove repeated exercises
- make text inputs big enough for MAX_DIGITS_PROBLEMS and MAX_DIGITS_BITS
- show a message on submit
- show warning when specifying invalid number of bits or problems

View File

@@ -64,3 +64,30 @@ button:not(:disabled):active {
button:focus {
border-color: #666;
}
.inputs {
text-align: right; width: 2em; border: none; outline: none;
}
.primary-button {
cursor: pointer;
border: none;
background-color: dodgerblue;
color: white
}
.button {
cursor: pointer;
background-color: white;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance:textfield;
}

View File

@@ -1,9 +1,15 @@
<script>
import Inputs from "./Inputs.svelte";
import Quiz from "./Quiz.svelte";
import Inputs from "./components/Inputs.svelte";
import Quiz from "./components/Quiz.svelte";
import Tally from "./components/Tally.svelte";
import {activeQuiz} from './stores'
</script>
<main style="margin: 2em;">
<h1>Binary Quiz!</h1>
<Inputs />
<Quiz />
{#if ($activeQuiz)}
<Tally />
<Quiz />
{:else}
<Inputs />
{/if}
</main>

View File

@@ -1,45 +0,0 @@
<script>
import download from './utils/download.js'
import {
MIN_BITS, MAX_BITS, MIN_PROBLEMS, MAX_PROBLEMS, DEFAULT_BITS, DEFAULT_NUM_PROBLEMS ,
MAX_DIGITS_BITS, MAX_DIGITS_PROBLEMS
} from './config.js'
import { bits, num_problems } from './stores.js'
$: valid = ($bits || DEFAULT_BITS) <= MAX_BITS
&& ($bits || DEFAULT_BITS) >= MIN_BITS
&& ($num_problems || DEFAULT_NUM_PROBLEMS) >= MIN_PROBLEMS
&& ($num_problems || DEFAULT_NUM_PROBLEMS) <= MAX_PROBLEMS
const downloadAndClear = () => {
download($bits || DEFAULT_BITS, $num_problems || DEFAULT_NUM_PROBLEMS)
bits.update(() => null)
num_problems.update(() => null)
}
</script>
<form on:submit|preventDefault={downloadAndClear}>
<div id=inputs style="margin: 2em;">
<label>
<input
style="text-align: right; width: 2em; border: none; outline: none"
maxlength={MAX_DIGITS_BITS}
placeholder={DEFAULT_BITS}
autofocus
type=text bind:value={$bits}
>
Bits
</label>
<label>
<input
style="text-align: right; width: 2em; border: none; outline: none"
maxlength={MAX_DIGITS_PROBLEMS}
placeholder={DEFAULT_NUM_PROBLEMS}
type=text bind:value={$num_problems}
>
Number of Problems
</label>
</div>
<input disabled={!valid} type=submit style="cursor:pointer;" value="Download PDFs" >
</form>

View File

View File

@@ -0,0 +1,52 @@
<script>
import download from '../utils/download'
import {
MIN_BITS, MAX_BITS, MIN_PROBLEMS, MAX_PROBLEMS, DEFAULT_BITS, DEFAULT_NUM_PROBLEMS,
MAX_DIGITS_BITS, MAX_DIGITS_PROBLEMS
} from '../config'
import { bits, num_problems, valid, activeQuiz, problems } from '../stores'
import {generateProblems} from "../problems";
const downloadAndClear = () => {
download($bits || DEFAULT_BITS, $num_problems || DEFAULT_NUM_PROBLEMS)
bits.update(() => null)
num_problems.update(() => null)
}
const submit = () => {
const problems_ = generateProblems($bits, $num_problems)
problems.update(() => problems_)
activeQuiz.update(() => true)
}
</script>
<form on:submit|preventDefault={submit}>
<div id=inputs style="margin: 2em;">
<label>
<input
class="inputs"
max={MAX_BITS}
min={MIN_BITS}
placeholder={DEFAULT_BITS}
autofocus
type=number
bind:value={$bits}
>
Bits
</label>
<label>
<input
class="inputs"
max={MAX_PROBLEMS}
min={MIN_PROBLEMS}
placeholder={DEFAULT_NUM_PROBLEMS}
type=number
bind:value={$num_problems}
>
Number of Problems
</label>
</div>
<input class="primary-button" disabled={!$valid} type=submit value="Start Quiz" >
<input class="button" disabled={!$valid} type=button on:click={downloadAndClear} value="Download PDFs">
</form>

View File

@@ -0,0 +1,54 @@
<script>
import {checkAnswer} from "../problems";
import { bits, activeProblemIndex, tally, num_problems, activeQuiz } from '../stores'
export let problem
let displaySummary = false
let solution
let submitted = false
let class_ = ""
const check = () => {
if (checkAnswer(solution, problem)) {
submitted = true
if ($num_problems === $activeProblemIndex + 1) {
displaySummary = true
}
activeProblemIndex.update(() => $activeProblemIndex + 1)
tally.update(() => $tally + 1)
} else {
class_ = "incorrect"
}
solution = null
}
const reset = () => {
activeQuiz.update(() => false)
bits.update(() => null)
num_problems.update(() => null)
}
</script>
{#if displaySummary}
<div>Congratulations, you've completed {$num_problems} {$bits}-bit problems!</div>
<div><a on:click={reset}>Go back to home screen.</a></div>
{:else}
<form on:submit|preventDefault={check} class="{class_} problem">
<label>
{problem} =
<input autofocus type=number style="width: {$bits}em" bind:value={solution}>
</label>
<input type=submit style="visibility: hidden">
</form>
{/if}
<style>
.problem {
font-size: 3em;
display: flex;
flex-direction: row;
}
.incorrect {
border: dodgerblue;
}
</style>

View File

@@ -0,0 +1,7 @@
<script>
import {bits, num_problems, problems, activeProblemIndex} from '../stores.js'
import Problem from "./Problem.svelte";
</script>
<Problem problem={$problems[$activeProblemIndex]}/>

View File

@@ -0,0 +1,7 @@
<script>
import { tally, num_problems, bits } from '../stores'
</script>
<div>
{$tally}/{$num_problems}
</div>

View File

@@ -7,3 +7,7 @@ export const MAX_DIGITS_BITS = MAX_BITS.toString().length
export const DEFAULT_BITS = 8
export const DEFAULT_NUM_PROBLEMS = 20
export const getMaxPermutations = (bits) => {
return Math.pow(2, bits)
}

22
src/problems.js Normal file
View File

@@ -0,0 +1,22 @@
import {DEFAULT_BITS, DEFAULT_NUM_PROBLEMS} from "./config";
export const generateProblems = (bits, num_problems) => {
let probs = []
let counter = 0
while (counter < (num_problems || DEFAULT_NUM_PROBLEMS)) {
let problem = generateProblem(bits || DEFAULT_BITS)
if (probs.includes(problem)) {
continue
}
probs.push(problem)
counter++
}
return probs
}
export const generateProblem = bits => Array.from(Array(bits)).map((_, i) => Math.random() >= .5 ? '1' : '0').join('')
export const solveProblem = problem => parseInt(problem, 2)
export const checkAnswer = (answer, problem) => solveProblem(problem) === answer

View File

@@ -1,4 +1,19 @@
import { writable } from 'svelte/store'
import {derived, writable} from 'svelte/store'
import {generateProblem} from "./problems"
import {getMaxPermutations, MIN_BITS, MAX_BITS, MIN_PROBLEMS, MAX_PROBLEMS, DEFAULT_BITS, DEFAULT_NUM_PROBLEMS} from "./config"
export const bits = writable()
export const num_problems = writable()
export const activeQuiz = writable(false)
export const activeProblemIndex = writable(0)
export const tally = writable(0)
export const problems = writable([])
export const valid = derived([bits, num_problems], ([$bits, $num_problems]) => (
($bits || DEFAULT_BITS) <= MAX_BITS
&& ($bits || DEFAULT_BITS) >= MIN_BITS
&& ($num_problems || DEFAULT_NUM_PROBLEMS) >= MIN_PROBLEMS
&& ($num_problems || DEFAULT_NUM_PROBLEMS) <= MAX_PROBLEMS
&& ($num_problems || DEFAULT_NUM_PROBLEMS) <= getMaxPermutations($bits)
))