mirror of
https://github.com/osmarks/random-stuff
synced 2025-01-02 21:40:35 +00:00
Add some web things
This commit is contained in:
parent
95e84ceb80
commit
723eb34e40
107
political_opinion_calendar.html
Normal file
107
political_opinion_calendar.html
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="https://unpkg.com/mithril/mithril.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.calday {
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.opinion {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="app">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var month = 6
|
||||||
|
var year = 2022
|
||||||
|
var opinions = []
|
||||||
|
|
||||||
|
const hash = (str, seed = 0) => {
|
||||||
|
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed
|
||||||
|
for (let i = 0, ch; i < str.length; i++) {
|
||||||
|
ch = str.charCodeAt(i)
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761)
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677)
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909)
|
||||||
|
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909)
|
||||||
|
return 4294967296 * (2097151 & h2) + (h1>>>0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function incMonth(by) {
|
||||||
|
month += by
|
||||||
|
if (month < 1) {
|
||||||
|
month = 12 - month
|
||||||
|
year--
|
||||||
|
} else if (month > 12) {
|
||||||
|
month = month - 12
|
||||||
|
year++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayMonth(year, month) {
|
||||||
|
var opinionLookup = []
|
||||||
|
for (const opinion of opinions) {
|
||||||
|
for (var i = 0; i < opinion.weight; i++) {
|
||||||
|
opinionLookup.push(opinion.opinion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(opinionLookup)
|
||||||
|
|
||||||
|
var init = dateFns.addMonths(dateFns.addYears(0, year - 1970), month - 1)
|
||||||
|
var offset = dateFns.getDay(init) - 1
|
||||||
|
var weekinit = dateFns.subDays(init, offset >= 0 ? offset : 6)
|
||||||
|
console.log(init, dateFns.getDay(init), weekinit)
|
||||||
|
var rows = [
|
||||||
|
m("tr.calweek.calhead", ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map(x => m("th.calday", x)))
|
||||||
|
]
|
||||||
|
outer: for (var i = 0; i < 6; i++) {
|
||||||
|
var row = []
|
||||||
|
for (var j = 0; j < 7; j++) {
|
||||||
|
var x = dateFns.addDays(dateFns.addWeeks(weekinit, i), j)
|
||||||
|
console.log(x, init, dateFns.getMonth(x), month)
|
||||||
|
if (x > init && dateFns.getMonth(x) + 1 !== month && dateFns.getDate(x) >= 7) { break outer }
|
||||||
|
var opindex = hash(`${dateFns.getYear(x)}-${dateFns.getMonth(x)}-${dateFns.getDate(x)}`) % opinionLookup.length
|
||||||
|
var opinion = opinionLookup.length > 0 ? opinionLookup[opindex] : "no opinion"
|
||||||
|
row.push(m("td.calday", { style: `background: hsl(${hash(opinion) % 360}deg, 100%, 60%); opacity: ${dateFns.getMonth(x) + 1 === month ? "1": "0.5"}` }, [
|
||||||
|
m(".date", dateFns.getDate(x)),
|
||||||
|
m(".opinion", opinion)
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
rows.push(m("tr.calweek", row))
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
m.mount(document.querySelector("#app"), {
|
||||||
|
view: function() {
|
||||||
|
return [
|
||||||
|
m("", [
|
||||||
|
m("h1", "Calendar"),
|
||||||
|
m("h2", `${year}-${month}`),
|
||||||
|
m("button", { onclick: () => incMonth(-1) }, "-"),
|
||||||
|
m("button", { onclick: () => incMonth(1) }, "+"),
|
||||||
|
m("table", displayMonth(year, month))
|
||||||
|
]),
|
||||||
|
m("", [
|
||||||
|
m("h1", "Political Opinions"),
|
||||||
|
m("ul",
|
||||||
|
opinions.map((opinion, index) => m("li", [
|
||||||
|
m("button", { onclick: () => opinions.splice(index, 1) }, "-"),
|
||||||
|
m("input[type=number]", { value: opinion.weight, min: 1, max: 100, oninput: ev => opinions[index].weight = Math.min(ev.target.value, 100) }),
|
||||||
|
m("input", { value: opinion.opinion, oninput: ev => opinions[index].opinion = ev.target.value })
|
||||||
|
]))
|
||||||
|
),
|
||||||
|
m("button", { onclick: () => opinions.push({ opinion: "", weight: 1 }) }, "+")
|
||||||
|
])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
@ -56,7 +56,10 @@
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
info.innerText = "Total E_k is " + objects.map(x => 1/2 * x.m * vmag(x.v) ** 2).reduce((a, b) => a + b).toString()
|
const E_k = objects.map(x => 1/2 * x.m * vmag(x.v) ** 2).reduce((a, b) => a + b)
|
||||||
|
// extra division by 2 due to double-counting
|
||||||
|
const E_p = objects.map(o1 => objects.filter(o2 => o2 !== o1).map(o2 => 1/6 * o1.m * o2.m * G * (vmag(vsub(o1.x, o2.x)) ** 3)).reduce((a, b) => a + b)).reduce((a, b) => a + b)
|
||||||
|
info.innerHTML = `E<sub>k</sub>=${E_k.toFixed(2)}<br>E<sub>p</sub>=${E_p.toFixed(2)}<br>sum=${E_k+E_p}`
|
||||||
|
|
||||||
requestAnimationFrame(step)
|
requestAnimationFrame(step)
|
||||||
}
|
}
|
||||||
|
104
wfc.html
Normal file
104
wfc.html
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<canvas id="canv"></canvas>
|
||||||
|
<input type="file" id="file">
|
||||||
|
<div id="out"></div>
|
||||||
|
<button id="step">Step</button>
|
||||||
|
<script>
|
||||||
|
const write = line => {
|
||||||
|
const out = document.querySelector("#out")
|
||||||
|
out.appendChild(document.createTextNode(line))
|
||||||
|
out.appendChild(document.createElement("br"))
|
||||||
|
}
|
||||||
|
|
||||||
|
const PX = 16
|
||||||
|
const W = 16
|
||||||
|
const RANGE = 10
|
||||||
|
const ctx = document.querySelector("canvas").getContext("2d")
|
||||||
|
ctx.canvas.width = PX * W
|
||||||
|
ctx.canvas.height = PX * W
|
||||||
|
|
||||||
|
let grid = Array(W * W).fill(null).map(x => ({ value: null, options: new Set(Array(RANGE).fill(null).map((_, ix) => ix)) }))
|
||||||
|
const map = ([x, y]) => x + y * W
|
||||||
|
const unmap = a => [a % W, Math.floor(a / W)]
|
||||||
|
const vsum = ([a, b], [c, d]) => [a + c, b + d]
|
||||||
|
const adj = [[0, 1], [0, -1], [1, 0], [-1, 0]]
|
||||||
|
const inRange = p => p >= 0 && p < grid.length
|
||||||
|
const modclamp = x => x < 0 ? 10 + x : x % 10
|
||||||
|
|
||||||
|
const updatePos = (pos, value) => {
|
||||||
|
grid[map(pos)].value = value
|
||||||
|
console.log(value)
|
||||||
|
grid[map(pos)].options = null
|
||||||
|
for (const a of adj) {
|
||||||
|
const n = map(vsum(a, pos))
|
||||||
|
if (inRange(n) && grid[n].value === null) {
|
||||||
|
for (const offset of [-1, 0, 1, 2, -2, 3, -3]) {
|
||||||
|
grid[n].options.delete(modclamp(offset + value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const findBestCandidates = grid => grid.reduce(([bestQty, bestPos], val, index) => {
|
||||||
|
if (val.value !== null) {
|
||||||
|
return [bestQty, bestPos]
|
||||||
|
}
|
||||||
|
if (val.options.size < bestQty) {
|
||||||
|
return [val.options.size, [unmap(index)]]
|
||||||
|
}
|
||||||
|
if (val.options.size == bestQty) {
|
||||||
|
bestPos.push(unmap(index))
|
||||||
|
}
|
||||||
|
return [bestQty, bestPos]
|
||||||
|
}, [RANGE, []])
|
||||||
|
const render = grid => {
|
||||||
|
for (let x = 0; x < W; x++) {
|
||||||
|
for (let y = 0; y < W; y++) {
|
||||||
|
const data = grid[map([x, y])]
|
||||||
|
const level = data.options && Math.floor(data.options.size / RANGE * 255).toString(16).padStart(2, "0")
|
||||||
|
ctx.fillStyle = data.value !== null ? `#0000${Math.floor(data.value / RANGE * 255).toString(16).padStart(2, "0")}` : `#${level}${level}${level}`
|
||||||
|
ctx.fillRect(x * PX, y * PX, PX, PX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pick = arr => arr[Math.floor(Math.random() * arr.length)]
|
||||||
|
|
||||||
|
render(grid)
|
||||||
|
|
||||||
|
step.onclick = () => {
|
||||||
|
const [qty, pos] = findBestCandidates(grid)
|
||||||
|
if (qty === 0) {
|
||||||
|
write("contradiction")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
write(`${qty} options on ${pos.length} tiles`)
|
||||||
|
if (qty === 1) {
|
||||||
|
write("resolving")
|
||||||
|
for (const p of pos) {
|
||||||
|
const newValue = Array.from(grid[map(p)].options)[0]
|
||||||
|
console.log(newValue)
|
||||||
|
updatePos(p, newValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const p = pick(pos)
|
||||||
|
console.log(p, map(p), grid[map(p)])
|
||||||
|
const newValue = pick(Array.from(grid[map(p)].options))
|
||||||
|
console.log(newValue)
|
||||||
|
updatePos(p, newValue)
|
||||||
|
}
|
||||||
|
render(grid)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.file.oninput = ev => {
|
||||||
|
const file = e.target.files[0]
|
||||||
|
const url = URL.createObjectURL(file)
|
||||||
|
const img = new Image()
|
||||||
|
|
||||||
|
img.onload = function() {
|
||||||
|
URL.revokeObjectURL(img.src)
|
||||||
|
c.getContext("2d").drawImage(img, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
img.src = url
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user