Flash Card manager for Economics students on Command Line.
See also: User Guide | Releases | Team Project Portfolio Page |
The Architecture Diagram given above explains the high-level design of the Flash Card Manager Application.
Main
is responsible for initializing the other components in the program and linking them up correctly.
Ui
Takes in instructions from user and displays the output to the userLogic
Consists of the Parsers
and the Commands
. The Parser
decipher the user input and executes the specific Command
that affects the change the user wishes.Model
Holds the data that is in memory as the program runs. It consists of the 3 components:
Flash Card
: A single question and answer pair.Deck
: A list of Flash Card
s under a common topic.Deck List
: A complete list of all the Deck
s in memory.Storage
Reads and writes data from and to a text file.The following Sequence Diagram shows how the components interact for a basic create <deck name>
command where a new deck is created and added in to the Deck List
.
The sequence shown is as follows:
Main
instance runs and calls the readUserInput()
of Ui
. The function waits for the user to key in one line of input
and then returns that input as a String to Main
. Main
calls parse
of which creates a new CreateCommand
and this is returned to Main
.
This section will be explained in details in the Parser
section later on.
Main
then calls for execute()
of the CreateCommand
that calls addDeck()
of DeckList
and subsequently printNewDeck()
of Ui
which prints the output to the user.
Finally, Main
calls write()
of Storage
to write the updated Deck List to the text file.API: seedu/ecardnomics/Ui.java
The Ui
contains String constants that represent the outputs that the application is defined to produce.
The Ui
component has two main purposes:
Reading of user input is done using the method readUserInput()
which reads one line of user input. The other methods within Ui
are
called when a specific output needs to be printed.
The Ui
component passes the user input to the NormalParser
, DeckParser
and
GameParser
components that will extract the relevant information.
The Ui
component provides its printing methods to NormalParser
, DeckParser
and GameParser
for printing the appropriate output when required.
This is an overview of interactions between objects in eCardnomics program.
Parser
class and Command
class.Parser
parses the user input and creates the respective Command
object.Main
class.There are three types of parsers: NormalParser
, DeckParser
and GameParser
. They will be executed
corresponding to the mode users are in. Users input in Normal Mode, Deck Mode or Game Mode will be parsed using the
respective parser. All are children classes of abstract class Parser, where there are three abstract methods:
Three Parsers will parse inputs from user and turns them to valid arguments for Command object creation. NormalParser will return NormalCommand, DeckParser will return DeckCommand and GameParser will return GameCommand. And all three can create everywhere Command such as ExitCommand.
API: seedu.ecardnomics/command
Commands are primarily classified into three categories, NormalCommand
, DeckCommand
, and GameCommand
,
corresponding to the application’s Normal, Deck, and Game Modes, respectively. All three are abstract children
derived from the overarching abstract class Command
. The basis Command
class is defined as such:
public abstract class Command {
public abstract void execute();
}
It only requires that all derived children implement the execute()
method. The only two classes not belonging to
individual modes are ExitCommand
and VoidCommand
. The former is so that users can call the command exit
from anywhere in the application, while the latter is a catch-all “command” for all erroneous commands a user
enters.
The specific commands defined within the different Modes are shown below; one can simply substitute the Normal Mode
Commands
, Game Mode Commands
and Deck Mode Commands
components in the above UML class diagram with the
corresponding Command
classes, with all of the classes inheriting from the corresponding abstract classes, and
being associated (with arrows pointing towards) with the corresponding Parser
classes.
Notice that the same StartCommand
class above is indicated as being in both Normal Mode and Deck Mode. While the
diagram does not explain this phenomenon fully, the idea is there: that start
is a command that can be run from
within Deck Mode, but that its implementation is passed to NormalParser
to be handled as a Normal Mode command
. More specifically, within the specification of DeckParser
’s parseCommand()
method, the case of command
word being parsed as start
will in turn call NormalParser
’s parseCommand()
method, supplementing it with
DeckParser
’s Deck class field object as the arguments
String.
The Parser
classes play important roles in execution of specific commands, e.g. CreateCommand
, because
they define methods that check and ensure the conformity of user input to the commands’ expected input. Below is a
sequence diagram showcasing this interaction, for execution of a CreateCommand
, e.g. create
microeconomics
:
Here, parse()
first splits the user input create microeconomics
into two strings, “create” and “microeconomics”,
the command word and command arguments respectively. Then within the parseCommand()
call in NormalParser
, a
dedicated method to create a new deck based on the argument string “microeconomics”, prepareNewDeck()
, is called
. A new Deck
object is returned to the same parseCommand()
call and used to create the new
CreateCommand
object, which is then propagated back to Main
(not shown here) that called parse()
.
Note that the
CreateCommand
object is not marked as deleted in the above diagram because its lifeline does not really end until itsexecute()
method has been called fromMain
, usingMain
’sexecuteCommand()
.
The Deck Model component is made up of three parts:
DeckList
Deck
FlashCard
The FlashCard
component represents a flashcard, storing question
and answer data. The Deck
represents a collection of flashcards
related by a common topic. The DeckList
represents the collection
of all the Deck
objects that the user has.
Only the Command
components can modify the DeckList
, Deck
and
FlashCard
components. However, Ui
, DeckParser
and NormalParser
are able to read data from the DeckList
, Deck
and FlashCard
components.
API: seedu/ecardnomics/storage
Storage of this application uses basic .txt
read and write functions.
Upon start of the program, the application checks whether there is a ./data
folder and creates one if there isn’t.
Then, it reads from the storage file deckList.txt
line by line to create:
Deck
FlashCard
and adds them to the current deckList
passed into the load
method call.
Similarly, for writing the data into .txt
file, the Storage will loop through all the current Decks
and their
current FlashCards
and write them in a specific format in the text file in the ./data
folder.
API: seedu/ecardnomics/exceptions
How to read the diagram above:
NormalParser
’s prepareNewDeck()
method throws EmptyInputException
NormalParser
’s getIndex()
and prepareDeck()
methods additionally throw
DeckRangeException
, on top of throwing IndexFormatException
An additional feature targeted at students who wish to add more style to their flash cards outside of the command line option to keep things interesting when they are revising.
The PowerPointCommand
is parsed by NormalParser
but the “Print to PowerPoint” command can be called from both Normal
and Deck Mode.
The following diagram shows how the PowerPointCommand
’s execute()
calls the createNewPowerPoint()
method of
PowerPoint
. execute()
first checks if the whether isPptxCreated
is true
and only creates the PowerPoint if
so. This is necessary as the user might have input the command pptx
but when prompted for confirmation, they input
n
which means no, but the parser will still output a PowerPointCommand
except with the element isPptxCreated
as false
and thus, when executed, nothing happens.
The newIntroSlide()
, newSlide()
and exportSlide()
method of PowerPoint
uses a third party library -
Apache POI
to create new slides, populate them with the questions and answers from the deck and finally print them out to a new
PowerPoint file in the pptx
folder under the name <deck name>.pptx
.
The following are the Classes/ Enum of the third party package org.apache.poi.xslf.usermodel
which are used:
SlideLayout
- Enum representing the Slide Layouts availableXMLSlideShow
- Class representing an entire Slide ShowXSLFSlide
- Class representing a single SlideXSLFSlideLayout
- Class representing the layout of a slideXSLFSlideMaster
- Class representing the default slides layoutsXSLFTextShape
- Class representing a shape within a slideXSLFTextParagraph
- Class representing a paragraph of text within a shapeXSLFTextRun
- Class representing the properties of the text within a paragraphThe 3 modes of Color Selection, DEFAULT
, COLOR_SCHEME
and ORIGINAL_COLOR
are stored in the enum ColorOption
.
The java.awt.Color
class itself has no methods to generate colors based on a given string. Thus, I used the
ColorFactory API
which has a public static method, valueOf()
which
takes in a string and outputs a Color
object if the String matches any of the available colors documented
here.
This is done in the constructor of PowerPoint
where bgColor = ColorFactory.valueOf(bgColorString)
(same for
txtColor
).
Each instance of PowerPoint
has an element of the enum ColorOption
, colorOpt
, which decides which of the outputs
to print back to the user. NormalParser
’s preparePptxCommand
create a PowerPointCommand
instance using different
constructors depending on the mode of Color Selection. The PowerPointCommand
then creates a PowerPoint
instance with
the respective constructor the assigns the respective value of colorOpt
. Below are the PowerPointCommand
and
PowerPoint
constructors used in each mode.
PowerPointCommand(deck, deckList, isPptxCreated)
and PowerPoint(deck)
.PowerPointCommand(deck, deckList, isPptxCreated, csIndex)
and PowerPoint(deck, csIndex)
PowerPointCommand(deck, deckList, isPptxCreated, bgColorString, txtColorString, bgColor, txtColor)
and PowerPoint(deck, bgColorString, txtColorString, bgColor, txtColor)
pptx
commandNormal Parser:
getCsIndex()
- for -cs
option
CsIndexRangeException
or
not in the correct format, CsIndexFormatException
.preparePptxCommand()
- for the rest of the options
ColorsNotAvailException
when the at least one of the colors chosen is not
a valid color. (-cs
option only)BothCsAndOcException
.-
will trigger the exception, InvalidOptionsException
.Deck Parser:
* checkForValidPptxArguments()
* If any other arguments other than the 3 options are present for pptx
command in Deck mode, the exception,
InvalidPptxArgumentException
will be thrown.
* Just like preparePptxCommand()
from NormalParser
, the function also checks for invalid options and throw
InvalidOptions
when there are any.
The purpose of this feature is to improve the readability of the command line text output for the user, in particular, the question and answer fields of a flashcard . Without this feature, long text outputs would follow the default wrapping style of the console. When words are truncated unnecessarily, it is going to be distracting and annoying for students trying to study. We illustrate the problem with the following example:
This is a long question (or maybe answer) field. Suppose tha
t our console is 60 characters wide, we see that the word "t
hat" was truncated in the first line and again in the second
line.
In this section, we define the following terms:
lineLength
is the maximum number of characters on a line, set to be equal to Ui.DASH_LINES.length()
. This is
also the number of characters between the start of line and end of line.offset
is the number of characters after the start of the line before the target string will be printed.usableLength
is the number of characters that can be used for printing the output.
This is Ui.DASH_LINES.length() - offset
.The prettyPrintFormatter(String target, int offset)
static method of the Ui
class takes as argument the
target string to be formatted for printing as well as the offset. The formatted String is returned to the caller for
printing. This is illustrated in the following sequence diagram:
Note:
The lifeline on the left represents the calling method that requires a formatted string. The
printMethod()
is a placeholder for any of the printing methods ofUi
class. The call toSystem.out.println
is omitted. Minimal notation is used for the return of control to the calling method.
The offset
parameter specifies the number of characters already
printed on the line before the target string will be printed.
prettyPrintFormatter()
places as many words as possible on each line until
the next word does not fit within the usableLength
of the current
line. This word is therefore placed on the next line and the process
repeats until all the words have been formatted into the response. If
the length of a single word exceeds the usableLength
, the word is
split across multiple lines to prevent the program from looping
infinitely as it would never be able to fit the word on any line.
Take note that infinite loops can still occur if prettyPrintFormatter()
is called with offset >= lineLength
The purpose of this feature is to provide a means to group the decks based on their subjects and search for relevant decks related to one or more relevant subjects in a robust way. Each created deck will be tagged to their respective field.
The user can also modify the tags of the decks by using tag
or untag
command, and use search
by tag to find
a group of decks he/she is interested in.
eCardnomics’ quintessential mode. Game Mode can be started from either Normal Mode or Deck Mode. The start
command
is parsed by NormalParser
(see Commands).
Game Mode contains two main components: a storage component, GameStorage
, and a logic component, GameEngine
. The
former handles all data structures used by Game Mode, and stores the original deck (originalDeck
), question pool
(deque
), and retest question pool (retestStore
). The latter executes the main game loop
(runGameLoop
()
), and
interacts with GameStorage
on package-private basis; i.e., GameEngine
and GameStorage
have full mutual
access as if they were a single class. This is one of the main intentional design decisions.
The schematic below describes the individual responsibilities of the GameStorage
and GameEngine
classes (or
components) of Game Mode as introduced above, and also two key interactions between the two classes, namely via
GameEngine
’s update(isResponseY:boolean, flashCard:FlashCard)
and poseQuestion()
method calls. For
context, poseQuestion()
pops the top flash card off GameStorage
’s question pool deque
to display to the user
, while update()
is the GameEngine
method that adds to the retest question pool retestStore
when the user chooses to do so (via isResponseY == true
). This essentially describes one iteration of
runGameLoop()
; more explanation and a full-blown illustration and sequence are given further below.
See also: Gameplay description
The actual “game” aspect of eCardnomics is essentially summarised in the runGameLoop()
high-level overview above
. For a textual gameplay description, check out the “See also” link.
For a more contextual use case, consider the following scenario of Econs Wiz attempting the Game Mode for the first
deck, 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 y
then the flash card is added to the
retestStore
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
)deque
) have been exhaustedFor 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
GameEngine
and 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
that the command
object that is parsed and returned upon the getAttempt()
call (that prompts the user for an
answer attempt) is either a DoneGameCommand
or ExitCommand
.
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.deque
is 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 updateDeque()
calls
createRandomisedStack(storage.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.
Junior College Economics Students.
Anybody > Students > Students in courses with high amount of content > Economics students > Junior College Economics students (focus on theory than calculations)
Flashcard application that allows students to quickly create new flashcards and access flashcards quickly on the command line to enhance their studying experience, and ultimately be an aid for active recall.
Version | As a(n) … | I want to … | So that I can … |
---|---|---|---|
v1.0 | poor student | have small computer programs | run it on my old computer |
v1.0 | fast typist | have an easily-navigable interface to type up notes and store them | create and manage notes quickly and efficiently |
v1.0 | smart student | be able to use the system effectively and efficiently | save time and maximise my productivity |
v1.0 | JC econs student | quickly create short notes of key concepts | keep up during lectures and tutorials |
v1.0 | tech-savvy student | have a software tool to store my notes | stop needing to worry about losing my hardcopy notes |
v1.0 | lazy student | create flashcards to keep my notes concise | learn at a comfortable, incrementing pace |
v2.0 | organised student | have my notes be stored in a systematic way | retrieve them quickly and easily |
v2.0 | student | have a system that can categorise material into different topics | quickly revise all the content for a topic when studying for an exam |
v2.0 | hardworking student | have a studying system that can help me memorise content in a non-traditional manner | remember all the facts during an exam through active recall |
v2.0 | busy student | have my notes available outside of CLI | study while on the go and not waste any time |
pptx
command.ArrayDeque
and functions as a stack of shuffled flash cards, from which questions are popped off during Game Mode.Starting the program:
ecardnomics.jar
file and copy it into an empty folder where read, write and execute permissions
are allowed.java -jar ecardnomics.jar
in a command line terminal to start the program.Creating a deck:
decks
does not show any entry ‘test deck’ or ‘tag deck’.create test deck
decks
shows the entry ‘test deck’.create test deck
after running the above testdecks
shows only one entry ‘test deck’.create tag deck /tag test
decks
shows the entry ‘tag deck’ with tag ‘test’.Deleting a deck:
decks
shows at least two decks.delete 1
followed by y
when prompteddelete 1
followed by n
when prompteddelete 1
followed by any input that is not ‘y/n’ surrounded with spaces when prompteddelete 1 -y
delete 0 -y
Tagging and untagging a deck:
decks
shows at least one deck.tag 1 /tag testing
followed by y
when prompteddecks
shows the first entry with tag ‘testing’.tag 1 /tag testing
followed by n
when prompteddecks
shows the first entry without tag ‘testing’.untag 1 /tag testing
followed by y
when prompteddecks
shows the first entry without tag ‘testing’.tag 1 /tag
untag 1 /tag
Searching a deck by tag:
search test
search LOL
Printing a deck to PowerPoint:
pptx 1
followed by y
when prompted pptx 1 -y
pptx 1 -y -cs 1
pptx 1 -y -oc black red
pptx 1 -y -cs black red
pptx 1 -y -cs 11
pptx 1 -y -oc block red
pptx 1 -y -cs 1 -oc black red
pptx 1 -y -cc 11
Editing a deck:
edit 1
edit -1
Adding a flashcard:
add
followed by ‘question’ and ‘answer’ when promptedlist /ans
shows the entry for the new flashcard.add question /ans answer
list /ans
shows the entry for the new flashcard.add question/answer
followed by ‘answer’ when promptedlist /ans
shows the entry for the new flashcard.add /ans
add /ans answer
Deleting a flashcard:
list
shows at least two flashcards.delete 1
followed by y
when prompteddelete 1
followed by n
when prompteddelete 1
followed by any input that is not ‘y/n’ surrounded with spaces when prompteddelete 1 -y
delete 0 -y
Updating a flashcard:
update 1
followed by ‘question’ and ‘answer’ when promptedlist /ans
shows that the entry for the first flashcard is updated.update 1
followed by ‘ ‘ and ‘answer’ when promptedlist /ans
shows that the answer for the first flashcard is updated.update 1
followed by ‘question’ and ‘ ‘ when promptedlist /ans
shows that the question for the first flashcard is updated.update 1
followed by ‘ ‘ and ‘ ‘ when promptedlist /ans
shows that the question for the first flashcard is not updated.Starting game mode:
start 1
start
<enter>
with no attemptdone
or exit
done
returns user to normal mode, exit
exits the program.Saving data to disk: