-
Notifications
You must be signed in to change notification settings - Fork 315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Ryan Chew] Duke Increments #355
base: master
Are you sure you want to change the base?
Changes from 8 commits
65f72a8
0112efe
7faa65a
46c55c6
94b4414
4cec14a
013cc37
9303e1d
5abe5d0
11f4134
3ec4d4e
b79c5c0
3a0d632
0139127
16718fb
8dd4b9b
d7e9187
501ae91
9880921
db72071
6ca4441
1cf63ce
f5ccf6e
a0d17c1
0b162a2
c842c6f
355f065
93b6e1c
dce444a
45172d8
9f28efa
ed5ea49
8c16531
c907b2c
c5eee9a
af1b0d4
7e2227e
e0b6066
63d9c81
3bfe760
1e6e594
31fb5b4
b04abda
354adca
f653e2d
7ea74be
00772ef
6d9eb22
1eebc7b
b508421
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import java.util.Map; | ||
import java.util.HashMap; | ||
import java.util.regex.Pattern; | ||
public class Command { | ||
public final String type; | ||
public final String arguments; | ||
public final Map<String,String> namedArguments; | ||
|
||
public Command(String type, String arguments, Map<String, String> namedArguments) { | ||
this.type = type; | ||
this.arguments = arguments; | ||
this.namedArguments = namedArguments; | ||
} | ||
|
||
private static final Pattern switchBoundary = Pattern.compile("\\s+/"); | ||
private static final Pattern cmdBoundary = Pattern.compile("\\s+"); | ||
|
||
public static Command parse(String input) { | ||
input = input.trim(); | ||
|
||
//Split on the presence of any switches | ||
String[] splits = switchBoundary.split(input); | ||
|
||
//First split value is "cmd-type args..." | ||
String[] mainArgs = cmdBoundary.split(splits[0], 2); | ||
if(mainArgs[0].isEmpty()) { | ||
return null; | ||
} | ||
|
||
String type = mainArgs[0]; | ||
//If no arguments, leave as empty string | ||
String arguments = mainArgs.length > 1 ? mainArgs[1] : ""; | ||
Map<String, String> namedArguments = new HashMap<>(); | ||
|
||
if(splits.length > 1) { | ||
//Each split value is "switch-name args..." | ||
//with no preceding slash | ||
for(int i=1;i<splits.length;i++) { | ||
if(splits[i].isEmpty()) { | ||
continue; | ||
} | ||
//Split at first whitespace | ||
String[] switchArgs = cmdBoundary.split(splits[i], 2); | ||
String switchName = switchArgs[0]; | ||
//If no arguments, leave as empty string | ||
String switchArguments = switchArgs.length > 1 ? switchArgs[1] : ""; | ||
namedArguments.put(switchName, switchArguments); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find it a bit confusing to use |
||
} | ||
} | ||
return new Command(type, arguments, namedArguments); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import java.util.function.Function; | ||
|
||
class CounterDecorator implements Function<String, String> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like that you create a class to format the string representation of a |
||
private int counter; | ||
public CounterDecorator(int start) { | ||
this.counter = start; | ||
} | ||
public String apply(String str) { | ||
String ret = String.format("%d: %s", this.counter, str); | ||
this.counter++; | ||
return ret; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
public class DeadlineTask extends Task { | ||
private final String deadline; | ||
|
||
public DeadlineTask(String task, String deadline) { | ||
super(task); | ||
this.deadline = deadline; | ||
} | ||
|
||
@Override | ||
protected String getTypeMarker() { | ||
return "[D]"; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
String baseDescription = super.toString(); | ||
return String.format("%s (by: %s)", baseDescription, deadline); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,105 @@ | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
import java.util.function.Predicate; | ||
|
||
public class Duke { | ||
|
||
private static final String[] initialGreeting = new String[]{ | ||
"Hello! I'm Duke", | ||
"What can I do for you?" | ||
}; | ||
|
||
private DukeIO io; | ||
private final List<Task> taskList; | ||
|
||
private void addTask(Task t) { | ||
this.taskList.add(t); | ||
this.io.say( | ||
"Got it. I've added this task:", | ||
" " + t, | ||
String.format("Now you have %d task%s in the list.", | ||
this.taskList.size(), | ||
this.taskList.size() == 1 ? "" : "s") | ||
); | ||
} | ||
|
||
private boolean handleBye(Command input) { | ||
this.io.say("Bye. Hope to see you again soon!"); | ||
return true; | ||
} | ||
|
||
private boolean displayList(Command input) { | ||
this.io.say(this.taskList.stream() | ||
.map(Object::toString) | ||
.map(new CounterDecorator(1)) | ||
.iterator()); | ||
return false; | ||
} | ||
|
||
private boolean makeDeadlineTask(Command input) { | ||
String description = input.arguments; | ||
String deadline = input.namedArguments.get("by"); | ||
if(deadline == null) { | ||
deadline = "unknown"; | ||
} | ||
|
||
DeadlineTask task = new DeadlineTask(description, deadline); | ||
|
||
this.addTask(task); | ||
return false; | ||
} | ||
private boolean makeToDoTask(Command input) { | ||
this.addTask(new Task(input.arguments)); | ||
return false; | ||
} | ||
|
||
private boolean markAsDone(Command input) { | ||
int index; | ||
try { | ||
index = Integer.parseInt(input.arguments); | ||
} catch(NumberFormatException e) { | ||
this.io.say("Index provided was not an integer!"); | ||
return false; | ||
} | ||
|
||
if(index < 0 || index > this.taskList.size()) { | ||
this.io.say("There's no task with that index!"); | ||
return false; | ||
} | ||
|
||
Task selectedTask = this.taskList.get(index-1); | ||
selectedTask.markComplete(); | ||
this.io.say("Nice! I've marked this task as done:", | ||
" " + selectedTask); | ||
return false; | ||
} | ||
|
||
private Duke() { | ||
this.io = new DukeIO(); | ||
//Bind command handlers | ||
this.io.bindCommand("list", this::displayList); | ||
this.io.bindCommand("done", this::markAsDone); | ||
this.io.bindCommand("bye", this::handleBye); | ||
this.io.bindCommand("deadline", this::makeDeadlineTask); | ||
this.io.bindCommand("todo", this::makeToDoTask); | ||
|
||
this.taskList = new ArrayList<>(); | ||
} | ||
|
||
private void run() { | ||
//Start off greeting the user. | ||
this.io.say(initialGreeting); | ||
|
||
//Start listen loop. | ||
this.io.listen(); | ||
} | ||
|
||
public static void main(String[] args) { | ||
String logo = " ____ _ \n" | ||
+ "| _ \\ _ _| | _____ \n" | ||
+ "| | | | | | | |/ / _ \\\n" | ||
+ "| |_| | |_| | < __/\n" | ||
+ "|____/ \\__,_|_|\\_\\___|\n"; | ||
System.out.println("Hello from\n" + logo); | ||
Duke duke = new Duke(); | ||
duke.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import java.util.Arrays; | ||
import java.util.Iterator; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Scanner; | ||
import java.util.function.Predicate; | ||
|
||
public class DukeIO { | ||
|
||
private static final String lineRule = | ||
"____________________________________________________________"; | ||
|
||
private final Map<String, Predicate<Command>> commandMap | ||
= new HashMap<>(); | ||
private Predicate<Command> defaultHandler = null; | ||
|
||
private final Scanner scanner; | ||
|
||
public DukeIO() { | ||
this.scanner = new Scanner(System.in); | ||
} | ||
|
||
public void say(String... lines) { | ||
say(Arrays.asList(lines).iterator()); | ||
} | ||
public void say(Iterator<String> lines) { | ||
//Print start of reply line | ||
System.out.println(lineRule); | ||
|
||
//Print each given line | ||
while(lines.hasNext()) { | ||
System.out.println(lines.next()); | ||
} | ||
|
||
//Print end of reply line, and extra empty line | ||
System.out.println(lineRule); | ||
System.out.println(); | ||
} | ||
|
||
public void bindCommand(String command, Predicate<Command> handler) { | ||
this.commandMap.put(command, handler); | ||
} | ||
|
||
public void setUnknownCommandHandler(Predicate<Command> handler) { | ||
this.defaultHandler = handler; | ||
} | ||
|
||
public void listen() { | ||
//While there is still input from user | ||
while(scanner.hasNextLine()) { | ||
//Read single line of user input, and remove extra spaces | ||
String userInput = scanner.nextLine(); | ||
|
||
Command command = Command.parse(userInput); | ||
|
||
Predicate<Command> cmdHandler = commandMap.get(command.type); | ||
boolean shouldExit; | ||
if(cmdHandler != null) { | ||
shouldExit = cmdHandler.test(command); | ||
} else if(defaultHandler != null) { | ||
shouldExit = defaultHandler.test(command); | ||
} else { | ||
say(String.format("Unknown command %s", command.type)); | ||
shouldExit = false; | ||
} | ||
|
||
if(shouldExit) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
public class Task { | ||
private final String description; | ||
private boolean completed; | ||
|
||
public Task(String description) { | ||
this.description = description; | ||
this.completed = false; | ||
} | ||
|
||
public void markComplete() { | ||
this.completed = true; | ||
} | ||
|
||
public boolean isCompleted() { | ||
return this.completed; | ||
} | ||
|
||
private static final String completedMarker = "[✓]"; | ||
private static final String incompleteMarker = "[✗]"; | ||
|
||
protected String getTypeMarker() { | ||
return "[T]"; | ||
} | ||
|
||
private String getCompleteMarker() { | ||
return this.completed ? completedMarker : incompleteMarker; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return this.getTypeMarker() + this.getCompleteMarker() + ' ' + this.description; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be more readable to include spaces to become
for (int i = 1; i < splits.length; i++)