Open sabu36 opened 4 years ago
I think loosing the checkbox and marking the field as optional would be sufficient (and easier):
Random seed (optional)
╭─────────────────────────────────╮
╰─────────────────────────────────╯
This will likely require own implementation of the pseudo random generator. Here is a Stack Overflow answer with a few possibilities
Yes, making it optional makes sense.
The text can be used as a memorable title when creating a game.
From the Stack Overflow answer: "A good hash function will generate very different results even when two strings are similar."
This might not be a good property flavor-wise for our purpose. It would be nice if "flying panda" and "surfing panda" had some resemblance.
One idea:
Divide the stones into groups and use one of the words for each group.
class Rng {
rngs // rng for each word
idx
generate() {
const idxCurrent = this.idx;
this.idx = (this.idx + 1) % this.rngs.length;
return this.rngs[idxCurrent].generate();
}
}
const rng = new Rng(words);
How can we set up so that we just replace Math.random()
with rng.generate()
(or similar name) in js/generators
?
Also, the class name Rng
is not very descriptive. Do you have any suggestion?
As for the actual RNG, the one by David Bau, which is mentioned in the same Stack Overflow thread, already takes a string. What do you think?
Rng
is a pretty common name for Random Number Generator, but I think Random
might be better.
I see two possibilities:
Math.random()
if word
is the empty string.(a) is less coding, but (b) makes writing unit tests much easier. I’m partial to (b) as I like pure functions (among other; functions that always return the same value given the same input) and I like well tested code.
As for the library, I don’t like how it extends the global Math
object. It is generally considered bad JavaScript to extend native objects. I would also prefer to remain buildless[1]. That would mean pulling a library that would work equally in the browser and in node. And using it would be as simple as:
import random from "https://cdn.jsdelivr.net/npm/some-rng-lib";
/** @type SomeType */
as opposed to the more commonly used .ts
files.Looking for a good library I think d3-random might be a good candidate.
Thank you very much for the detailed explanations.
I appreciate your invite to be a collaborator but I feel safer staying the same as I still have shaky understanding of what is going on.
I actually ended up making a build step and am now serving from the gh-pages
branch (#15). This way it is easier to add libraries and we are serving a little more optimized code for the users. But the dev build is still (almost) uncompleted. The only thing we change are bare imports (e.g. import { randomUniform } from d3-random;
) will be altered to resolved location (import { randomUniform } from '/node_modules/d3-random/index.js;
). In the future we can look forward to import maps so we won’t even need that.
I will probably go ahead and implement the seed feature this evening (my time). After that implementing and testing new generators would be even easier. I’m already thinking about normal-handicap. Where stones probability of being drawn at an intersection is normally distributed with the mean on the next traditional handicap star point and a user defined standard deviation.
I'll work on the following.
In adaptive-weights.js
, domino-shuffle.js
, (part of) utils.js
:
@runarberg You may have already realized this but it dawned on me that, since we may use different distributions at different parts, we need to pass around seeders (?) instead of rngs themselves.
Also, d3.randomLcg seems to only take numbers, so it looks like we need a way to convert string into number.
If we have wordToNum()
as a converter, maybe something like:
class Seeder {
constructor(words) {
this.lcgs = words.map((wd) => d3.randomLcg(wordToNum(wd)));
this.idx = 0;
}
next() {
const idxCurrent = this.idx;
this.idx = (this.idx + 1) % this.lcgs.length;
return this.lcgs[idxCurrent];
}
}
const words = ["sea", "sjór", "海"];
config.seeder = new Seeder(words);
I don't know if this is practical but one idea is to hash (?) each word as an image in some reference font to make hashing invariant to alphabetic/character ordering, perhaps using grid larger than pixel to reduce computation and emphasize the general directions of where strokes are going.
(Scratch my last idea.)
In the explanation for d3.randomLcg()
in d3-random:
A seed can be specified as a real number in the interval [0,1) or as any integer. In the latter case, only the lower 32 bits are considered.
For converting string to number, one example I found is murmurhash:
take a JavaScript string (and a seed), and quickly create a non-cryptographic 32-bit hash
Yeah I like that. Last week I conjured something up that hashes a string, slices the last bits and divides by the maximum of that giving a number between 0 and 1:
Number.parseInt(hash(word).toString(16).slice(-8), 16) / 0xffff_ffff;
But if D3 can do that internally and we can use a library for the hashing, thats even better :wink:
It's your call but I also like your solution.
@sabu36 I like your idea of using murmurhash with D3-random. I’ve re-assigned this to you if you want to give it a stab.
I’ve already started, but didn’t get really far (I’ve had a busy couple of weeks). If you like to look at my work (might be useful for styling) see commit fa7335677.
Starting from where you left off--I couldn't figure out how to import murmurhash
so used your solution--uniform.js
now accepts seed.
flying panda
and surfing panda
had 1/2 of their stones in identical positions.blue bird singing
and blue sky falling
had 1/3 in identical positions.So it seems to be working. d13dac5
You can import modules installed with npm install --save <module>
by using bare names:
import d3Random from "d3-random";
import hash from "murmurhash";
This is non-standard as of yet. But I’ve configured a dev-server and the bundler to under stand this. Basically it will map the module using the dependency
field in package.json
and then locate it inside the node_modules
directory.
@runarberg
I still can't figure out how to import d3-random and murmurhash without errors.
(For murmurhash, if it's difficult to fix, it seems we can just use your toHash()
+ toFraction()
.)
They seem to not have default export:
Uncaught SyntaxError: import not found: default
When I tried importing individually:
import { randomLcg, randomUniform } from "d3-random"; ^^^^^^^^^ SyntaxError: The requested module 'd3-random' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export.
When I tried require('murmurhash')
, in browser's Web Console:
ReferenceError: require is not defined
I don't know if this is relevant but this answer lists some options to make require()
work.
Could not find a declaration file for module 'd3-random'. '/home/runner/work/random-go-stone-placements/random-go-stone-placements/node_modules/d3-random/dist/d3-random.js' implicitly has an 'any' type.
Try npm install @types/d3-random if it exists or add a new declaration (.d.ts) file containing declare module 'd3-random';
Something like:
[checkbox] Generate from: [sample-text]