Open lidavidm opened 6 years ago
I'm using Redux in my other research project, so I wouldn't mind using Redux/Immutable.js here too. I did find Redux to be a bit annoying because of boilerplate but since managing mutable state is a pain, the tradeoff is probably worth it.
I'm still thinking about the other issues so I'll get back to you on those later.
How about
type Store = {
learned: Map<Id, Learned>, // Not fond of requiring a unique ID, but we need some way to reference things
collections: List<Collection>,
resources: Map<Resource, any>,
location: Location, // Probably also an ID, referencing a location in some database
}
type Learned = {
Learnable, // Agnostic to whatever this actually is,
lastReviewed: DateTime,
score: double, // And some sort of level/EXP to next level?
}
type Collection = List<Id> // Do we need any specific metadata for collections? (No need to store whether they know the word or not - this is part of the store impllicitly)
Actions:
Learned
to learned
)score
)We'd also have helper functions to surface reviewable items and potentially relevant new items.
Hiragana:
Kanji: separate from vocab - just learning the character
Vocab: overlap between readings and vocab
Ideally cross-link everything (e.g. denwa: link den and wa to respective on-reading of kanji) Need notes/metadata for each of these (irregular reading, etc) Look @ jisho.org API model
Probably have a high-level representation, convert to individual learnable items
Couple things:
To clarify, what do you mean by "are these unique"? There can be multiple readings in romaji for a given character (早々 = sousou or hayabaya). There can also be multiple kanji for one string of romaji (hashi = 橋 or 箸).
Well in that case, they aren't unique. I'm just looking for some unique identifier for a particular word-concept so that we can avoid having to assign and manage numeric IDs which would be a pain.
anyways so I propose
type learnable = {
id: string;
subid: string option;
type: learnableType;
(* ...other fields depend on type *)
}
example:
let hiragana = {
type: "hiragana",
unicode: "<squiggle>",
reading: "ko",
id: "hira-ko",
subId: null,
}
let kanji = {
type: "kanji-wo-reading",
unicode: "电话",
reading: "<series of japanese squiggles>",
subId: "reading-wo",
id: "kanji-denwa",
}
and the actual database definition might be something like
let denwa = new Kanji({
unicode: "电话",
readings: {
wo: "...",
...
},
meanings: ["phone", ...],
});
Overall I think this makes sense to me.
thank
@lidavidm
export interface StoreProps {
readonly learned: immutable.Map<LearnableId, Learned>;
readonly collections: immutable.List<Collection>;
readonly resources: immutable.Map<Resource, number>;
readonly location: Location;
}
I'm currently adding a collection of hiragana to the game (via data file) and I'm wondering where to store it, since learned
is only for learned vocab and collections
is just a list of lists of ids.
Should I make a new field for the store that just contains all the static data?
The store shouldn't contain any static data. You can define it separately, and just correlate it using the ID. For instance, you could have a model that just contains tables of static data, or you could make the reducer a partially applied function where the first parameter is the static data, and the data is loaded from someplace at runtime. I do something similar for the latter at https://github.com/lidavidm/reduct-redux/blob/1b245406dd8c78062a1cefd4ebe3a7cc0f64a65b/src/reducer/reducer.js#L35 (calling reduct(...)
returns a function which is the actual reducer)
Overall
Static data:
Dynamic data:
Static Data
Things Learned
Hiragana:
Kanji:
More complicated things:
Questions
Template-based:
Fixed:
Events
Either asking a specific question, and/or giving the player some resource/updating a flag (see "Frienships")
Dynamic Data
Friendships
Presumably we're not going to model individual students, The Sims style. So we probably want some flags that events can update, and which other events can predicate themselves on.
Actually storing things
React is somewhat agnostic to its data model, but word on the street is that storing data inside of components doesn't scale so well. I think it'd make our lives easier if we have a central data store. Redux+Immutable.js seems pretty popular at the moment, and I've used this combo before elsewhere. (It has some performance caveats if you're trying to update it hundreds of times per second, but I don't think we're doing that.)
Long story short, in Redux you have a single immutable state object, which you do not directly update. Instead, you define a set of actions that can be performed, and provide a function that takes the current state and requested action, and returns a new state object. React has bridges to expose the current state object to our views, and views dispatch actions to the central store to update it.
This fairly nicely separates the view and model, allowing us to do things like logging easily (e.g. just wrap the updater in a function that logs the action). The caveat is that updating the store itself is a pain (immutable.js is a library & JS doesn't let you override most syntax, so it starts looking like using Java collections) and you have to come up with a clearly defined set of actions (this probably won't be so hard for us).
Static data can probably be stored outside Redux; we can have global tables of questions, events, etc. We do need to correlate these somehow (unique IDs for everything?).
One final caveat is that Immutable.js hates deeply nested data structures, which I will explain if we run into it.
@a7c (and mauer too, but I can't tag him yet)