Euler golf #1
38
euler-golf/index.html
Normal file
38
euler-golf/index.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Euler Golf 2</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: scroll;
|
||||
font-family: Lucida Console, Lucida Sans Typewriter, monaco,
|
||||
Bitstream Vera Sans Mono, monospace;
|
||||
}
|
||||
|
||||
.canvas-holder canvas {
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
display: block;
|
||||
height: 70vh;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
|
||||
<script src="js/cx.js"></script>
|
||||
<script src="js/sol.js"></script>
|
||||
<script src="js/game.js"></script>
|
||||
</body>
|
||||
</html>
|
308
euler-golf/js/cx.js
Normal file
308
euler-golf/js/cx.js
Normal file
@ -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
|
11
euler-golf/js/game.js
Normal file
11
euler-golf/js/game.js
Normal file
@ -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();
|
44
euler-golf/js/sol.js
Normal file
44
euler-golf/js/sol.js
Normal file
@ -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;
|
||||
};
|
78
index.html
78
index.html
@ -3,37 +3,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Simponic's Static Sites</title>
|
||||
<link href="css/styles.css" rel="stylesheet">
|
||||
<link href="css/styles.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
|
||||
/>
|
||||
<script src="https://kit.fontawesome.com/d7e97ed48f.js" crossorigin="anonymous"></script>
|
||||
<script
|
||||
src="https://kit.fontawesome.com/d7e97ed48f.js"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="top-container animate__animated animate__fadeIn">
|
||||
<img src="images/profile.png" class="profile-picture">
|
||||
<img src="images/profile.png" class="profile-picture" />
|
||||
<h3>
|
||||
👋 Hello, I'm Simponic!
|
||||
<br>
|
||||
<br />
|
||||
📖 This page hosts strictly static content.
|
||||
<br>
|
||||
🔔 My "real website" is at <a href="https://simponic.xyz">simponic.xyz</a>.
|
||||
<br />
|
||||
🔔 My "real website" is at
|
||||
<a href="https://simponic.xyz">simponic.xyz</a>.
|
||||
</h3>
|
||||
<div class="projects-grid">
|
||||
<div class="project" onclick="window.location='dvd-logo/index.html'">
|
||||
<div class="project" onclick="window.location='julia/index.html'">
|
||||
<div class="project-logo-container">
|
||||
<i class="fa-solid fa-compact-disc"></i>
|
||||
<i class="fa-solid fa-square-root-variable"></i>
|
||||
</div>
|
||||
|
||||
<div class="project-body">
|
||||
<h1>DVD Logo Bouncing Animation</h1>
|
||||
<p>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!</p>
|
||||
<h1>Julia Set Explorer</h1>
|
||||
<p>
|
||||
Zoom, pan, and "c" complex changes in this fun GPU-accelerated
|
||||
playground!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="project"
|
||||
onclick="window.location='ft-visualizer/index.html'"
|
||||
>
|
||||
<div class="project-logo-container">
|
||||
<i class="fa-solid fa-wave-square"></i>
|
||||
</div>
|
||||
|
||||
<div class="project-body">
|
||||
<h1>Discrete Fourier Visualizer</h1>
|
||||
<p>
|
||||
Draw how your year has gone and view a reactive graph containing
|
||||
its DFT by dragging your mouse over the canvas!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project" onclick="window.location='maize-maze/index.html'">
|
||||
<div class="project-logo-container">
|
||||
<i class="fa-solid fa-diagram-project"></i>
|
||||
@ -41,7 +64,10 @@
|
||||
|
||||
<div class="project-body">
|
||||
<h1>The A-maze-ing Maize Maze</h1>
|
||||
<p>A Randomized Kruskal's Maze game with BFS path-finding. You play as a 🌽corn stalk trying to become 🍿popcorn.</p>
|
||||
<p>
|
||||
A Randomized Kruskal's Maze game with BFS path-finding. You play
|
||||
as a 🌽corn stalk trying to become 🍿popcorn.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -52,29 +78,25 @@
|
||||
|
||||
<div class="project-body">
|
||||
<h1>Centipede</h1>
|
||||
<p>In this game, shoot all the centipede bodies and score points and go up levels.</p>
|
||||
<p>
|
||||
In this game, shoot all the centipede bodies and score points and
|
||||
go up levels.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project" onclick="window.location='julia/index.html'">
|
||||
<div class="project" onclick="window.location='dvd-logo/index.html'">
|
||||
<div class="project-logo-container">
|
||||
<i class="fa-solid fa-square-root-variable"></i>
|
||||
<i class="fa-solid fa-compact-disc"></i>
|
||||
</div>
|
||||
|
||||
<div class="project-body">
|
||||
<h1>Julia Set Explorer</h1>
|
||||
<p>Zoom, pan, and "c" complex changes in this fun GPU-accelerated playground!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project" onclick="window.location='ft-visualizer/index.html'">
|
||||
<div class="project-logo-container">
|
||||
<i class="fa-solid fa-wave-square"></i>
|
||||
</div>
|
||||
|
||||
<div class="project-body">
|
||||
<h1>Discrete Fourier Visualizer</h1>
|
||||
<p>Draw how your year has gone and view a reactive graph containing its DFT by dragging your mouse over the canvas!</p>
|
||||
<h1>DVD Logo Bouncing Animation</h1>
|
||||
<p>
|
||||
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!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user