Skip to content

Commit 99c8273

Browse files
Add split-second-stopwatch exercise #2968
git add . git commit -m "Add split-second-stopwatch exercise Implement the split-second-stopwatch practice exercise with: - State management (ready/running/stopped) - Time tracking for current lap and total elapsed time - Lap functionality with previous laps history - Start, stop, reset operations with proper state validation - Error handling for invalid state transitions - Time formatting in HH:MM:SS format - Mock time advancement for testing Includes reference solution, starter implementation, and comprehensive test suite covering all canonical data test cases."
1 parent c5d8fe4 commit 99c8273

File tree

12 files changed

+142
-384
lines changed

12 files changed

+142
-384
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,14 @@
18811881
"lists"
18821882
],
18831883
"difficulty": 10
1884+
},
1885+
{
1886+
"slug": "split-second-stopwatch",
1887+
"name": "Split-Second Stopwatch",
1888+
"uuid": "9510c0ae-9977-4260-8991-0e8e849094b0",
1889+
"practices": [],
1890+
"prerequisites": [],
1891+
"difficulty": 1
18841892
}
18851893
],
18861894
"foregone": [

exercises/practice/split-second-stopwatch/.docs/instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ What commands can be used depends on which state the stopwatch is in:
1919
| Start | Stopped | Running | Resume tracking time |
2020
| Stop | Running | Stopped | Stop tracking time |
2121
| Lap | Running | Running | Add current lap to previous laps, then reset current lap |
22-
| Reset | Stopped | Ready | Reset current lap and clear previous laps |
22+
| Reset | Stopped | Ready | Reset current lap and clear previous laps |

exercises/practice/split-second-stopwatch/.docs/introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
You've always run for the thrill of it — no schedules, no timers, just the sound of your feet on the pavement.
44
But now that you've joined a competitive running crew, things are getting serious.
55
Training sessions are timed to the second, and every split second counts.
6-
To keep pace, you've picked up the _Split-Second Stopwatch_ — a sleek, high-tech gadget that's about to become your new best friend.
6+
To keep pace, you've picked up the _Split-Second Stopwatch_ — a sleek, high-tech gadget that's about to become your new best friend.
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
{
22
"authors": [
3-
"Jagdish Prajapati, Kah Goh & Emmanuel Berkowicz"
3+
"EmmanuelBerkowicz"
44
],
55
"files": {
66
"solution": [
77
"src/main/java/SplitSecondStopwatch.java"
88
],
99
"test": [
10-
"src/test/java/SplitSecondStopwatch.java"
10+
"src/test/java/SplitSecondStopwatchTest.java"
1111
],
1212
"example": [
1313
".meta/src/reference/java/SplitSecondStopwatch.java"
14-
],
15-
"invalidator": [
16-
"build.gradle"
1714
]
1815
},
19-
"blurb": "Time to create a new and improved split second stopwatch using your friendly neighbourhood OOP language!.",
20-
"source": "Emmanuel Berkowicz",
21-
"source_url": "https://github.com/exercism/problem-specifications/tree/main/exercises/split-second-stopwatch"
16+
"blurb": "Keep track of time through a digital stopwatch.",
17+
"source": "Erik Schierboom",
18+
"source_url": "https://github.com/exercism/problem-specifications/pull/2547"
2219
}

exercises/practice/split-second-stopwatch/.meta/src/reference/java/SplitSecondStopwatch.java

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ public class SplitSecondStopwatch {
1616
private enum State { READY, RUNNING, STOPPED }
1717

1818
private State state;
19-
private long totalElapsed;
20-
private long currentLapStart;
21-
private long lastStopTime;
19+
private long totalCompletedLaps; // Total time from completed laps
20+
private long currentLapStart; // When current lap started
21+
private long accumulated; // Accumulated time for current lap when stopped
2222
private List<String> previousLaps;
2323
private long mockTime;
2424

2525
public SplitSecondStopwatch() {
2626
this.state = State.READY;
27-
this.totalElapsed = 0;
27+
this.totalCompletedLaps = 0;
2828
this.currentLapStart = 0;
29-
this.lastStopTime = 0;
29+
this.accumulated = 0;
3030
this.previousLaps = new ArrayList<>();
3131
this.mockTime = 0;
3232
}
@@ -36,13 +36,7 @@ public void start() {
3636
throw new IllegalStateException("cannot start an already running stopwatch");
3737
}
3838

39-
if (state == State.READY) {
40-
currentLapStart = mockTime;
41-
} else if (state == State.STOPPED) {
42-
long pausedDuration = mockTime - lastStopTime;
43-
currentLapStart += pausedDuration;
44-
}
45-
39+
currentLapStart = mockTime;
4640
state = State.RUNNING;
4741
}
4842

@@ -51,8 +45,7 @@ public void stop() {
5145
throw new IllegalStateException("cannot stop a stopwatch that is not running");
5246
}
5347

54-
lastStopTime = mockTime;
55-
totalElapsed += mockTime - currentLapStart;
48+
accumulated += mockTime - currentLapStart;
5649
state = State.STOPPED;
5750
}
5851

@@ -62,9 +55,9 @@ public void reset() {
6255
}
6356

6457
state = State.READY;
65-
totalElapsed = 0;
58+
totalCompletedLaps = 0;
6659
currentLapStart = 0;
67-
lastStopTime = 0;
60+
accumulated = 0;
6861
previousLaps.clear();
6962
}
7063

@@ -73,8 +66,12 @@ public void lap() {
7366
throw new IllegalStateException("cannot lap a stopwatch that is not running");
7467
}
7568

76-
long currentLapTime = mockTime - currentLapStart;
69+
long currentLapTime = getCurrentLapTime();
70+
totalCompletedLaps += currentLapTime;
7771
previousLaps.add(formatTime(currentLapTime));
72+
73+
// Reset current lap and restart
74+
accumulated = 0;
7875
currentLapStart = mockTime;
7976
}
8077

@@ -83,19 +80,11 @@ public String state() {
8380
}
8481

8582
public String currentLap() {
86-
if (state == State.RUNNING) {
87-
return formatTime(mockTime - currentLapStart);
88-
} else {
89-
return formatTime(lastStopTime - currentLapStart);
90-
}
83+
return formatTime(getCurrentLapTime());
9184
}
9285

9386
public String total() {
94-
if (state == State.RUNNING) {
95-
return formatTime(totalElapsed + (mockTime - currentLapStart));
96-
} else {
97-
return formatTime(totalElapsed);
98-
}
87+
return formatTime(totalCompletedLaps + getCurrentLapTime());
9988
}
10089

10190
public List<String> previousLaps() {
@@ -112,6 +101,19 @@ public void advanceTime(String timeString) {
112101
mockTime += milliseconds;
113102
}
114103

104+
private long getCurrentLapTime() {
105+
switch (state) {
106+
case READY:
107+
return 0;
108+
case RUNNING:
109+
return accumulated + (mockTime - currentLapStart);
110+
case STOPPED:
111+
return accumulated;
112+
default:
113+
throw new IllegalStateException("Invalid state");
114+
}
115+
}
116+
115117
private String formatTime(long milliseconds) {
116118
long totalSeconds = milliseconds / 1000;
117119
long hours = totalSeconds / 3600;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[ddb238ea-99d4-4eaa-a81d-3c917a525a23]
13+
description = "new stopwatch starts in ready state"
14+
15+
[b19635d4-08ad-4ac3-b87f-aca10e844071]
16+
description = "new stopwatch's current lap has no elapsed time"
17+
18+
[492eb532-268d-43ea-8a19-2a032067d335]
19+
description = "new stopwatch's total has no elapsed time"
20+
21+
[8a892c1e-9ef7-4690-894e-e155a1fe4484]
22+
description = "new stopwatch does not have previous laps"
23+
24+
[5b2705b6-a584-4042-ba3a-4ab8d0ab0281]
25+
description = "start from ready state changes state to running"
26+
27+
[748235ce-1109-440b-9898-0a431ea179b6]
28+
description = "start does not change previous laps"
29+
30+
[491487b1-593d-423e-a075-aa78d449ff1f]
31+
description = "start initiates time tracking for current lap"
32+
33+
[a0a7ba2c-8db6-412c-b1b6-cb890e9b72ed]
34+
description = "start initiates time tracking for total"
35+
36+
[7f558a17-ef6d-4a5b-803a-f313af7c41d3]
37+
description = "start cannot be called from running state"
38+
39+
[32466eef-b2be-4d60-a927-e24fce52dab9]
40+
description = "stop from running state changes state to stopped"
41+
42+
[621eac4c-8f43-4d99-919c-4cad776d93df]
43+
description = "stop pauses time tracking for current lap"
44+
45+
[465bcc82-7643-41f2-97ff-5e817cef8db4]
46+
description = "stop pauses time tracking for total"
47+
48+
[b1ba7454-d627-41ee-a078-891b2ed266fc]
49+
description = "stop cannot be called from ready state"
50+
51+
[5c041078-0898-44dc-9d5b-8ebb5352626c]
52+
description = "stop cannot be called from stopped state"
53+
54+
[3f32171d-8fbf-46b6-bc2b-0810e1ec53b7]
55+
description = "start from stopped state changes state to running"
56+
57+
[626997cb-78d5-4fe8-b501-29fdef804799]
58+
description = "start from stopped state resumes time tracking for current lap"
59+
60+
[58487c53-ab26-471c-a171-807ef6363319]
61+
description = "start from stopped state resumes time tracking for total"
62+
63+
[091966e3-ed25-4397-908b-8bb0330118f8]
64+
description = "lap adds current lap to previous laps"
65+
66+
[1aa4c5ee-a7d5-4d59-9679-419deef3c88f]
67+
description = "lap resets current lap and resumes time tracking"
68+
69+
[4b46b92e-1b3f-46f6-97d2-0082caf56e80]
70+
description = "lap continues time tracking for total"
71+
72+
[ea75d36e-63eb-4f34-97ce-8c70e620bdba]
73+
description = "lap cannot be called from ready state"
74+
75+
[63731154-a23a-412d-a13f-c562f208eb1e]
76+
description = "lap cannot be called from stopped state"
77+
78+
[e585ee15-3b3f-4785-976b-dd96e7cc978b]
79+
description = "stop does not change previous laps"
80+
81+
[fc3645e2-86cf-4d11-97c6-489f031103f6]
82+
description = "reset from stopped state changes state to ready"
83+
84+
[20fbfbf7-68ad-4310-975a-f5f132886c4e]
85+
description = "reset resets current lap"
86+
87+
[00a8f7bb-dd5c-43e5-8705-3ef124007662]
88+
description = "reset clears previous laps"
89+
90+
[76cea936-6214-4e95-b6d1-4d4edcf90499]
91+
description = "reset cannot be called from ready state"
92+
93+
[ba4d8e69-f200-4721-b59e-90d8cf615153]
94+
description = "reset cannot be called from running state"
95+
96+
[0b01751a-cb57-493f-bb86-409de6e84306]
97+
description = "supports very long laps"
Binary file not shown.

exercises/practice/split-second-stopwatch/gradle/wrapper/gradle-wrapper.properties

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)