Init.
This commit is contained in:
commit
011ea8bdeb
9 changed files with 239 additions and 0 deletions
11
README
Normal file
11
README
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Fisher
|
||||
|
||||
Fish simulation as a TCP service.
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Colors.
|
||||
- [ ] Don't redraw if buffer unchanged.
|
||||
- [ ] Don't overwrite fishes with space.
|
||||
- [ ] Layer labels above fishes.
|
||||
- [ ] Post new fishes.
|
2
assets/fishes/albert.txt
Normal file
2
assets/fishes/albert.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
_
|
||||
<•_)<(
|
2
assets/fishes/bernard.txt
Normal file
2
assets/fishes/bernard.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
____ _
|
||||
/o'_/\(
|
2
assets/fishes/charles.txt
Normal file
2
assets/fishes/charles.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
___ ,
|
||||
(.o.)<,
|
2
assets/fishes/daniel.txt
Normal file
2
assets/fishes/daniel.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
_
|
||||
(_\/(
|
2
assets/fishes/emile.txt
Normal file
2
assets/fishes/emile.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
___
|
||||
/•v_><[
|
7
deno.json
Normal file
7
deno.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fmt": {
|
||||
"useTabs": true,
|
||||
"lineWidth": 120,
|
||||
"semiColons": false
|
||||
}
|
||||
}
|
78
deno.lock
generated
Normal file
78
deno.lock
generated
Normal file
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"version": "4",
|
||||
"specifiers": {
|
||||
"npm:@spissvinkel/simplex-noise@1.0.1": "1.0.1"
|
||||
},
|
||||
"npm": {
|
||||
"@spissvinkel/simplex-noise@1.0.1": {
|
||||
"integrity": "sha512-Ni1aqFlajxWFxkp2WuCspat6wmrsRZmDv1hgt90hm8J0XkRByd1bzlJFIKw9kC0q5MlOH5GyVrHVR/ZVvhOzqg=="
|
||||
}
|
||||
},
|
||||
"remote": {
|
||||
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
|
||||
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
|
||||
"https://deno.land/std@0.224.0/bytes/concat.ts": "86161274b5546a02bdb3154652418efe7af8c9310e8d54107a68aaa148e0f5ed",
|
||||
"https://deno.land/std@0.224.0/bytes/copy.ts": "08d85062240a7223e6ec4e2af193ad1a50c59a43f0d86ac3a7b16f3e0d77c028",
|
||||
"https://deno.land/std@0.224.0/io/_common.ts": "36705cdb4dfcd338d6131bca1b16e48a4d5bf0d1dada6ce397268e88c17a5835",
|
||||
"https://deno.land/std@0.224.0/io/_constants.ts": "3c7ad4695832e6e4a32e35f218c70376b62bc78621ef069a4a0a3d55739f8856",
|
||||
"https://deno.land/std@0.224.0/io/buf_reader.ts": "aa6d589e567c964c8ba1f582648f3feac45e88ab2e3d2cc2c9f84fd73c05d051",
|
||||
"https://deno.land/std@0.224.0/io/buf_writer.ts": "3fab3fbeae7a6ed1672207b640b6781a2369890878f8a7bb35f95d364dd6dae6",
|
||||
"https://deno.land/std@0.224.0/io/buffer.ts": "4d1f805f350433e418002accec798bc6c33ce18f614afa65f987c202d7b2234e",
|
||||
"https://deno.land/std@0.224.0/io/copy.ts": "63c6a4acf71fb1e89f5e47a7b3b2972f9d2c56dd645560975ead72db7eb23f61",
|
||||
"https://deno.land/std@0.224.0/io/copy_n.ts": "1bad1525b1f78737cb4c11084e2f7cf22359210fea89e2f0e784bd9a4b221fca",
|
||||
"https://deno.land/std@0.224.0/io/iterate_reader.ts": "1e5e4fea22d8965afb7df4ee9ab9adda0a0fc581adbea31bc2f2d25453f8a6e9",
|
||||
"https://deno.land/std@0.224.0/io/limited_reader.ts": "bbe3f7dafe9dd076d0c92d88b1b94e91ecad4825997064f44c2a767737ad2526",
|
||||
"https://deno.land/std@0.224.0/io/mod.ts": "f0a3f9d419394cec27099ba15ab0c8100da1e70928f95ebe646caaf667c6870c",
|
||||
"https://deno.land/std@0.224.0/io/multi_reader.ts": "dd8f06d50adec0e1befb92a1d354fcf28733a4b1669b23bf534ace161ce61b1c",
|
||||
"https://deno.land/std@0.224.0/io/read_all.ts": "876c1cb20adea15349c72afc86cecd3573335845ae778967aefb5e55fe5a8a4a",
|
||||
"https://deno.land/std@0.224.0/io/read_delim.ts": "d26cfed53b0c2c127ec3453ccd65f474ecc36a331209e246448885434afffc4e",
|
||||
"https://deno.land/std@0.224.0/io/read_int.ts": "2412f106103a271f5d770b2a61c97b13eebcd18de414a0a092ed82dfcb875903",
|
||||
"https://deno.land/std@0.224.0/io/read_lines.ts": "17b96f87dbebc5edb976b3d83dc7713bddb994e9c8cb688012d6c6c26803fb9e",
|
||||
"https://deno.land/std@0.224.0/io/read_long.ts": "d7cd367ab5c1263014c32a76afa0f0584c3bf3a3d860963c7368a6825094df46",
|
||||
"https://deno.land/std@0.224.0/io/read_range.ts": "2ddfedbfff44e4ea8d60c0463cddb2b1860293d932d6a72a0fb78bdf412538fc",
|
||||
"https://deno.land/std@0.224.0/io/read_short.ts": "f6dff570e685ade917dcb5188e8ecf0b701d6581b0cd186f08e6efe7f5ce33f7",
|
||||
"https://deno.land/std@0.224.0/io/read_string_delim.ts": "f6beafa8969e6d9d6d7d679f846cd6595d8b6e99091a20a0aecbd50eb30a391e",
|
||||
"https://deno.land/std@0.224.0/io/reader_from_stream_reader.ts": "a75bbc93f39df8b0e372cc1fbdc416a7cbf2a39fc4c09ddb057f1241100191c5",
|
||||
"https://deno.land/std@0.224.0/io/slice_long_to_bytes.ts": "bc59a7aaac64845371dbd44debf3e864ae7b7e453127751d96e30adb29fb633b",
|
||||
"https://deno.land/std@0.224.0/io/string_reader.ts": "279e9ea72e0ed7af6a9cb6da84f4148af93df849d308c31f124ca21f16d09cf2",
|
||||
"https://deno.land/std@0.224.0/io/string_writer.ts": "923954c2038a622b84c294b94a3a322565fa0d67e8b4c62942b154fc1ad3bb9b",
|
||||
"https://deno.land/std@0.224.0/io/to_readable_stream.ts": "ed03a44a1ec1cc55a85a857acf6cac472035298f6f3b6207ea209f93b4aefb39",
|
||||
"https://deno.land/std@0.224.0/io/to_writable_stream.ts": "ef422e0425963c8a1e0481674e66c3023da50f0acbe5ef51ec9789efc3c1e2ed",
|
||||
"https://deno.land/std@0.224.0/io/types.ts": "acecb3074c730b5ff487ba4fe9ce51e67bd982aa07c95e5f5679b7b2f24ad129",
|
||||
"https://deno.land/std@0.224.0/io/write_all.ts": "24aac2312bb21096ae3ae0b102b22c26164d3249dff96dbac130958aa736f038",
|
||||
"https://deno.land/x/noise@v1.1.0/_utils.ts": "09d276f9f2b76b7ed91d0553dfef63af2df911ef252ea831850a3e9d595b3e0c",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/_math.ts": "f85d46e7e9781f54f4c6d7f360e8fff52516a0d13933fb550b14993a48cdb3af",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/cubic.ts": "08da8567c1b04ba27eb789d3c1933e3ed8d5e58af1d03a278e558191e94954e1",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/cylindrical.ts": "f0c324889481f2493f9787bee4059ff4da7b8127797846bbf297a0d10d675a3b",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/linear.ts": "7957faa7c16289fae40d53a79a2d287bcb9eee936d0022f82d2e67fb132bb510",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/mod.ts": "8a204173bd4eaf71052b61eda3c7eb9be626b983ae3885f659316594e3094596",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/options.ts": "48a8c835637855a7fe77a16d38db6c4bd9b5f48912d456d1f45ba1e37e7bdc55",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/rectangular.ts": "b11c760f1d0d999461e5ea1cf4d1cd8b08eb819c7029cee3bf9b09330ae79376",
|
||||
"https://deno.land/x/noise@v1.1.0/fractal/spherical.ts": "a2bdd079f155594259c541238c39b2dde7b74c5a3d0f74449bed579c668bada4",
|
||||
"https://deno.land/x/noise@v1.1.0/math.ts": "d93ab4c1aa2c45635db3936b0cc4c612e21cdfa7165140bb138d25b4003e0466",
|
||||
"https://deno.land/x/noise@v1.1.0/mod.ts": "488e92a50b28b5209c8e6c93e736df2f4542adb90f193de1a756093548191dce",
|
||||
"https://deno.land/x/noise@v1.1.0/noise.ts": "2e937c759f55681fecb17ccf88e08b358df99459115bd9f26a02313b7cf6fb38",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/2d.ts": "01930f7f1a585c10eed02d6abf548e00ade756ff29f57439c669ad6d67070a43",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/3d.ts": "610ff2533419ae4252b78584df341617c420a56d3cc663bcf5e32e50babb5899",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/4d.ts": "7566693f82a35da0643ab4f404e0eca142b990065d60b38f998a842b485912f3",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/_3d_constants.ts": "7f89ce76d03edc51bd150fbab9036ce439eda76c6ee73b738b16d6a485760b4a",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/_4d_constants.ts": "fa218f32de12dc8311e0d7bf32cdbe438df2b45058a215340e4527dde714cee4",
|
||||
"https://deno.land/x/noise@v1.1.0/open_simplex/mod.ts": "084791c4e4e44c9389cfcc6667e4078560349b999f998813a9d309522789021b",
|
||||
"https://deno.land/x/noise@v1.1.0/options.ts": "6048592a492b84724af37aee34a199d0cd1887ad39edec16bcb27bf5cf2869f9",
|
||||
"https://deno.land/x/noise@v1.1.0/perlin/2d.ts": "c7a4273d4e6d9ff669aa764c2eca7b990f7e760848cd56fbeceb459f45837d91",
|
||||
"https://deno.land/x/noise@v1.1.0/perlin/3d.ts": "4575cbcbc3b2c0d368d215e51c3646e97b9ed0c9d8875c9f860d770b673b0533",
|
||||
"https://deno.land/x/noise@v1.1.0/perlin/4d.ts": "8e878efd0edfb31d3872f33652fcb478b6433fd210630cf4d80e91ef4f219113",
|
||||
"https://deno.land/x/noise@v1.1.0/perlin/mod.ts": "30a2ce75e4bf9ae74fb08e9de6b4e767f62500cf532508a0fb4dc9a09e4165c8",
|
||||
"https://deno.land/x/noise@v1.1.0/perlin/options.ts": "af59a2db880352261a57208fae136700bb5ed331439e6da2b49e02a56ea7f6a2",
|
||||
"https://deno.land/x/noise@v1.1.0/simplex/2d.ts": "d6cdcf77280c55c968af591b0a41bcb42a9495270e84e29fce7d568114d3b82f",
|
||||
"https://deno.land/x/noise@v1.1.0/simplex/3d.ts": "e8663685cf32b2da4b400cf9504a883a1e77eb95ffff1565570ea3c48486ea16",
|
||||
"https://deno.land/x/noise@v1.1.0/simplex/4d.ts": "57349d61e0461c509da85c468bd03962fc6dd75c50491b5bbafb918242190b80",
|
||||
"https://deno.land/x/noise@v1.1.0/simplex/mod.ts": "084791c4e4e44c9389cfcc6667e4078560349b999f998813a9d309522789021b",
|
||||
"https://deno.land/x/noise@v1.1.0/value/1d.ts": "240b0bde9623ab2bfb41caf9591c60fe3db9dff386fa23651a321ed712acf6b3",
|
||||
"https://deno.land/x/noise@v1.1.0/value/2d.ts": "f8cef1670aa1559353437c720394519324aa0e6d033c51edabb833af89efd227",
|
||||
"https://deno.land/x/noise@v1.1.0/value/3d.ts": "878ae8722db4a92386d140b3654246b837f635354fca591a4f5b6611d65cc24b",
|
||||
"https://deno.land/x/noise@v1.1.0/value/4d.ts": "2c655fc2b4e47459dcd945e5ba1e91dd16fbf6a1638587feda5d6bb46ce21910",
|
||||
"https://deno.land/x/noise@v1.1.0/value/mod.ts": "0590eb561a46e6495bbe91501db0cdec75756f4080ce64096017bdcfb7cfaf24",
|
||||
"https://deno.land/x/noise@v1.1.0/value/options.ts": "6b3a0206247410b2f6a5540aedc66819c0b6a92ea53a4856be2da917e8ad6e0c"
|
||||
}
|
||||
}
|
133
src/main.ts
Executable file
133
src/main.ts
Executable file
|
@ -0,0 +1,133 @@
|
|||
#!/usr/bin/env -S deno run -A
|
||||
|
||||
import { writeAll } from "https://deno.land/std@0.224.0/io/mod.ts"
|
||||
import { mkSimplexNoise, SimplexNoise } from "npm:@spissvinkel/simplex-noise@1.0.1"
|
||||
|
||||
async function main() {
|
||||
const connections = Listener.listen(8080)
|
||||
const fishes = await Fishes.load("./assets/fishes")
|
||||
for await (const moved of fishes.movements()) {
|
||||
console.log(moved.name, "at", moved.position)
|
||||
const displayed = esc_clear() + fishes.fishes.map(display).join("") + "\n"
|
||||
connections.send(displayed)
|
||||
}
|
||||
}
|
||||
|
||||
class Listener {
|
||||
private constructor(
|
||||
private connections: Set<Deno.TcpConn>,
|
||||
) {}
|
||||
|
||||
public static listen(port: number) {
|
||||
const connections = new Set<Deno.TcpConn>()
|
||||
;(async () => {
|
||||
for await (const conn of Deno.listen({ transport: "tcp", port })) connections.add(conn)
|
||||
})()
|
||||
return new Listener(connections)
|
||||
}
|
||||
|
||||
public async send(text: string) {
|
||||
const encoded = new TextEncoder().encode(text)
|
||||
const promises = new Array<Promise<unknown>>()
|
||||
for (const conn of this.connections) {
|
||||
const promise = writeAll(conn, encoded).catch((_) => this.connections.delete(conn))
|
||||
promises.push(promise)
|
||||
}
|
||||
await Promise.all(promises)
|
||||
}
|
||||
}
|
||||
|
||||
class Fishes {
|
||||
private constructor(
|
||||
public fishes: Fish[],
|
||||
) {}
|
||||
|
||||
public static async load(path: string, max = 999) {
|
||||
const fishes = new Array<Fish>()
|
||||
for await (const entry of Deno.readDir(path)) {
|
||||
if (fishes.length >= max) break
|
||||
if (!entry.isFile) continue
|
||||
if (!entry.name.endsWith(".txt")) continue
|
||||
const name = entry.name.slice(0, entry.name.length - ".txt".length)
|
||||
const file_path = `${path}/${entry.name}`
|
||||
const content = await Deno.readTextFile(file_path)
|
||||
const shape = content.split("\n").filter((l) => l.length > 0)
|
||||
const size: [number, number] = [shape.map((l) => l.length).reduce((a, b) => Math.max(a, b)), shape.length]
|
||||
fishes.push(new Fish(name, size, shape, [Math.random() * 20, Math.random() * 20]))
|
||||
}
|
||||
console.log("Loaded", fishes.length, "fishes.")
|
||||
return new Fishes(fishes)
|
||||
}
|
||||
|
||||
public async *movements() {
|
||||
const noise = mkSimplexNoise(Math.random)
|
||||
while (true) {
|
||||
const picked = pick(this.fishes)
|
||||
picked.move_into(noise, [[0, 0], [80, 25]])
|
||||
yield picked
|
||||
await new Promise((res) => setTimeout(res, 200))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Fish {
|
||||
public constructor(
|
||||
public name: string,
|
||||
public size: [x: number, y: number],
|
||||
public shape: string[],
|
||||
public position: [number, number] = [0, 0],
|
||||
public age = 0,
|
||||
) {}
|
||||
|
||||
public move_into(noise: SimplexNoise, bounds: [[number, number], [number, number]]) {
|
||||
const base = [...this.name].map((c) => c.charCodeAt(0)).reduce((a, b) => a + b)
|
||||
const velocityX = noise.noise2D(this.age % 100, base)
|
||||
const velocityY = noise.noise2D(this.age % 100, base + 100)
|
||||
this.position[0] += velocityX
|
||||
this.position[1] += velocityY
|
||||
this.age += 1
|
||||
if (this.position[0] < bounds[0][0]) this.position[0] = bounds[0][0]
|
||||
if (this.position[1] < bounds[0][1]) this.position[1] = bounds[0][1]
|
||||
if (this.position[0] > bounds[1][0]) this.position[0] = bounds[1][0]
|
||||
if (this.position[1] > bounds[1][1]) this.position[1] = bounds[1][1]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ```
|
||||
* _ <name>
|
||||
* /
|
||||
* #####
|
||||
* #####
|
||||
* #####
|
||||
* ```
|
||||
*
|
||||
* @param fish Fish to display.
|
||||
*/
|
||||
function display(fish: Fish) {
|
||||
const tick_pad = " ".repeat(fish.size[0])
|
||||
// TODO : add position and color
|
||||
return [
|
||||
tick_pad + " _ " + fish.name,
|
||||
tick_pad + "/",
|
||||
...fish.shape,
|
||||
]
|
||||
.map((l, i) => esc_goto([fish.position[0], fish.position[1] + i]) + l)
|
||||
.join("") + "\n"
|
||||
}
|
||||
|
||||
function pick<T>(arr: T[], random = Math.random) {
|
||||
const index = Math.floor(random() * arr.length)
|
||||
return arr[index]
|
||||
}
|
||||
|
||||
function esc_goto(pos: [number, number]) {
|
||||
const [x, y] = pos.map(Math.floor)
|
||||
return "\u001B[" + y + ";" + x + "H"
|
||||
}
|
||||
|
||||
function esc_clear() {
|
||||
return "\u001B[3J"
|
||||
}
|
||||
|
||||
if (import.meta.main) await main()
|
Loading…
Add table
Add a link
Reference in a new issue