eCardnomics is a desktop flashcard application to quickly create, manage, and access new flashcards via a Command Line Interface (CLI). eCardnomics is targeted at economics students in Junior College in Singapore, and aims to enhance students’ study experience as an efficient and handy aid for active recall.
The main goals of this application are to help students store and segment their economics subject syllabus into different decks, consolidate bite-sized information within each topic by way of flash cards, and offer a fun way for students to study and revise.
Summary: tP Code Dashboard
In short, I did the following:
In v1.0, I split the work with Wayne in implementing the Deck Mode commands. Specifically, I implemented:
DeleteCommand required me to implement a
y/n prompt method for the
Ui class, to be used by
was later used by all commands in the application that utilise
y/n prompts. Example of the user-interface of the
In v2.0, I implemented the Game Mode feature. For this, our
team originally thought it would be just another command implemented as part of Normal Mode or Deck Mode, but I felt
it deserved its own mode. I created a separate package,
game, and parser class
GameParser for Game Mode
, with the
game package abstracting away the entire Game Mode implementation from the rest of the application.
So the resulting
game package is structured as such:
game | Game | GameEngine | runGameLoop(), update() | GameStorage | originalDeck, deque, retestStore
Here, I tried as much as possible to incorporate the Single Responsibility Principle, both within the
and the SRP-ness of the existing classes.
Notable posts/responses posted in forum, and peer software testing:
Questions are displayed in a randomised order. At each question, the user will:
<enter>(optionally with an empty attempt).
Then, the correct answer is displayed, and our ‘advanced’ algorithm scores the user’s attempt against the correct answer. Finally, the user is given the option to re-attempt the question later. See below for example gamplay.
[Deck - Micro-Economics] > list // ------------------------------------------------------------ // You are now viewing deck: Micro-Economics // 1. Question: What is the Law of demand? // // 2. Question: What is the Law of supply? // // 3. Question: What is price elasticity of demand? // // 4. Question: What is price elasticity of supply? // ------------------------------------------------------------ [Deck - Micro-Economics] > start
Relevant Pull Requests for DG:
For a more contextual use case, consider the following scenario of Econs Wiz attempting the Game Mode for the first
Demand-Supply, in his deck list.
Note: Focus on the biggest box in the diagram!
Since there are quite a few things going on in this diagram, here are the key takeaways (the last of which arguably the most important):
retestStore) is updated upon the user’s attempt at each question and response to the prompt to include or exclude the flash card to be displayed again—if
ythen the flash card is added to the
deque) is emptied, i.e. all flash cards have been popped off and displayed to the user, the retest question pool (
retestStore) is consulted from which to create a new question pool (
deque) have been exhausted
For a more formal sequential flow of the inner workings of Game Mode, the following elaborates the execution
sequence of Game Mode, from after a
start command has been parsed in Normal Mode:
In the above diagram the key takeaway is the existence of an intermediary
game:Game object that holds
GameStorage together. In fact, this is the sole purpose of the
Game class: to hold the
current game instance, in a Single-Responsibility-Principle (SRP) and Object-Oriented Programming (OOP) manner.
This intermediary role of the
Game class is also illustrated in the upper part of the earlier use case
diagram. Note how it is from this
game object that the main game loop, run and managed by
GameEngine, is started.
The main game loop. As with all simple games, this flash card game mode is fundamentally built on the concept of a
possibly never-ending game loop with specific end conditions. In this case, the main end condition is explicitly
command object that is parsed and returned upon the
getAttempt() call (that prompts the user for an
answer attempt) is either a
This is not the only end condition, though, because the other important but implicit end scenario is when the question pool is exhausted (i.e.,
storage.dequeis empty) and the retest question pool (
storage.retestStore) is empty.
Naturally, the other sequence of special note here is the whole
update() sequence, and even more specifically the
updateDeque() call within the
update() sequence. Notice how
.retestStore) with the
retestStore as argument. This essentially creates a new randomised question pool from the
retest question pool.
Notice how this
updateDeque() sequence is only called exactly when the
storage.deque is empty (i.e., when all
questions have been popped off the question pool). This is important because it ensures that the user encounters all
available questions in the
deque at least once before the retest questions are later displayed. Cross-check this
with the detailed descriptions of the inner workings of the game loop implementation shown in the earlier
architecture and use case diagrams.
Lastly, notice how
refreshRetestStore() is called at the end of
updateDeque() to, as its name suggests, clear the
retest question pool to get ready to store the next wave of retest questions. This is also covered in the bottom few
lines of the
GameEngine portion of the use case diagram.