diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/src/PU2213.html b/src/PU2213.html
new file mode 100644
index 0000000..4eb9d25
--- /dev/null
+++ b/src/PU2213.html
@@ -0,0 +1,17 @@
+
+
+
+ PU2213
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/data/puzzles.json b/src/data/puzzles.json
new file mode 100644
index 0000000..d22bd88
--- /dev/null
+++ b/src/data/puzzles.json
@@ -0,0 +1,18 @@
+{
+ "app": "PU2213",
+ "dateCreated": "2020-02-24",
+ "puzzles": [
+ {
+ "id": "e79679e7896",
+ "type": "SequencePuzzle",
+ "seed": 1582571656,
+ "dateEntered": "2020-02-24 19:14:16"
+ },
+ {
+ "id": "u383u833838",
+ "type": "SequencePuzzle",
+ "seed": 1582571877,
+ "dateEntered": "2020-02-24 19:17:57"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/js/app.js b/src/js/app.js
new file mode 100644
index 0000000..af9a1aa
--- /dev/null
+++ b/src/js/app.js
@@ -0,0 +1,16 @@
+import { Puzzles } from "./puzzles.js";
+
+export class App {
+ constructor() {
+ this.puzzles = new Puzzles();
+
+ this.loadData();
+ }
+
+ async loadData() {
+ await this.puzzles.fetch();
+
+ this.puzzles.computePuzzle( 0 );
+ this.puzzles.computePuzzle( 1 );
+ }
+}
\ No newline at end of file
diff --git a/src/js/mersennetwister.js b/src/js/mersennetwister.js
new file mode 100644
index 0000000..b8fb9c4
--- /dev/null
+++ b/src/js/mersennetwister.js
@@ -0,0 +1,70 @@
+// Code adapted to JS module. Original mersenne.js (c) 2014 Stephan Brumme.
+
+export class MersenneTwister {
+ constructor( seed ) {
+ this.state = new Array(624);
+ this.next = null;
+
+ if ( seed === undefined ) {
+ seed = 5489;
+ }
+
+ this.seed = seed;
+ this.state[ 0 ] = this.seed;
+
+ let s = null;
+ for ( let i = 1 ; i < 624; i++ ) {
+ s = this.state[ i - 1 ] ^ ( this.state[ i - 1 ] >>> 30);
+ this.state[ i ] = ( ( ( ( ( s & 0xffff0000 ) >>> 16 ) * 1812433253 ) << 16 ) +
+ ( s & 0x0000ffff ) * 1812433253 ) + i;
+
+ this.state[ i ] |= 0;
+ }
+
+ this.twist();
+ }
+
+ twist() {
+ let i = 0;
+ let bits = 0;
+
+ for ( i = 0; i < 227; i++ )
+ {
+ bits = ( this.state[ i ] & 0x80000000) | ( this.state[ i + 1 ] & 0x7fffffff);
+ this.state[ i ] = this.state[ i + 397 ] ^ ( bits >>> 1 ) ^ ( ( bits & 1 ) * 0x9908b0df );
+ }
+
+ for ( i = 227 ; i < 623; i++ )
+ {
+ bits = ( this.state[ i ] & 0x80000000) | ( this.state[ i + 1 ] & 0x7fffffff );
+ this.state[ i ] = this.state[ i - 227 ] ^ ( bits >>> 1 ) ^ ( ( bits & 1 ) * 0x9908b0df );
+ }
+
+ bits = ( this.state[ 623 ] & 0x80000000 ) | ( this.state[ 0 ] & 0x7fffffff );
+ this.state[ 623 ] = this.state[ 396 ] ^ ( bits >>> 1 ) ^ ( ( bits & 1 ) * 0x9908b0df );
+
+ this.next = 0;
+ }
+
+ random = function() {
+ if ( this.next >= 624 ) {
+ this.twist();
+ }
+
+ let x = this.state[ this.next++ ];
+ x ^= x >>> 11;
+ x ^= (x << 7) & 0x9d2c5680;
+ x ^= (x << 15) & 0xefc60000;
+ x ^= x >>> 18;
+
+ return x;
+ }
+
+ randomRange( min, max ) {
+ let x = Math.abs( this.random() );
+ let l = Math.pow( 10, x.toString().length );
+ let y = Math.round( ( Math.floor( ( x / l ) * ( Math.floor( max * 100 ) - Math.ceil( min * 10 ) ) ) + Math.ceil( min * 10 ) ) / 100 );
+
+ return y;
+ }
+}
\ No newline at end of file
diff --git a/src/js/puzzles.js b/src/js/puzzles.js
new file mode 100644
index 0000000..e2f36df
--- /dev/null
+++ b/src/js/puzzles.js
@@ -0,0 +1,31 @@
+import { SequencePuzzle } from "./puzzles/sequencepuzzle.js";
+
+export class Puzzles {
+ constructor() {
+ this.data = null;
+ }
+
+ async fetch() {
+ let response = await fetch( "./data/puzzles.json" );
+ this.data = await response.json();
+ }
+
+ dynamicPuzzle( name ) {
+ let puzzleClasses = { SequencePuzzle };
+ let className = puzzleClasses[ name ];
+
+ return className;
+ }
+
+ computePuzzle( puzzleIndex ) {
+ if ( this.data !== null &&
+ typeof this.data.puzzles !== "undefined" &&
+ this.data.puzzles.length > puzzleIndex )
+ {
+ let puzzleData = this.data.puzzles[ puzzleIndex ];
+ let puzzleClass = this.dynamicPuzzle( puzzleData.type );
+
+ let puzzleInstance = new puzzleClass( puzzleData );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/js/puzzles/sequencepuzzle.js b/src/js/puzzles/sequencepuzzle.js
new file mode 100644
index 0000000..7152f78
--- /dev/null
+++ b/src/js/puzzles/sequencepuzzle.js
@@ -0,0 +1,31 @@
+import { MersenneTwister } from "../mersennetwister.js";
+
+export class SequencePuzzle {
+ constructor( puzzleData ) {
+ this.puzzleData = puzzleData;
+
+ this.mersennetwister = new MersenneTwister( this.puzzleData.seed );
+ this.operators = [
+ "ADD"
+ ];
+
+ this.length = Math.round( this.mersennetwister.randomRange( 30, 70 ) / 10 );
+ this.answerposition = ( Math.floor( this.mersennetwister.randomRange( 15, this.length * 500 ) / 10 ) - 1 ) % this.length;
+ this.operator = this.operators[ ( Math.floor( this.mersennetwister.randomRange( 15, this.length * 500 ) / 10 ) - 1 ) % this.operators.length ];
+ this.factor = Math.round( this.mersennetwister.randomRange( 10, 100 ) / 10 );
+ this.start = Math.round( this.mersennetwister.randomRange( 10, 97 ) / 10 );
+
+ this.parts = new Array( this.length );
+ this.parts[ 0 ] = this.start;
+
+ for ( var i = 1; i < this.length; i++ ) {
+ this.parts[ i ] = this.parts[ i - 1] + this.factor;
+ }
+
+ this.answer = this.parts[ this.answerposition ];
+ this.parts[ this.answerposition ] = "?";
+
+ console.log( "Puzzle id: " + this.puzzleData.id + " (seed: " + this.puzzleData.seed + ")" );
+ console.log( this.parts.join( " " ) );
+ }
+}
\ No newline at end of file