From 6d2a2433345c96809a4ba2ad96b8e9c451d10aca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 22:57:53 +0000 Subject: [PATCH 1/5] Initial plan From 9c7a6a8a8bc9c1f3b2c84eefdf134a6cf8fe6334 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:00:50 +0000 Subject: [PATCH 2/5] Implement interactive fishing minigame with timing-based catches Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com> --- src/location/docks.py | 41 +++++++++++++++++++++++-- tests/location/test_docks.py | 58 ++++++++++++++++++++++++++++++++---- 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/src/location/docks.py b/src/location/docks.py index 5c26e56..dd53fbd 100644 --- a/src/location/docks.py +++ b/src/location/docks.py @@ -90,24 +90,61 @@ def fish(self): self.currentPrompt.text = "You're too tired to fish! Go home and sleep." return + successfulCatches = 0 + totalAttempts = 0 + for i in range(hours): print("><> ") sys.stdout.flush() time.sleep(0.5) + + # Interactive minigame: player must press Enter at the right moment + print("A fish is biting! Press Enter quickly! ") + sys.stdout.flush() + + start_time = time.time() + try: + input() + reaction_time = time.time() - start_time + + # Success if pressed within 2 seconds + if reaction_time <= 2.0: + successfulCatches += 1 + print("Got it! ") + else: + print("Too slow... ") + except: + print("Missed! ") + + sys.stdout.flush() + totalAttempts += 1 + self.stats.hoursSpentFishing += 1 self.timeService.increaseTime() self.player.energy -= 10 # Consume 10 energy per hour - fishToAdd = random.randint(1, 10) * self.player.fishMultiplier + # Calculate fish caught based on success rate + basefish = random.randint(1, 10) + if totalAttempts > 0: + success_rate = successfulCatches / totalAttempts + fishToAdd = int(basefish * success_rate * self.player.fishMultiplier) + else: + fishToAdd = 0 + + # Ensure at least 1 fish if player attempted + if fishToAdd == 0 and totalAttempts > 0: + fishToAdd = 1 + self.player.fishCount += fishToAdd self.stats.totalFishCaught += fishToAdd if fishToAdd == 1: self.currentPrompt.text = "Nice catch!" else: - self.currentPrompt.text = "You caught %d fish! It only took %d hours!" % ( + self.currentPrompt.text = "You caught %d fish! It only took %d hours! Success rate: %d%%" % ( fishToAdd, hours, + int((successfulCatches / totalAttempts * 100) if totalAttempts > 0 else 0) ) def talkToNPC(self): diff --git a/tests/location/test_docks.py b/tests/location/test_docks.py index 5bbdb07..67575f3 100644 --- a/tests/location/test_docks.py +++ b/tests/location/test_docks.py @@ -130,6 +130,8 @@ def test_fish(): docks.print = MagicMock() docks.sys.stdout.flush = MagicMock() docks.time.sleep = MagicMock() + docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) # Simulate quick reactions + docks.input = MagicMock(return_value="") # Simulate player pressing Enter docks.random.randint = MagicMock(return_value=3) docksInstance.timeService.increaseTime = MagicMock() @@ -139,11 +141,9 @@ def test_fish(): # check docksInstance.userInterface.lotsOfSpace.assert_called_once() docksInstance.userInterface.divider.assert_called_once() - assert docks.print.call_count == 4 - assert docks.sys.stdout.flush.call_count == 4 - assert docks.time.sleep.call_count == 4 - assert docksInstance.player.fishCount == 3 - assert docksInstance.stats.totalFishCaught == 3 + # Player should catch fish based on success rate + assert docksInstance.player.fishCount >= 1 + assert docksInstance.stats.totalFishCaught >= 1 def test_run_fish_action_low_energy(): @@ -172,6 +172,8 @@ def test_fish_consumes_energy(): docks.print = MagicMock() docks.sys.stdout.flush = MagicMock() docks.time.sleep = MagicMock() + docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) # Simulate quick reactions + docks.input = MagicMock(return_value="") # Simulate player pressing Enter docks.random.randint = MagicMock(return_value=3) # Fish for 3 hours, catch 3 fish docksInstance.timeService.increaseTime = MagicMock() @@ -193,6 +195,8 @@ def test_fish_with_limited_energy(): docks.print = MagicMock() docks.sys.stdout.flush = MagicMock() docks.time.sleep = MagicMock() + docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5]) # Simulate quick reactions for 2 hours + docks.input = MagicMock(return_value="") # Simulate player pressing Enter docks.random.randint = MagicMock( return_value=5 ) # Would normally fish for 5 hours, but energy limits to 2 @@ -206,3 +210,47 @@ def test_fish_with_limited_energy(): assert ( docksInstance.timeService.increaseTime.call_count == 2 ) # Only fished for 2 hours due to energy limit + + +def test_fish_interactive_success(): + # Test that quick reactions result in successful catches + docksInstance = createDocks() + docksInstance.userInterface.lotsOfSpace = MagicMock() + docksInstance.userInterface.divider = MagicMock() + docks.print = MagicMock() + docks.sys.stdout.flush = MagicMock() + docks.time.sleep = MagicMock() + # Simulate all quick reactions (under 2 seconds) + docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) + docks.input = MagicMock(return_value="") + docks.random.randint = MagicMock(side_effect=[3, 6]) # 3 hours, 6 base fish + docksInstance.timeService.increaseTime = MagicMock() + + # call + docksInstance.fish() + + # check - with 100% success rate, should get full catch + assert docksInstance.player.fishCount >= 3 # Should get good catch with all successes + assert docksInstance.stats.totalFishCaught >= 3 + + +def test_fish_interactive_failure(): + # Test that slow reactions result in fewer catches + docksInstance = createDocks() + docksInstance.userInterface.lotsOfSpace = MagicMock() + docksInstance.userInterface.divider = MagicMock() + docks.print = MagicMock() + docks.sys.stdout.flush = MagicMock() + docks.time.sleep = MagicMock() + # Simulate all slow reactions (over 2 seconds) + docks.time.time = MagicMock(side_effect=[0, 3.0, 0, 3.0, 0, 3.0]) + docks.input = MagicMock(return_value="") + docks.random.randint = MagicMock(side_effect=[3, 10]) # 3 hours, 10 base fish + docksInstance.timeService.increaseTime = MagicMock() + + # call + docksInstance.fish() + + # check - with 0% success rate, should still get at least 1 fish minimum + assert docksInstance.player.fishCount == 1 # Minimum 1 fish even with failures + assert docksInstance.stats.totalFishCaught == 1 From 003baa5588eced8d3f8cda4d8b64d0d7d6146a58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:02:50 +0000 Subject: [PATCH 3/5] Address code review feedback: fix naming conventions Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com> --- src/location/docks.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/location/docks.py b/src/location/docks.py index dd53fbd..f722116 100644 --- a/src/location/docks.py +++ b/src/location/docks.py @@ -102,18 +102,18 @@ def fish(self): print("A fish is biting! Press Enter quickly! ") sys.stdout.flush() - start_time = time.time() + startTime = time.time() try: input() - reaction_time = time.time() - start_time + reactionTime = time.time() - startTime # Success if pressed within 2 seconds - if reaction_time <= 2.0: + if reactionTime <= 2.0: successfulCatches += 1 print("Got it! ") else: print("Too slow... ") - except: + except (KeyboardInterrupt, EOFError): print("Missed! ") sys.stdout.flush() @@ -124,10 +124,10 @@ def fish(self): self.player.energy -= 10 # Consume 10 energy per hour # Calculate fish caught based on success rate - basefish = random.randint(1, 10) + baseFish = random.randint(1, 10) if totalAttempts > 0: - success_rate = successfulCatches / totalAttempts - fishToAdd = int(basefish * success_rate * self.player.fishMultiplier) + successRate = successfulCatches / totalAttempts + fishToAdd = int(baseFish * successRate * self.player.fishMultiplier) else: fishToAdd = 0 From 60b2e7426f62b1bdfa3e0ec6c167deb9853b2f6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:21:22 +0000 Subject: [PATCH 4/5] Fix test isolation issue causing test_sellFish to fail Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com> --- tests/location/test_docks.py | 60 +++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/tests/location/test_docks.py b/tests/location/test_docks.py index 67575f3..5380eb3 100644 --- a/tests/location/test_docks.py +++ b/tests/location/test_docks.py @@ -5,7 +5,7 @@ from src.stats.stats import Stats from src.ui.userInterface import UserInterface from src.world.timeService import TimeService -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch def createDocks(): @@ -217,21 +217,22 @@ def test_fish_interactive_success(): docksInstance = createDocks() docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() - docks.print = MagicMock() - docks.sys.stdout.flush = MagicMock() - docks.time.sleep = MagicMock() - # Simulate all quick reactions (under 2 seconds) - docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) - docks.input = MagicMock(return_value="") - docks.random.randint = MagicMock(side_effect=[3, 6]) # 3 hours, 6 base fish - docksInstance.timeService.increaseTime = MagicMock() + + with patch('src.location.docks.print'), \ + patch('src.location.docks.sys.stdout.flush'), \ + patch('src.location.docks.time.sleep'), \ + patch('src.location.docks.time.time', side_effect=[0, 0.5, 0, 0.5, 0, 0.5]), \ + patch('src.location.docks.input', return_value=""), \ + patch('src.location.docks.random.randint', side_effect=[3, 6]): + + docksInstance.timeService.increaseTime = MagicMock() - # call - docksInstance.fish() + # call + docksInstance.fish() - # check - with 100% success rate, should get full catch - assert docksInstance.player.fishCount >= 3 # Should get good catch with all successes - assert docksInstance.stats.totalFishCaught >= 3 + # check - with 100% success rate, should get full catch + assert docksInstance.player.fishCount >= 3 # Should get good catch with all successes + assert docksInstance.stats.totalFishCaught >= 3 def test_fish_interactive_failure(): @@ -239,18 +240,19 @@ def test_fish_interactive_failure(): docksInstance = createDocks() docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() - docks.print = MagicMock() - docks.sys.stdout.flush = MagicMock() - docks.time.sleep = MagicMock() - # Simulate all slow reactions (over 2 seconds) - docks.time.time = MagicMock(side_effect=[0, 3.0, 0, 3.0, 0, 3.0]) - docks.input = MagicMock(return_value="") - docks.random.randint = MagicMock(side_effect=[3, 10]) # 3 hours, 10 base fish - docksInstance.timeService.increaseTime = MagicMock() - - # call - docksInstance.fish() - - # check - with 0% success rate, should still get at least 1 fish minimum - assert docksInstance.player.fishCount == 1 # Minimum 1 fish even with failures - assert docksInstance.stats.totalFishCaught == 1 + + with patch('src.location.docks.print'), \ + patch('src.location.docks.sys.stdout.flush'), \ + patch('src.location.docks.time.sleep'), \ + patch('src.location.docks.time.time', side_effect=[0, 3.0, 0, 3.0, 0, 3.0]), \ + patch('src.location.docks.input', return_value=""), \ + patch('src.location.docks.random.randint', side_effect=[3, 10]): + + docksInstance.timeService.increaseTime = MagicMock() + + # call + docksInstance.fish() + + # check - with 0% success rate, should still get at least 1 fish minimum + assert docksInstance.player.fishCount == 1 # Minimum 1 fish even with failures + assert docksInstance.stats.totalFishCaught == 1 From b9d82284dc867270d2eaed4abf26f4ea897002bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:47:38 +0000 Subject: [PATCH 5/5] Fix CI failure by using infinite generators for time.time mocks Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com> --- tests/location/test_docks.py | 126 ++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/tests/location/test_docks.py b/tests/location/test_docks.py index 5380eb3..d1c4edd 100644 --- a/tests/location/test_docks.py +++ b/tests/location/test_docks.py @@ -127,23 +127,31 @@ def test_fish(): docksInstance = createDocks() docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() - docks.print = MagicMock() - docks.sys.stdout.flush = MagicMock() - docks.time.sleep = MagicMock() - docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) # Simulate quick reactions - docks.input = MagicMock(return_value="") # Simulate player pressing Enter - docks.random.randint = MagicMock(return_value=3) - docksInstance.timeService.increaseTime = MagicMock() + + # Create a side effect that alternates between 0 and 0.5 indefinitely + def time_side_effect(): + while True: + yield 0 + yield 0.5 + + with patch('src.location.docks.print'), \ + patch('src.location.docks.sys.stdout.flush'), \ + patch('src.location.docks.time.sleep'), \ + patch('src.location.docks.time.time', side_effect=time_side_effect()), \ + patch('src.location.docks.input', return_value=""), \ + patch('src.location.docks.random.randint', return_value=3): + + docksInstance.timeService.increaseTime = MagicMock() - # call - docksInstance.fish() + # call + docksInstance.fish() - # check - docksInstance.userInterface.lotsOfSpace.assert_called_once() - docksInstance.userInterface.divider.assert_called_once() - # Player should catch fish based on success rate - assert docksInstance.player.fishCount >= 1 - assert docksInstance.stats.totalFishCaught >= 1 + # check + docksInstance.userInterface.lotsOfSpace.assert_called_once() + docksInstance.userInterface.divider.assert_called_once() + # Player should catch fish based on success rate + assert docksInstance.player.fishCount >= 1 + assert docksInstance.stats.totalFishCaught >= 1 def test_run_fish_action_low_energy(): @@ -169,21 +177,29 @@ def test_fish_consumes_energy(): docksInstance.player.energy = 100 docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() - docks.print = MagicMock() - docks.sys.stdout.flush = MagicMock() - docks.time.sleep = MagicMock() - docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5, 0, 0.5]) # Simulate quick reactions - docks.input = MagicMock(return_value="") # Simulate player pressing Enter - docks.random.randint = MagicMock(return_value=3) # Fish for 3 hours, catch 3 fish - docksInstance.timeService.increaseTime = MagicMock() + + # Create a side effect that alternates between 0 and 0.5 indefinitely + def time_side_effect(): + while True: + yield 0 + yield 0.5 + + with patch('src.location.docks.print'), \ + patch('src.location.docks.sys.stdout.flush'), \ + patch('src.location.docks.time.sleep'), \ + patch('src.location.docks.time.time', side_effect=time_side_effect()), \ + patch('src.location.docks.input', return_value=""), \ + patch('src.location.docks.random.randint', return_value=3): + + docksInstance.timeService.increaseTime = MagicMock() - # call - docksInstance.fish() + # call + docksInstance.fish() - # check - assert docksInstance.player.energy == 100 - ( - 3 * 10 - ) # Should lose 30 energy (3 hours * 10 per hour) + # check + assert docksInstance.player.energy == 100 - ( + 3 * 10 + ) # Should lose 30 energy (3 hours * 10 per hour) def test_fish_with_limited_energy(): @@ -192,24 +208,30 @@ def test_fish_with_limited_energy(): docksInstance.player.energy = 25 # Only enough for 2 hours docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() - docks.print = MagicMock() - docks.sys.stdout.flush = MagicMock() - docks.time.sleep = MagicMock() - docks.time.time = MagicMock(side_effect=[0, 0.5, 0, 0.5]) # Simulate quick reactions for 2 hours - docks.input = MagicMock(return_value="") # Simulate player pressing Enter - docks.random.randint = MagicMock( - return_value=5 - ) # Would normally fish for 5 hours, but energy limits to 2 - docksInstance.timeService.increaseTime = MagicMock() + + # Create a side effect that alternates between 0 and 0.5 indefinitely + def time_side_effect(): + while True: + yield 0 + yield 0.5 + + with patch('src.location.docks.print'), \ + patch('src.location.docks.sys.stdout.flush'), \ + patch('src.location.docks.time.sleep'), \ + patch('src.location.docks.time.time', side_effect=time_side_effect()), \ + patch('src.location.docks.input', return_value=""), \ + patch('src.location.docks.random.randint', return_value=5): + + docksInstance.timeService.increaseTime = MagicMock() - # call - docksInstance.fish() + # call + docksInstance.fish() - # check - assert docksInstance.player.energy == 5 # Should be 25 - (2 * 10) - assert ( - docksInstance.timeService.increaseTime.call_count == 2 - ) # Only fished for 2 hours due to energy limit + # check + assert docksInstance.player.energy == 5 # Should be 25 - (2 * 10) + assert ( + docksInstance.timeService.increaseTime.call_count == 2 + ) # Only fished for 2 hours due to energy limit def test_fish_interactive_success(): @@ -218,10 +240,16 @@ def test_fish_interactive_success(): docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() + # Create a side effect that alternates between 0 and 0.5 indefinitely (quick reactions) + def time_side_effect(): + while True: + yield 0 + yield 0.5 + with patch('src.location.docks.print'), \ patch('src.location.docks.sys.stdout.flush'), \ patch('src.location.docks.time.sleep'), \ - patch('src.location.docks.time.time', side_effect=[0, 0.5, 0, 0.5, 0, 0.5]), \ + patch('src.location.docks.time.time', side_effect=time_side_effect()), \ patch('src.location.docks.input', return_value=""), \ patch('src.location.docks.random.randint', side_effect=[3, 6]): @@ -241,10 +269,16 @@ def test_fish_interactive_failure(): docksInstance.userInterface.lotsOfSpace = MagicMock() docksInstance.userInterface.divider = MagicMock() + # Create a side effect that alternates between 0 and 3.0 indefinitely (slow reactions) + def time_side_effect(): + while True: + yield 0 + yield 3.0 + with patch('src.location.docks.print'), \ patch('src.location.docks.sys.stdout.flush'), \ patch('src.location.docks.time.sleep'), \ - patch('src.location.docks.time.time', side_effect=[0, 3.0, 0, 3.0, 0, 3.0]), \ + patch('src.location.docks.time.time', side_effect=time_side_effect()), \ patch('src.location.docks.input', return_value=""), \ patch('src.location.docks.random.randint', side_effect=[3, 10]):