From 77bcd2b2f2fcb3c712e6d80949d44a88b22d0794 Mon Sep 17 00:00:00 2001 From: Simponic Date: Thu, 23 Feb 2023 10:15:07 -0700 Subject: [PATCH] Initial euler golf sol --- euler-golf/index.html | 38 ++++++ euler-golf/js/cx.js | 308 ++++++++++++++++++++++++++++++++++++++++++ euler-golf/js/game.js | 11 ++ euler-golf/js/sol.js | 44 ++++++ index.html | 88 +++++++----- 5 files changed, 456 insertions(+), 33 deletions(-) create mode 100644 euler-golf/index.html create mode 100644 euler-golf/js/cx.js create mode 100644 euler-golf/js/game.js create mode 100644 euler-golf/js/sol.js diff --git a/euler-golf/index.html b/euler-golf/index.html new file mode 100644 index 0000000..2682a0c --- /dev/null +++ b/euler-golf/index.html @@ -0,0 +1,38 @@ + + + + Euler Golf 2 + + + + + + + + + + diff --git a/euler-golf/js/cx.js b/euler-golf/js/cx.js new file mode 100644 index 0000000..371415d --- /dev/null +++ b/euler-golf/js/cx.js @@ -0,0 +1,308 @@ +// http://www.russellcottrell.com/fractalsEtc/cx.js + +class cx { + static degrees(d) { + cx._RD = d ? Math.PI / 180 : 1; + } + // Math.PI/180 for degrees, 1 for radians + // applies to i/o (constructor, get/set arg, and toString etc.) + + constructor(x, y, polar) { + if (!polar) { + this.re = x; + this.im = y; + } else { + y *= cx._RD; // may be radians or degrees + this.re = x * Math.cos(y); + this.im = x * Math.sin(y); + } + } + + get abs() { + return Math.sqrt(this.re * this.re + this.im * this.im); + } + + set abs(r) { + var theta = this._arg; + this.re = r * Math.cos(theta); + this.im = r * Math.sin(theta); + } + + get arg() { + // returns radians or degrees, non-negative + return ( + ((Math.atan2(this.im, this.re) + 2 * Math.PI) % (2 * Math.PI)) / cx._RD + ); + } + + set arg(theta) { + // may be radians or degrees + var r = this.abs; + this.re = r * Math.cos(theta * cx._RD); + this.im = r * Math.sin(theta * cx._RD); + } + + get _arg() { + // internal; returns radians + return Math.atan2(this.im, this.re); + } + + static get i() { + return new cx(0, 1); + } + + static set i(x) { + throw new Error("i is read-only"); + } + + toString(polar) { + if (!polar) + return ( + this.re.toString() + + (this.im >= 0 ? " + " : " - ") + + Math.abs(this.im).toString() + + "i" + ); + else return this.abs.toString() + " cis " + this.arg.toString(); + } + + toPrecision(n, polar) { + if (!polar) + return ( + this.re.toPrecision(n) + + (this.im >= 0 ? " + " : " - ") + + Math.abs(this.im).toPrecision(n) + + "i" + ); + else return this.abs.toPrecision(n) + " cis " + this.arg.toPrecision(n); + } + + toPrecis(n, polar) { + // trims trailing zeros + if (!polar) + return ( + parseFloat(this.re.toPrecision(n)).toString() + + (this.im >= 0 ? " + " : " - ") + + parseFloat(Math.abs(this.im).toPrecision(n)).toString() + + "i" + ); + else + return ( + parseFloat(this.abs.toPrecision(n)).toString() + + " cis " + + parseFloat(this.arg.toPrecision(n)).toString() + ); + } + + toFixed(n, polar) { + if (!polar) + return ( + this.re.toFixed(n) + + (this.im >= 0 ? " + " : " - ") + + Math.abs(this.im).toFixed(n) + + "i" + ); + else return this.abs.toFixed(n) + " cis " + this.arg.toFixed(n); + } + + toExponential(n, polar) { + if (!polar) + return ( + this.re.toExponential(n) + + (this.im >= 0 ? " + " : " - ") + + Math.abs(this.im).toExponential(n) + + "i" + ); + else return this.abs.toExponential(n) + " cis " + this.arg.toExponential(n); + } + + static getReals(c, d) { + // when c or d may be simple or complex + var x, y, u, v; + if (c instanceof cx) { + x = c.re; + y = c.im; + } else { + x = c; + y = 0; + } + if (d instanceof cx) { + u = d.re; + v = d.im; + } else { + u = d; + v = 0; + } + return [x, y, u, v]; + } + + static conj(c) { + return new cx(c.re, -c.im); + } + + static neg(c) { + return new cx(-c.re, -c.im); + } + + static add(c, d) { + var a = cx.getReals(c, d); + var x = a[0]; + var y = a[1]; + var u = a[2]; + var v = a[3]; + return new cx(x + u, y + v); + } + + static sub(c, d) { + var a = cx.getReals(c, d); + var x = a[0]; + var y = a[1]; + var u = a[2]; + var v = a[3]; + return new cx(x - u, y - v); + } + + static mult(c, d) { + var a = cx.getReals(c, d); + var x = a[0]; + var y = a[1]; + var u = a[2]; + var v = a[3]; + return new cx(x * u - y * v, x * v + y * u); + } + + static div(c, d) { + var a = cx.getReals(c, d); + var x = a[0]; + var y = a[1]; + var u = a[2]; + var v = a[3]; + return new cx( + (x * u + y * v) / (u * u + v * v), + (y * u - x * v) / (u * u + v * v) + ); + } + + static pow(c, int) { + if (Number.isInteger(int) && int >= 0) { + var r = Math.pow(c.abs, int); + var theta = int * c._arg; + return new cx(r * Math.cos(theta), r * Math.sin(theta)); + } else return NaN; + } + + static root(c, int, k) { + if (!k) k = 0; + if ( + Number.isInteger(int) && + int >= 2 && + Number.isInteger(k) && + k >= 0 && + k < int + ) { + var r = Math.pow(c.abs, 1 / int); + var theta = (c._arg + 2 * k * Math.PI) / int; + return new cx(r * Math.cos(theta), r * Math.sin(theta)); + } else return NaN; + } + + static log(c) { + return new cx(Math.log(c.abs), c._arg); + } + + static exp(c) { + var r = Math.exp(c.re); + var theta = c.im; + return new cx(r * Math.cos(theta), r * Math.sin(theta)); + } + + static sin(c) { + var a = c.re; + var b = c.im; + return new cx(Math.sin(a) * Math.cosh(b), Math.cos(a) * Math.sinh(b)); + } + + static cos(c) { + var a = c.re; + var b = c.im; + return new cx(Math.cos(a) * Math.cosh(b), -Math.sin(a) * Math.sinh(b)); + } + + static tan(c) { + return cx.div(cx.sin(c), cx.cos(c)); + } + + static asin(c, k) { + if (!k) k = 0; + var ic = cx.mult(cx.i, c); + var c2 = cx.pow(c, 2); + return cx.mult( + cx.neg(cx.i), + cx.log(cx.add(ic, cx.root(cx.sub(1, c2), 2, k))) + ); + } + + static acos(c, k) { + if (!k) k = 0; + var c2 = cx.pow(c, 2); + return cx.mult( + cx.neg(cx.i), + cx.log(cx.add(c, cx.mult(cx.i, cx.root(cx.sub(1, c2), 2, k)))) + ); + } + + static atan(c) { + return cx.mult( + cx.div(cx.i, 2), + cx.log(cx.div(cx.add(cx.i, c), cx.sub(cx.i, c))) + ); + } + + static sinh(c) { + var a = c.re; + var b = c.im; + return new cx(Math.sinh(a) * Math.cos(b), Math.cosh(a) * Math.sin(b)); + } + + static cosh(c) { + var a = c.re; + var b = c.im; + return new cx(Math.cosh(a) * Math.cos(b), Math.sinh(a) * Math.sin(b)); + } + + static tanh(c) { + return cx.div(cx.sinh(c), cx.cosh(c)); + } + + static asinh(c, k) { + if (!k) k = 0; + var c2 = cx.pow(c, 2); + return cx.log(cx.add(c, cx.root(cx.add(c2, 1), 2, k))); + } + + static acosh(c, k) { + if (!k) k = 0; + var c2 = cx.pow(c, 2); + return cx.log(cx.add(c, cx.root(cx.sub(c2, 1), 2, k))); + } + + static atanh(c) { + return cx.mult(cx.div(1, 2), cx.log(cx.div(cx.add(1, c), cx.sub(1, c)))); + } + + static copy(c) { + return new cx(c.re, c.im); + } + + static eq(c, d, epsilon) { + if (!epsilon) { + if (c.re == d.re && c.im == d.im) return true; + } else { + if (Math.abs(c.re - d.re) < epsilon && Math.abs(c.im - d.im) < epsilon) + return true; + } + return false; + } +} + +cx.degrees(true); // need to call this diff --git a/euler-golf/js/game.js b/euler-golf/js/game.js new file mode 100644 index 0000000..6283cc4 --- /dev/null +++ b/euler-golf/js/game.js @@ -0,0 +1,11 @@ +const WIDTH = 1000; +const HEIGHT = 1000; + +const draw_grid = (ctx) => {}; + +const main = () => { + const canvas = document.getElementById("canvas"); + const ctx = canvas.getContext("2d"); +}; + +main(); diff --git a/euler-golf/js/sol.js b/euler-golf/js/sol.js new file mode 100644 index 0000000..a022c99 --- /dev/null +++ b/euler-golf/js/sol.js @@ -0,0 +1,44 @@ +const DEPTH = 7; + +const DIRECTION = { + 0: new cx(0, 1), + 1: new cx(0, -1), +}; + +const move = (prev, curr, c) => cx.add(prev, cx.mult(c, cx.sub(curr, prev))); +const construct_moves = (curr, prev) => + Object.keys(DIRECTION).map((x) => move(curr, prev, DIRECTION[x])); +const backtrack = (local_index, depth) => + local_index + .toString(2) + .padStart(depth, "0") + .split("") + .reverse() + .map((dir) => (dir ? "+" : "-")); + +const sol = (target, start_from = new cx(0, 0), start_to = new cx(1, 0)) => { + let moves = construct_moves(start_from, start_to); + let curr_depth = 2; // potential bug: when target is within one move away + + do { + for (let i = 0; i < Math.pow(2, curr_depth); i++) { + const current_i = + (i >> 1) + ((1 - Math.pow(2, curr_depth - 1)) / (1 - 2) - 1); + const previous_i = + (i >> 2) + ((1 - Math.pow(2, curr_depth - 2)) / (1 - 2) - 1); + + const new_move = move( + previous_i < 0 ? start_from : moves[previous_i], + moves[current_i], + DIRECTION[parseInt(i.toString(2)[0])] + ); + + if (cx.eq(new_move, target)) return backtrack(moves, target); + + moves.push(new_move); + } + curr_depth++; + } while (curr_depth < DEPTH); + console.log(moves); + return null; +}; diff --git a/index.html b/index.html index 3eb01e3..758b4e0 100644 --- a/index.html +++ b/index.html @@ -3,45 +3,71 @@ Simponic's Static Sites - + - - - + + +
- +

- 👋 Hello, I'm Simponic! -
- 📖 This page hosts strictly static content. -
- 🔔 My "real website" is at simponic.xyz. + 👋 Hello, I'm Simponic! +
+ 📖 This page hosts strictly static content. +
+ 🔔 My "real website" is at + simponic.xyz.

-
+
- +
-

DVD Logo Bouncing Animation

-

Brings back the nostalgia of old-school DVD players with an intersection predictor. The twist: no Canvas API! Only svg's and absolute positioned images!

+

Julia Set Explorer

+

+ Zoom, pan, and "c" complex changes in this fun GPU-accelerated + playground! +

+
+
+ +
+ +
+

Discrete Fourier Visualizer

+

+ Draw how your year has gone and view a reactive graph containing + its DFT by dragging your mouse over the canvas! +

+
+
-
+

The A-maze-ing Maize Maze

-

A Randomized Kruskal's Maze game with BFS path-finding. You play as a 🌽corn stalk trying to become 🍿popcorn.

+

+ A Randomized Kruskal's Maze game with BFS path-finding. You play + as a 🌽corn stalk trying to become 🍿popcorn. +

@@ -50,31 +76,27 @@
-
+

Centipede

-

In this game, shoot all the centipede bodies and score points and go up levels.

+

+ In this game, shoot all the centipede bodies and score points and + go up levels. +

-
+
- +
-

Julia Set Explorer

-

Zoom, pan, and "c" complex changes in this fun GPU-accelerated playground!

-
-
- -
-
- -
- -
-

Discrete Fourier Visualizer

-

Draw how your year has gone and view a reactive graph containing its DFT by dragging your mouse over the canvas!

+

DVD Logo Bouncing Animation

+

+ Brings back the nostalgia of old-school DVD players with an + intersection predictor. The twist: no Canvas API! Only svg's and + absolute positioned images! +