From c8306a0794c470c282dd0c52e8cc06d68781dbc8 Mon Sep 17 00:00:00 2001 From: Michael Lizzio Date: Sun, 9 Nov 2025 14:57:49 -0500 Subject: Basic undo Mememto Pattern --- src/main/java/design/model/undo/Memento.java | 4 ++ src/main/java/design/model/undo/Originator.java | 7 ++ src/main/java/design/model/undo/UndoManager.java | 91 ++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/main/java/design/model/undo/Memento.java create mode 100644 src/main/java/design/model/undo/Originator.java create mode 100644 src/main/java/design/model/undo/UndoManager.java (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/undo/Memento.java b/src/main/java/design/model/undo/Memento.java new file mode 100644 index 0000000..162c3f3 --- /dev/null +++ b/src/main/java/design/model/undo/Memento.java @@ -0,0 +1,4 @@ +package design.model.undo; + +public interface Memento { +} diff --git a/src/main/java/design/model/undo/Originator.java b/src/main/java/design/model/undo/Originator.java new file mode 100644 index 0000000..63eac38 --- /dev/null +++ b/src/main/java/design/model/undo/Originator.java @@ -0,0 +1,7 @@ +package design.model.undo; + +public interface Originator { + Memento createMemento(); + + void restore(Memento memento); +} \ No newline at end of file diff --git a/src/main/java/design/model/undo/UndoManager.java b/src/main/java/design/model/undo/UndoManager.java new file mode 100644 index 0000000..5c6a4a0 --- /dev/null +++ b/src/main/java/design/model/undo/UndoManager.java @@ -0,0 +1,91 @@ +package design.model.undo; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; + +// Singleton caretaker that handles undo and redo stacks. +public final class UndoManager { + + private static final UndoManager INSTANCE = new UndoManager(); + + public static UndoManager instance() { + return INSTANCE; + } + + private UndoManager() { + } + + // Stack entry + private static class Entry { + final Originator originator; + final Memento memento; + final String label; + + Entry(Originator originator, Memento memento, String label) { + this.originator = originator; + this.memento = memento; + this.label = label; + } + } + + private final Deque undoStack = new ArrayDeque<>(); + private final Deque redoStack = new ArrayDeque<>(); + + // Capture state + public void capture(Originator originator, String label) { + undoStack.push(new Entry(originator, originator.createMemento(), label)); + redoStack.clear(); + } + + // Undo / Redo ops + public boolean canUndo() { + return !undoStack.isEmpty(); + } + + public boolean canRedo() { + return !redoStack.isEmpty(); + } + + public String peekUndoLabel() { + return canUndo() ? undoStack.peek().label : null; + } + + public String peekRedoLabel() { + return canRedo() ? redoStack.peek().label : null; + } + + public List getUndoHistoryLabels() { + return undoStack.stream() + .map(e -> e.label) + .collect(Collectors.toList()); + } + + public void undo() { + if (!canUndo()) { + System.out.println("Nothing to undo."); + return; + } + + Entry entry = undoStack.pop(); + redoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label)); + entry.originator.restore(entry.memento); + } + + public void redo() { + if (!canRedo()) { + System.out.println("Nothing to redo."); + return; + } + + Entry entry = redoStack.pop(); + undoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label)); + entry.originator.restore(entry.memento); + } + + public void purge() { + undoStack.clear(); + redoStack.clear(); + } +} -- cgit v1.2.3 From 873c9c81fab807127fb70e5abb88c8f96c9d8934 Mon Sep 17 00:00:00 2001 From: Michael Lizzio Date: Mon, 10 Nov 2025 14:19:24 -0500 Subject: Added GolferMememto, updated Golfer --- src/main/java/design/model/Golfer.java | 51 +++++++++++++++++++++- .../design/model/holeplay/HolePlayContext.java | 17 +++++++- 2 files changed, 66 insertions(+), 2 deletions(-) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/Golfer.java b/src/main/java/design/model/Golfer.java index 48daae8..0f4c914 100644 --- a/src/main/java/design/model/Golfer.java +++ b/src/main/java/design/model/Golfer.java @@ -6,8 +6,11 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import java.util.ArrayList; import java.util.List; +import design.model.undo.Memento; +import design.model.undo.Originator; + @JsonPropertyOrder({ "clubs", "nextClubId" }) -public class Golfer { +public class Golfer implements Originator { private String username; private int passwordHash; private String fullName; @@ -112,4 +115,50 @@ public class Golfer { public void removeClub(Club c) { clubs.remove(c); } + + // Takes a snapshot of the golfer + private static class GolferMemento implements Memento { + private final String username; + private final int passwordHash; + private final String fullName; + private final List courses; + private final List rounds; + private final List clubs; + private final int nextClubId; + + GolferMemento(Golfer g) { + this.username = g.username; + this.passwordHash = g.passwordHash; + this.fullName = g.fullName; + this.courses = new ArrayList<>(g.courses); + this.rounds = new ArrayList<>(g.rounds); + this.clubs = new ArrayList<>(g.clubs); + this.nextClubId = g.nextClubId; + } + } + + @Override + public Memento createMemento() { + return new GolferMemento(this); + } + + @Override + public void restore(Memento memento) { + GolferMemento gm = (GolferMemento) memento; + + this.username = gm.username; + this.passwordHash = gm.passwordHash; + this.fullName = gm.fullName; + + this.courses.clear(); + this.courses.addAll(gm.courses); + + this.rounds.clear(); + this.rounds.addAll(gm.rounds); + + this.clubs.clear(); + this.clubs.addAll(gm.clubs); + + this.nextClubId = gm.nextClubId; + } } diff --git a/src/main/java/design/model/holeplay/HolePlayContext.java b/src/main/java/design/model/holeplay/HolePlayContext.java index 7a5d8ef..16201b6 100644 --- a/src/main/java/design/model/holeplay/HolePlayContext.java +++ b/src/main/java/design/model/holeplay/HolePlayContext.java @@ -6,7 +6,10 @@ import java.util.ArrayList; import design.model.*; import design.persistence.PersonalDatabase; -public class HolePlayContext { +import design.model.undo.Memento; +import design.model.undo.Originator; + +public class HolePlayContext implements Originator { private final Golfer golfer; private final Round round; private final PersonalDatabase pdb; @@ -109,4 +112,16 @@ public class HolePlayContext { void setStrokes(int s) { this.strokes = s; } + + @Override + public Memento createMemento() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'createMemento'"); + } + + @Override + public void restore(Memento memento) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'restore'"); + } } \ No newline at end of file -- cgit v1.2.3 From a29285b3aaf19becc74ef5b2755052aed8782a57 Mon Sep 17 00:00:00 2001 From: Michael Lizzio Date: Mon, 10 Nov 2025 14:25:30 -0500 Subject: Added HolePlayMemento with sanpshots and restore --- .../design/model/holeplay/HolePlayContext.java | 54 ++++++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/holeplay/HolePlayContext.java b/src/main/java/design/model/holeplay/HolePlayContext.java index 16201b6..71fba32 100644 --- a/src/main/java/design/model/holeplay/HolePlayContext.java +++ b/src/main/java/design/model/holeplay/HolePlayContext.java @@ -113,15 +113,59 @@ public class HolePlayContext implements Originator { this.strokes = s; } + // Captures current State, current play (hole# + swings), and stroke counter + private static class HolePlayMemento implements Memento { + private final String stateName; + private final Play currentPlayCopy; + private final int strokesCopy; + + HolePlayMemento(HolePlayContext ctx) { + this.stateName = ctx.state.name(); + + // Copy currentPlay if it exists + Play src = ctx.currentPlay; + if (src != null) { + var copySwings = new ArrayList(); + for (Swing s : src.getSwings()) { + copySwings.add(new Swing(s.getDistance(), s.getClubUsed())); + } + this.currentPlayCopy = new Play(src.getHoleNumber(), copySwings); + } else { + this.currentPlayCopy = null; + } + + this.strokesCopy = ctx.strokes; + } + } + @Override public Memento createMemento() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'createMemento'"); + return new HolePlayMemento(this); } @Override - public void restore(Memento memento) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'restore'"); + public void restore(Memento m) { + HolePlayMemento hm = (HolePlayMemento) m; + + // restore strokes + this.strokes = hm.strokesCopy; + + // restore currentPlay + if (hm.currentPlayCopy == null) { + this.currentPlay = null; + } else { + var copySwings = new ArrayList(); + for (Swing s : hm.currentPlayCopy.getSwings()) { + copySwings.add(new Swing(s.getDistance(), s.getClubUsed())); + } + this.currentPlay = new Play(hm.currentPlayCopy.getHoleNumber(), copySwings); + } + + // restore state based on name + switch (hm.stateName) { + case "SetupState" -> this.state = new SetupState(); + case "PlayState" -> this.state = new PlayState(); + case "HoleCompleteState" -> this.state = new HoleCompleteState(); + } } } \ No newline at end of file -- cgit v1.2.3 From fcf058c1999e4d23fd9e79e021901dbb39095367 Mon Sep 17 00:00:00 2001 From: Jacob Shimp Date: Tue, 11 Nov 2025 08:48:38 -0500 Subject: Added list of matches --- src/main/java/design/model/League.java | 3 ++- src/main/java/design/model/ScrambleLeague.java | 8 ++++---- src/main/java/design/model/StrokeLeague.java | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/League.java b/src/main/java/design/model/League.java index 0252f89..6621513 100644 --- a/src/main/java/design/model/League.java +++ b/src/main/java/design/model/League.java @@ -3,6 +3,7 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; import java.util.Date; +import java.util.List; public abstract class League { private int id; @@ -13,7 +14,7 @@ public abstract class League { private final Golfer owner; @JsonCreator - protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List schedule) { this.id = id; this.name = name; this.registrationDate = registrationDate; diff --git a/src/main/java/design/model/ScrambleLeague.java b/src/main/java/design/model/ScrambleLeague.java index 7ff966e..92e7099 100644 --- a/src/main/java/design/model/ScrambleLeague.java +++ b/src/main/java/design/model/ScrambleLeague.java @@ -10,13 +10,13 @@ public class ScrambleLeague extends League { private final List participants; @JsonCreator - private ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List participants) { - super(id, name, registrationDate, startDate, endDate, owner); + private ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List participants, List schedule) { + super(id, name, registrationDate, startDate, endDate, owner, schedule); this.participants = participants; } - public ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { - super(id, name, registrationDate, startDate, endDate, owner); + public ScrambleLeague(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + super(name, registrationDate, startDate, endDate, owner); this.participants = new ArrayList<>(); } diff --git a/src/main/java/design/model/StrokeLeague.java b/src/main/java/design/model/StrokeLeague.java index 6bdde0a..f09cabf 100644 --- a/src/main/java/design/model/StrokeLeague.java +++ b/src/main/java/design/model/StrokeLeague.java @@ -10,13 +10,13 @@ public class StrokeLeague extends League { private final List participants; @JsonCreator - private StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List participants) { - super(id, name, registrationDate, startDate, endDate, owner); + private StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List participants, List schedule) { + super(id, name, registrationDate, startDate, endDate, owner, schedule); this.participants = participants; } - public StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { - super(id, name, registrationDate, startDate, endDate, owner); + public StrokeLeague(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + super(name, registrationDate, startDate, endDate, owner); this.participants = new ArrayList<>(); } -- cgit v1.2.3 From a0b662eccc6422348a1016dc71b8262eeeeee78f Mon Sep 17 00:00:00 2001 From: Jacob Shimp Date: Tue, 11 Nov 2025 09:02:20 -0500 Subject: working with matches in league --- src/main/java/design/model/League.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/League.java b/src/main/java/design/model/League.java index 6621513..6dab033 100644 --- a/src/main/java/design/model/League.java +++ b/src/main/java/design/model/League.java @@ -2,6 +2,7 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -12,6 +13,7 @@ public abstract class League { private final Date startDate; private final Date endDate; private final Golfer owner; + private List schedule; @JsonCreator protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List schedule) { @@ -21,6 +23,7 @@ public abstract class League { this.startDate = startDate; this.endDate = endDate; this.owner = owner; + this.schedule = schedule; } public League(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { @@ -30,6 +33,7 @@ public abstract class League { this.startDate = startDate; this.endDate = endDate; this.owner = owner; + this.schedule = new ArrayList<>(); } public int getId() { @@ -56,6 +60,18 @@ public abstract class League { return owner; } + public List getSchedule() { + return schedule; + } + + public void addMatchToSchedule(Match match) { + Date date = match.getDateScheduled(); + if(date.after(endDate)){ + throw new IllegalArgumentException("Cannot create match after league has ended"); + } + schedule.add(match); + } + public void setId(int id) { assert this.id == -1; this.id = id; -- cgit v1.2.3 From 9a0949d31a7a0e8c9c311b07e92852cff867cc66 Mon Sep 17 00:00:00 2001 From: sowgro Date: Wed, 12 Nov 2025 12:55:12 -0500 Subject: Fix some serialization stuff --- src/main/java/design/model/League.java | 19 +++++++++++++++---- src/main/java/design/model/ScrambleLeague.java | 12 ++++++++++++ src/main/java/design/model/StrokeLeague.java | 2 ++ 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/League.java b/src/main/java/design/model/League.java index 6dab033..881e25f 100644 --- a/src/main/java/design/model/League.java +++ b/src/main/java/design/model/League.java @@ -1,11 +1,22 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import java.util.ArrayList; import java.util.Date; import java.util.List; +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type" +) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ScrambleLeague.class, name = "scramble"), + @JsonSubTypes.Type(value = StrokeLeague.class, name = "stroke") +}) public abstract class League { private int id; private final String name; @@ -13,7 +24,7 @@ public abstract class League { private final Date startDate; private final Date endDate; private final Golfer owner; - private List schedule; + private final List schedule; @JsonCreator protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List schedule) { @@ -23,7 +34,7 @@ public abstract class League { this.startDate = startDate; this.endDate = endDate; this.owner = owner; - this.schedule = schedule; + this.schedule = schedule != null ? schedule : new ArrayList<>(); } public League(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { @@ -60,8 +71,8 @@ public abstract class League { return owner; } - public List getSchedule() { - return schedule; + public Match[] getSchedule() { + return schedule.toArray(Match[]::new); } public void addMatchToSchedule(Match match) { diff --git a/src/main/java/design/model/ScrambleLeague.java b/src/main/java/design/model/ScrambleLeague.java index 92e7099..d372264 100644 --- a/src/main/java/design/model/ScrambleLeague.java +++ b/src/main/java/design/model/ScrambleLeague.java @@ -1,11 +1,14 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; +@JsonTypeName("scramble") public class ScrambleLeague extends League { private final List participants; @@ -31,4 +34,13 @@ public class ScrambleLeague extends League { public Team[] getParticipants() { return participants.toArray(Team[]::new); } + + public Team locateTeam(Golfer golfer) { + for (Team participant : participants) { + if (List.of(participant.getMembers()).contains(golfer)) { + return participant; + } + } + return null; + } } diff --git a/src/main/java/design/model/StrokeLeague.java b/src/main/java/design/model/StrokeLeague.java index f09cabf..2b787b5 100644 --- a/src/main/java/design/model/StrokeLeague.java +++ b/src/main/java/design/model/StrokeLeague.java @@ -1,11 +1,13 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.ArrayList; import java.util.Date; import java.util.List; +@JsonTypeName("stroke") public class StrokeLeague extends League { private final List participants; -- cgit v1.2.3 From 43530df067b1132b944e9619bdf60b72264829ec Mon Sep 17 00:00:00 2001 From: sowgro Date: Thu, 13 Nov 2025 08:22:39 -0500 Subject: fix constructor --- src/main/java/design/model/Golfer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/design/model') diff --git a/src/main/java/design/model/Golfer.java b/src/main/java/design/model/Golfer.java index 0f4c914..870b460 100644 --- a/src/main/java/design/model/Golfer.java +++ b/src/main/java/design/model/Golfer.java @@ -89,9 +89,9 @@ public class Golfer implements Originator { rounds.add(round); } - public Club addClub(String manufacture, String nickname, Club.ClubType type) { - Club c = new Club(nextClubId++, manufacture, nickname, type); + public Club addClub(Club c) { clubs.add(c); + c.setId(nextClubId++); return c; } -- cgit v1.2.3