diff --git a/mj/.idea/.gitignore b/mj/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/mj/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/mj/.idea/misc.xml b/mj/.idea/misc.xml
new file mode 100644
index 0000000..28a804d
--- /dev/null
+++ b/mj/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mj/.idea/mj.iml b/mj/.idea/mj.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/mj/.idea/mj.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mj/.idea/modules.xml b/mj/.idea/modules.xml
new file mode 100644
index 0000000..45d0b26
--- /dev/null
+++ b/mj/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mj/card.js b/mj/card.js
new file mode 100644
index 0000000..92b95a9
--- /dev/null
+++ b/mj/card.js
@@ -0,0 +1,97 @@
+let x1 = 0;
+let x2 = 1000;
+let y1 = 0;
+let y2 = 1000;
+
+const width = 150;
+const height = 220;
+const hw = width / 2;
+const hh = height / 2;
+const r = Math.sqrt(width * width + height * height) / 2;
+const a = Math.asin(hw / r) * 180 / Math.PI;
+class Card {
+ constructor(word, clickHandler, setId, cardId) {
+ this.word = word;
+ this.setId = setId;
+ this.cardId = cardId;
+ this._onCLick = clickHandler;
+ this.selected = false;
+
+ this._rotation = 0;
+ this.element = document.createElement("div");
+ this.element.classList.add("card");
+ this.element.innerText = word;
+
+ this.x = 0;
+ this.y = 0;
+
+ this.element.addEventListener("click", this._onElementClick.bind(this));
+ }
+ destructor() {
+ this.element.remove();
+ }
+ select() {
+ if (!this.selected) {
+ this.element.classList.add("selected");
+ this.selected = true;
+ }
+ }
+ unselect() {
+ if (this.selected) {
+ this.element.classList.remove("selected");
+ this.selected = false;
+ }
+ }
+ disrotate() {
+ let angle = Math.random() * 150 - 75;
+ this.rotate(angle);
+ }
+ rotate(angle) {
+ this._rotation = angle;
+ this.element.style.transform = "rotate(" + angle +"deg)"
+ }
+ position(x, y) {
+ this.element.style.position = "absolute";
+ this.x = x;
+ this.y = y;
+ this.element.style.top = y + "px";
+ this.element.style.left = x + "px";
+ }
+ displace() {
+ let lA;
+ let cA = 90;
+ if (this._rotation > 0) {
+ lA = this._rotation - a;
+ cA += this._rotation + a;
+ } else {
+ lA = this._rotation + a;
+ cA -= this._rotation - a;
+ }
+
+ let hl = r * Math.abs(Math.cos(lA * Math.PI/180));
+ let hc = r * Math.abs(Math.cos(cA * Math.PI/180))
+ let yDiff = hl - hh;
+ let xDiff = hc - hw;
+ let minY = yDiff + y1;
+ let maxY = y2 - height - yDiff;
+ let minX = xDiff + x1;
+ let maxX = x2 - width - xDiff;
+
+ let x = Math.round(Math.random() * (maxX - minX) + minX);
+ let y = Math.round(Math.random() * (maxY - minY) + minY);
+
+ this.position(x, y);
+ }
+ _onElementClick(e) {
+ this._onCLick(this);
+ }
+
+ static setBounds(minX, minY, maxX, maxY) {
+ x1 = minX;
+ x2 = maxX - 7;
+ y1 = minY;
+ y2 = maxY - 7;
+ }
+}
+
+export default Card
\ No newline at end of file
diff --git a/mj/index.html b/mj/index.html
new file mode 100644
index 0000000..2d9224b
--- /dev/null
+++ b/mj/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Match
+
+
+
+
+
+loading...
+
+
\ No newline at end of file
diff --git a/mj/main.css b/mj/main.css
new file mode 100644
index 0000000..0942bbb
--- /dev/null
+++ b/mj/main.css
@@ -0,0 +1,37 @@
+body {
+ margin: 0;
+ font-family: Sans;
+}
+
+.card {
+ display: flex;
+ width: 150px;
+ height: 220px;
+ align-items: center;
+ justify-content: center;
+ background-color: #ddd;
+ margin: 5px;
+ float: left;
+ box-shadow: #000000 1px 1px 7px -1px;
+ font-size: 17pt;
+ color: #4c4c4c;
+ opacity: 1;
+
+ transition: background-color 200ms ease-in-out,
+ opacity 200ms ease-in-out,
+ top 200ms ease-in-out,
+ left 200ms ease-in-out,
+ transform 100ms ease-in-out;
+}
+
+.selected {
+ background-color: #76bce2;
+}
+
+.card.selected:hover {
+ background-color: #76bce2;
+}
+
+.card:hover {
+ background-color: #e3cfbb;
+}
\ No newline at end of file
diff --git a/mj/main.js b/mj/main.js
new file mode 100644
index 0000000..7f47755
--- /dev/null
+++ b/mj/main.js
@@ -0,0 +1,91 @@
+import Card from './card.js'
+
+document.body.innerText = "";
+
+const vocabulary = [
+ ["drive", "drove"],
+ ["send", "sent"],
+ ["understand", "understood"],
+ ["find", "found"],
+ ["write", "wrote"],
+ ["feel", "felt"],
+ ["fall", "fell"],
+ ["run", "ran"],
+ ["do", "did"],
+ ["speak", "spoke"],
+ ["awake", "awoke"],
+ ["bear", "bore"],
+ ["bend", "bent"],
+ ["bite", "bit"],
+ ["cling", "clung"],
+ ["breed", "bred"],
+ ["feed", "fed"]
+];
+
+let deck = [];
+let selected = null;
+
+Card.setBounds(0, 0, window.innerWidth, window.innerHeight)
+for (let i = 0; i < 50; ++i) {
+ let id = Math.floor(Math.random() * vocabulary.length);
+ let set = vocabulary[id];
+ for (let s = 0; s < set.length; ++s) {
+ let card = new Card(set[s], onCardClick, id, s);
+ card.disrotate();
+ card.displace();
+ deck.push(card);
+ }
+}
+
+deck = shuffle(deck);
+for (let i = 0; i < deck.length; ++i) {
+ document.body.appendChild(deck[i].element);
+}
+
+function onCardClick(card) {
+ if (selected != null) {
+ if (card === selected) {
+ return;
+ }
+ if (selected.setId === card.setId && selected.cardId !== card.cardId) {
+ score(selected, card);
+ selected = null;
+ return;
+ }
+ selected.unselect();
+ }
+ selected = card;
+ card.select();
+}
+
+function score(c1, c2) {
+ deck.splice(deck.indexOf(c1), 1)
+ deck.splice(deck.indexOf(c2), 1);
+
+ let x = window.innerWidth / 2
+ let y = -500;
+
+ c1.position(x, y);
+ c2.position(x, y);
+ c1.rotate(0);
+ c2.rotate(0);
+ c1.element.style.zIndex = "5";
+ c2.element.style.zIndex = "5";
+
+ setTimeout(fade.bind(null, c1, c2), 200);
+}
+
+function fade(c1, c2) {
+ c1.destructor();
+ c2.destructor();
+}
+
+function shuffle(deck) {
+ let spare = deck.slice();
+ let result = [];
+ while (spare.length > 0) {
+ let index = Math.floor(Math.random() * spare.length);
+ result.push(spare.splice(index, 1)[0]);
+ }
+ return result;
+}
\ No newline at end of file