GithubHelp home page GithubHelp logo

dolphinsr's Introduction

DolphinSR: Spaced Repetition in JavaScript

DolphinSR implements spaced repetition in JavaScript. Specifically, it uses Anki's modifications to the SM2 algorithm including:

  • an initial mode for learning new cards
  • a mode for re-learning cards after forgetting them
  • reducing the number of self-assigned ratings from 6 to 4
  • factoring lateness into card scheduling
  • Anki's default configuration options

While DolphinSR is intentionally very similar to Anki's algorithm, it does deviate in a few ways:

  • improved support for adding reviews out of order (for example, due to network latency)
  • very different internal data structures (DolphinSR is largely written in a functional style to make testing and debugging easier, and does not rely on storing computed data or any SQL database)
  • only one kind of card

Installation

DolphinSR is an npm package. Install it with either yarn add dolphinsr or npm install --save dolphinsr.

It's strongly recommended that you use Flow to statically check your code when using DolphinSR. We rely on it exclusively for type-checking, and don't do any runtime validation of type arguments. For more information, visit the Flow webpage;

Quick Start


import { DolphinSR, generateId } from 'dolphinsr';
import type { Master, Review } from 'dolphinsr';

// Specify the combinations DolphinSR should make out of your master cards.
// Numbers refer to indexes on the card. (Don't worry and keep reading if you don't understand)
const chineseCombinations = [
  {front: [0], back: [1, 2]},
  {front: [1], back: [0, 2]},
  {front: [2], back: [0, 3]}
];
const frenchCombinations = [
  {front: [0], back: [1]},
  {front: [1], back: [0]}
];

// Create the master cards that DolphinSR will use spaced repetition to teach.
// Note: in a real program, you'd want to persist these somewhere (a database, localStorage, etc)
const vocab: Array<Master> = [
  {
    id: generateId(),
    combinations: chineseCombinations,
    fields: ['你好', 'nǐ hǎo', 'hello']
  },
  {
    id: generateId(),
    combinations: chineseCombinations,
    fields: ['世界', 'shìjiè', 'world']
  },
  {
    id: generateId(),
    combinations: frenchCombinations,
    fields: ['le monde', 'the world']
  },
  {
    id: generateId(),
    combinations: frenchCombinations,
    fields: ['bonjour', 'hello (good day)']
  }
];

// Create the datastore used to house reviews.
// Again, in a real app you'd want to persist this somewhere.
const reviews: Array<Review> = [];

// Create a new DolphinSR instance
const d = new DolphinSR();

// Add all of your vocab to the DolphinSR instance
d.addMasters(...vocab);

// Add any existing reviews to the DolphinSR instance
// (In this example, this doesn't do anything since reviews is empty.)
d.addReviews(...reviews);

// Now, DolphinSR can tell us what card to review next.
// Since generateId() generates a random ID, it could be any of the cards we added.
// For example, it could be:
//     {
//       master: <Id>,
//       combination: {front: [0], back: [1, 2]},
//       front: ['你好'],
//       back: ['nǐ hǎo', 'hello']
//     }
const card = d.nextCard();

// It will also give us statistics on the cards we have:
// Since we added 2 masters with 3 combinations (the Chinese vocab) and 2 masters with 2
// combinations (the French vocab), we will have 10 cards. Since we haven't reviewed any of them
// yet, they will all be in a "learning" state.
const stats = d.summary(); // => { due: 0, later: 0, learning: 10, overdue: 0 }

// Now, we can review the current card (probably triggered by a real app's UI)
// If we already knew the answer, we would create a review saying that it was "easy" to recall:
const review: Review = {
  // identify which card we're reviewing
  master: d.nextCard().master,
  combination: d.nextCard().combination,

  // store when we reviewed it
  ts: new Date(),

  // store how easy it was to remember
  rating: 'easy'
};
reviews.push(review); // in a real app, we'd store this persistently
d.addReviews(review);

// Since we reviewed the current card, and marked it easy to remember, DolphinSR will move it into
// 'review' mode, which resembles classic SM2 spaced repetition. So everything else will still be in
// 'learn' mode, and it will be scheduled to be reviewed later.
d.summary(); // => { due: 0, later: 1, learning: 9, overdue: 0 }

// This will show the next card to review.
d.nextCard();

API

generateId(): Id

This generates a new ID for a master card. It uses the uuid package under the hood. Always use generateId() to generate IDs for your masters.

new DolphinSR()

Create a new DolphinSR instance, d.

(new DolphinSR()).addMasters(...masters: Master[]): void

Add masters to the DolphinSR instance. Masters with duplicate IDs will cause a runtime exception.

(new DolphinSR()).addReviews(...reviews: Review[]): boolean

Add reviews to the DolphinSR instance.

addReviews() is significantly more efficient if reviews are sorted in ascending order by ts, and all chronologically come after the previous latest review for any card. If this condition is met, addReviews() will return false. Otherwise, it returns true.

(new DolphinSR()).summary(): { due: number, later: number, learning: number, overdue: number }

Returns summary statistics for cards. Each category (due, later, learning, overdue) is a count.

  • Due cards are cards that the algorithm has determined should be reviewed on the day of the call. (That is, the current date as reflected by new Date().)
  • Overdue cards are cards that the algorithm has determined should be reviewed earlier than the day of the call.
  • Learning cards are cards that are either new and don't have any reviews, or cards that were forgotten (reviewed with an again rating) and not yet re-learned.
  • Later cards are cards that will be due in the future.

(new DolphinSR()).nextCard(): ?Card

Returns the next card to be reviewed, or null if there are no cards that need to be reviewed. Any card classified as due, overdue or learning by .summary() could appear in .nextCard().

Note: .nextCard() is deterministic--there is a defined order for prioritizing cards that are in different classifications and within classifications. That means that for any given set of masters and reviews added to a DolphinSR instance, nextCard() will return the same result.

Types

Master

A Master is an object conforming to the following Flow signature:

{
  id: Id, // from generateId()
  fields: Array<Field>, // see Field
  combinations: Array<Combination>, // see Combination
}

Field

A Field is a unit of data in a master. It is type alias for string.

Combination

A Combination is an object representing how Fields in a master should be combined to fit on a card with a front and a back. It looks like this:

{front: number[], back: number[]}

Rating

A Rating is an enum describing how well a user knows a specific combination of a master card. It can be (in descending order of ease):

  • 'easy'
  • 'good'
  • 'hard'
  • 'again'

Review

A Review is an object describing a review of a card by a user. It should look like this:

{
  master: Id,
  combination: Combination,
  ts: Date,
  rating: Rating,
}

Card

A Card is an object returned by .nextCard() which describes a part of a master suitable for displaying to a user. It should look like this:

{
  master: Id,
  combination: Combination,
  front: Array<Field>,
  back: Array<Field>
}

dolphinsr's People

Contributors

yodaiken avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.