summaryrefslogtreecommitdiff
path: root/domain/src
diff options
context:
space:
mode:
Diffstat (limited to 'domain/src')
-rw-r--r--domain/src/main/java/mancala/domain/Bowl.java29
-rw-r--r--domain/src/main/java/mancala/domain/Foo.java11
-rw-r--r--domain/src/main/java/mancala/domain/Kalaha.java29
-rw-r--r--domain/src/main/java/mancala/domain/Player.java37
-rw-r--r--domain/src/main/java/mancala/domain/SmallBowl.java111
-rw-r--r--domain/src/main/main.iml11
-rw-r--r--domain/src/test/java/mancala/domain/BowlTest.java208
-rw-r--r--domain/src/test/java/mancala/domain/FooTest.java23
-rw-r--r--domain/src/test/java/mancala/domain/PlayerTest.java35
-rw-r--r--domain/src/test/test.iml28
10 files changed, 488 insertions, 34 deletions
diff --git a/domain/src/main/java/mancala/domain/Bowl.java b/domain/src/main/java/mancala/domain/Bowl.java
new file mode 100644
index 0000000..9da4f3b
--- /dev/null
+++ b/domain/src/main/java/mancala/domain/Bowl.java
@@ -0,0 +1,29 @@
+package mancala.domain;
+
+abstract class Bowl {
+ protected int myRocks;
+ protected Player playerThatOwnsMe;
+ protected Bowl nextBowl;
+
+ protected int calculateBoardPosition(int startPosition, int addedBowlsCount) {
+ if ((startPosition + addedBowlsCount) > 14) {
+ return ((addedBowlsCount + startPosition) - 14);
+ }
+ return startPosition + addedBowlsCount;
+ }
+
+ protected void printStateDuringConstruction(int startPosition, int addedBowlsCount) {
+ System.out.println("Board position: " + calculateBoardPosition(startPosition, addedBowlsCount)+ " type of bowl: " + this.getClass().toString() + ", Player pointer:" + this.playerThatOwnsMe);
+ }
+
+ Bowl getNextBowl() {
+ return nextBowl;
+ }
+ Player getPlayerThatOwnsMe() {
+ return playerThatOwnsMe;
+ }
+
+ int getMyRocks() {
+ return myRocks;
+ }
+}
diff --git a/domain/src/main/java/mancala/domain/Foo.java b/domain/src/main/java/mancala/domain/Foo.java
deleted file mode 100644
index bcce6fa..0000000
--- a/domain/src/main/java/mancala/domain/Foo.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package mancala.domain;
-
-// Make your own mancala implementation using your design.
-// You can take this stub as an example how to make a
-// class inside a package and how to test it.
-public class Foo {
-
- public int theAnswerToLifeTheUniverseAndEverything() {
- return 41;
- }
-} \ No newline at end of file
diff --git a/domain/src/main/java/mancala/domain/Kalaha.java b/domain/src/main/java/mancala/domain/Kalaha.java
new file mode 100644
index 0000000..13e8273
--- /dev/null
+++ b/domain/src/main/java/mancala/domain/Kalaha.java
@@ -0,0 +1,29 @@
+package mancala.domain;
+
+public class Kalaha extends Bowl {
+
+ public Kalaha() {
+ this.myRocks = 0;
+ this.playerThatOwnsMe = new Player();
+ this.nextBowl = new SmallBowl(14, 1, this, this.playerThatOwnsMe.getOpponent());
+ }
+
+ Kalaha(int startPosition, int addedBowlsCount, Bowl startBowl, Player playerOwningThisSide) {
+ this.myRocks = 0;
+ this.playerThatOwnsMe = playerOwningThisSide;
+
+ int boardPosition = calculateBoardPosition(startPosition, addedBowlsCount);
+
+ try {
+ if (!(boardPosition == 7 || boardPosition == 14))
+ throw new Exception("Kalaha in wrong position");
+ else if (addedBowlsCount == 13)
+ this.nextBowl = startBowl;
+ else {
+ this.nextBowl = new SmallBowl(startPosition, ++addedBowlsCount, startBowl, playerOwningThisSide.getOpponent());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/domain/src/main/java/mancala/domain/Player.java b/domain/src/main/java/mancala/domain/Player.java
new file mode 100644
index 0000000..130308e
--- /dev/null
+++ b/domain/src/main/java/mancala/domain/Player.java
@@ -0,0 +1,37 @@
+package mancala.domain;
+
+public class Player {
+ private boolean hasTheTurn;
+ private Player opponent;
+
+ public Player() {
+ // player has the turn when created
+ this.hasTheTurn = true;
+
+ this.opponent = new Player(this);
+ }
+
+ private Player(Player opponent) {
+ this.hasTheTurn = false;
+
+ this.opponent = opponent;
+ }
+
+ public Player getOpponent() {
+ return opponent;
+ }
+
+ public boolean hasTheTurn() {
+ return hasTheTurn;
+ }
+
+ public void switchTurn() {
+ if (this.hasTheTurn == true) {
+ this.hasTheTurn = false;
+ this.opponent.hasTheTurn = true;
+ } else {
+ this.hasTheTurn = true;
+ this.opponent.hasTheTurn = false;
+ }
+ }
+}
diff --git a/domain/src/main/java/mancala/domain/SmallBowl.java b/domain/src/main/java/mancala/domain/SmallBowl.java
new file mode 100644
index 0000000..8d0b059
--- /dev/null
+++ b/domain/src/main/java/mancala/domain/SmallBowl.java
@@ -0,0 +1,111 @@
+package mancala.domain;
+
+// Make your own mancala implementation using your design.
+// You can take this stub as an example how to make a
+// class inside a package and how to test it.
+public class SmallBowl extends Bowl {
+
+ public SmallBowl() {
+ constructorHelper(1);
+ }
+
+ public SmallBowl(int position) {
+ // constructs board by recursively calling either kalaha or smallbowl constructors
+ constructorHelper(position);
+ }
+
+ SmallBowl getNextSmallBowlRepeat(int i) {
+ Recursive recursive = new Recursive();
+ SmallBowl next = recursive.getNextSmallBowl(i, this);
+ return next;
+ }
+
+ SmallBowl getOpposite() {
+ Bowl kalaha = this.getNextBowl();
+ Recursive recursive = new Recursive();
+ int i = 0;
+ while (kalaha.getClass() != Kalaha.class) {
+ i++;
+ kalaha.getNextBowl();
+ }
+ return (SmallBowl) recursive.getNextSmallBowl(i-1, (SmallBowl) kalaha.getNextBowl());
+ }
+
+ Kalaha getKalaha() {
+ Bowl kalaha = this.getNextBowl();
+ while (kalaha.getClass() != Kalaha.class)
+ kalaha = kalaha.getNextBowl();
+ return (Kalaha) kalaha;
+ }
+
+ public void play() {
+ if ((!this.playerThatOwnsMe.hasTheTurn()) || (this.myRocks == 0));
+ else {
+ Recursive recursive = new Recursive();
+ Bowl playEndedInThisBowl = recursive.distributeAntiClockWise(this.myRocks, this.getNextBowl());
+ this.myRocks = 0;
+ if (!(playEndedInThisBowl.getClass() == Kalaha.class&&playEndedInThisBowl.getPlayerThatOwnsMe().equals(this.getPlayerThatOwnsMe()))) {
+ this.playerThatOwnsMe.switchTurn();
+ }
+ }
+ }
+
+ private class Recursive {
+ Bowl distributeAntiClockWise(int remainingRocks, Bowl currentBowl) {
+ Boolean opponentKalahaCondition = (currentBowl.getClass() == Kalaha.class)&&!(currentBowl.getPlayerThatOwnsMe().equals(SmallBowl.this.getPlayerThatOwnsMe()));
+ if (remainingRocks > 1&&!opponentKalahaCondition) {
+ currentBowl.myRocks++;
+ return distributeAntiClockWise(--remainingRocks, currentBowl.getNextBowl());
+ } else if (opponentKalahaCondition) {
+ return distributeAntiClockWise(remainingRocks, currentBowl.getNextBowl());
+ } else {
+ currentBowl.myRocks++;
+ return currentBowl;
+ }
+ }
+
+ SmallBowl getNextSmallBowl(int remainingNexts, Bowl currentBowl) {
+ if (remainingNexts > 0)
+ return getNextSmallBowl(--remainingNexts, currentBowl.getNextBowl());
+ else if (currentBowl.getClass() == Kalaha.class)
+ return getNextSmallBowl(remainingNexts, currentBowl.getNextBowl());
+ else
+ return (SmallBowl) currentBowl;
+
+ }
+ }
+
+ // Recurses through board positions until connected again to startBowl
+ SmallBowl(int startPosition, int addedBowlsCount, Bowl startBowl, Player playerOwningThisSide) {
+ this.myRocks = 4;
+ this.playerThatOwnsMe = playerOwningThisSide;
+
+ int boardPosition = calculateBoardPosition(startPosition, addedBowlsCount);
+
+ if (addedBowlsCount == 13)
+ this.nextBowl = startBowl;
+
+ else if (boardPosition < 6 || (7 < boardPosition && boardPosition < 13))
+ this.nextBowl = new SmallBowl(startPosition, ++addedBowlsCount, startBowl, playerOwningThisSide);
+
+ else if (boardPosition == 6 || boardPosition == 13)
+ this.nextBowl = new Kalaha(startPosition, ++addedBowlsCount, startBowl, playerOwningThisSide);
+ }
+
+ private void constructorHelper(int position) {
+ this.myRocks = 4;
+ this.playerThatOwnsMe = new Player();
+
+ if (position < 6 || (7 < position && position < 13))
+ this.nextBowl = new SmallBowl(position, 1, this, this.playerThatOwnsMe);
+ else if (position == 6 || position == 13)
+ this.nextBowl = new Kalaha(position, 1, this, this.playerThatOwnsMe);
+ else if (position == 7) {
+ this.nextBowl = new SmallBowl(1, 1, this, this.playerThatOwnsMe);
+ } else if (position == 14) {
+ this.nextBowl = new SmallBowl(8, 1, this, this.playerThatOwnsMe);
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/domain/src/main/main.iml b/domain/src/main/main.iml
new file mode 100644
index 0000000..908ad4f
--- /dev/null
+++ b/domain/src/main/main.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/domain/src/test/java/mancala/domain/BowlTest.java b/domain/src/test/java/mancala/domain/BowlTest.java
new file mode 100644
index 0000000..5863784
--- /dev/null
+++ b/domain/src/test/java/mancala/domain/BowlTest.java
@@ -0,0 +1,208 @@
+package mancala.domain;
+
+// Your test class should be in the same
+// package as the class you're testing.
+// Usually the test directory mirrors the
+// main directory 1:1. So for each class in src/main,
+// there is a class in src/test.
+
+// Import our test dependencies. We import the Test-attribute
+// and a set of assertions.
+
+import org.junit.jupiter.api.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+
+class BowlTest {
+ // Define a test starting with @Test. The test is like
+ // a small main method - you need to setup everything
+ // and you can write any arbitrary Java code in it.
+
+ protected void traverseAndCheckBoard(Bowl currentBowl, int position) {
+ Bowl initialBowl = currentBowl;
+ int traversedCount = 0;
+ int currentPosition = 0;
+ for (int i = 0; i < 14; i++) {
+
+ if ((position + traversedCount) > 14) {
+ // if looping around the board, position = ((start+traversed) - total)
+ // in other words the amount of bowls that the absolute position is greater than the board's total bowls
+ currentPosition = ((traversedCount + position) - 14);
+ } else
+ // Or just use normal position
+ currentPosition = position + traversedCount;
+
+ // check for kalaha's, and check for smallbowl otherwise
+ if (currentPosition == 7 || currentPosition == 14)
+ assertEquals(currentBowl.getClass(), Kalaha.class);
+ else
+ assertEquals(currentBowl.getClass(), SmallBowl.class);
+
+ currentBowl = currentBowl.getNextBowl();
+ assertNotNull(currentBowl);
+ traversedCount++;
+ }
+ assertSame(initialBowl, currentBowl);
+ }
+
+ @Nested
+ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+ class For_a_normal_mancala_bowl{
+ SmallBowl firstSmallBowlPlayer;
+
+ @BeforeEach
+ public void makeASmallBowlInMancala() {
+ firstSmallBowlPlayer = new SmallBowl();
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {1,2,3,4,5,6,8,9,10,11,12,13})
+ public void given_always_when_created_it_exists_in_a_mancala_board(int position) {
+ traverseAndCheckBoard(new SmallBowl(position), position);
+ traverseAndCheckBoard(new SmallBowl(), 1);
+ }
+
+ @Nested
+ class given_its_the_start_of_the_game {
+ @Test
+ public void When_created_Then_has_four_rocks() {
+ Bowl current = firstSmallBowlPlayer;
+ for (int i = 0; i < 14; i++) {
+ current = current.getNextBowl();
+ if (current.getClass() == SmallBowl.class)
+ assertEquals(current.getMyRocks(), 4);
+ }
+ assertSame(current, firstSmallBowlPlayer);
+ }
+
+ @Test
+ public void When_chosen_by_the_player_that_has_the_turn_Then_distribute_its_rocks_anti_clockwise() {
+ int initialRocks = firstSmallBowlPlayer.getMyRocks();
+ firstSmallBowlPlayer.play();
+ Bowl neighbour = firstSmallBowlPlayer.getNextBowl();
+ for (int i = 0; i < initialRocks; i++) {
+ assertEquals(5, neighbour.getMyRocks());
+ neighbour = neighbour.getNextBowl();
+ }
+ }
+
+ }
+
+ @Nested
+ class given_the_game_is_in_a_state_where {
+
+ @Test
+ public void its_not_the_players_turn_When_played_by_the_player_Then_nothing_happens() {
+ firstSmallBowlPlayer.getPlayerThatOwnsMe().switchTurn();
+ int initialRocks = firstSmallBowlPlayer.getMyRocks();
+ firstSmallBowlPlayer.play();
+ Bowl neighbour = firstSmallBowlPlayer.getNextBowl();
+ for (int i = 0; i < initialRocks; i++) {
+ assertEquals(4, neighbour.getMyRocks());
+ neighbour = neighbour.getNextBowl();
+ }
+ }
+
+ @Test
+ public void play_can_reach_opponents_kalaha_When_player_plays_Then_opponents_kalaha_is_skipped() {
+ SmallBowl playWillSkipFromThisBowl = goToSkippableState();
+ int opponentKalahaRocksBefore = firstSmallBowlPlayer.getNextSmallBowlRepeat(6).getKalaha().getMyRocks();
+ playWillSkipFromThisBowl.play();
+ int opponentKalahaRocksAfter = firstSmallBowlPlayer.getNextSmallBowlRepeat(6).getKalaha().getMyRocks();
+ assertEquals(opponentKalahaRocksBefore, opponentKalahaRocksAfter);
+ }
+
+ @Test
+ public void the_bowl_is_empty_When_player_plays_the_bowl_Then_nothing_happens() {
+ firstSmallBowlPlayer.play();
+ firstSmallBowlPlayer.getPlayerThatOwnsMe().switchTurn();
+ assertTrue(firstSmallBowlPlayer.getPlayerThatOwnsMe().hasTheTurn());
+ firstSmallBowlPlayer.play();
+ assertTrue(firstSmallBowlPlayer.getPlayerThatOwnsMe().hasTheTurn());
+ assertEquals(5, firstSmallBowlPlayer.getNextBowl().getMyRocks());
+ }
+
+ private SmallBowl goToSkippableState() {
+ SmallBowl firstSmallBowlOpponent = firstSmallBowlPlayer.getNextSmallBowlRepeat(6);
+
+ firstSmallBowlPlayer.getNextSmallBowlRepeat(2).play();
+ firstSmallBowlPlayer.getNextSmallBowlRepeat(3).play();
+
+ firstSmallBowlOpponent.getNextSmallBowlRepeat(2).play();
+ firstSmallBowlOpponent.getNextSmallBowlRepeat(3).play();
+
+ firstSmallBowlPlayer.play();
+ firstSmallBowlOpponent.play();
+
+ firstSmallBowlPlayer.getNextSmallBowlRepeat(4).play();
+ firstSmallBowlOpponent.getNextSmallBowlRepeat(4).play();
+
+ // Playing this bowl should give a skip!
+ assertTrue(firstSmallBowlPlayer.getNextSmallBowlRepeat(5).getMyRocks() >= 8);
+ return firstSmallBowlPlayer.getNextSmallBowlRepeat(5);
+ }
+ }
+
+ @Nested
+ class given_the_play_ends{
+
+ @Test
+ public void in_own_kalaha_When_player_plays_this_bowl_Then_turn_is_not_switched() {
+ firstSmallBowlPlayer.getNextSmallBowlRepeat(2).play();
+ assertTrue(firstSmallBowlPlayer.getPlayerThatOwnsMe().hasTheTurn());
+ }
+
+ @Test
+ public void in_own_small_bowl_When_player_plays_this_bowl_Then_turn_is_switched() {
+ firstSmallBowlPlayer.play();
+ assertFalse(firstSmallBowlPlayer.getPlayerThatOwnsMe().hasTheTurn());
+ }
+
+ @Test
+ public void in_opponents_small_bowl_When_player_plays_this_bowl_Then_turn_is_switched() {
+ firstSmallBowlPlayer.getNextSmallBowlRepeat(5).play();
+ assertFalse(firstSmallBowlPlayer.getPlayerThatOwnsMe().hasTheTurn());
+ }
+
+ }
+
+
+ }
+
+ @Nested
+ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+ class a_kalaha {
+
+ Kalaha kalaha;
+
+ @BeforeEach
+ public void makeKalahaInBoard() {
+ kalaha = new Kalaha();
+ }
+
+ @Test
+ public void exists_in_a_mancala_board() {
+ traverseAndCheckBoard(kalaha, 14);
+ }
+
+ @Test
+ public void has_zero_rocks_when_created() {
+ Bowl current = kalaha;
+ for (int i = 0; i < 14; i++) {
+ current = current.getNextBowl();
+ if (current.getClass() == Kalaha.class)
+ assertEquals(current.getMyRocks(), 0);
+ }
+ }
+ }
+
+
+ @Nested
+ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+ class in_a_game_of_mancala {
+
+ }
+} \ No newline at end of file
diff --git a/domain/src/test/java/mancala/domain/FooTest.java b/domain/src/test/java/mancala/domain/FooTest.java
deleted file mode 100644
index fa784d3..0000000
--- a/domain/src/test/java/mancala/domain/FooTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package mancala.domain;
-
-// Your test class should be in the same
-// package as the class you're testing.
-// Usually the test directory mirrors the
-// main directory 1:1. So for each class in src/main,
-// there is a class in src/test.
-
-// Import our test dependencies. We import the Test-attribute
-// and a set of assertions.
-import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
-
-public class FooTest {
- // Define a test starting with @Test. The test is like
- // a small main method - you need to setup everything
- // and you can write any arbitrary Java code in it.
- @Test
- public void aNormalBorlStartsWith4Stones() {
- Foo foo = new Foo();
- assertEquals(42, foo.theAnswerToLifeTheUniverseAndEverything());
- }
-} \ No newline at end of file
diff --git a/domain/src/test/java/mancala/domain/PlayerTest.java b/domain/src/test/java/mancala/domain/PlayerTest.java
new file mode 100644
index 0000000..3538ec5
--- /dev/null
+++ b/domain/src/test/java/mancala/domain/PlayerTest.java
@@ -0,0 +1,35 @@
+package mancala.domain;
+
+import org.junit.jupiter.api.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@DisplayName("A player model ")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+class PlayerTest {
+ Player player;
+ Player opponent;
+
+ @BeforeEach
+ public void let_player_and_oppenent_exist() {
+ player = new Player();
+ opponent = player.getOpponent();
+ }
+
+ @Test
+ public void has_turn_when_created() {
+ assertTrue(player.hasTheTurn());
+ }
+
+ @Test
+ public void opponent_does_not_have_turn_when_player_models_are_created() {
+ assertFalse(player.getOpponent().hasTheTurn());
+ }
+
+ @Test
+ public void can_change_turn_when_necessary() {
+ player.switchTurn();
+ assertFalse(player.hasTheTurn());
+ assertTrue(player.getOpponent().hasTheTurn());
+ }
+} \ No newline at end of file
diff --git a/domain/src/test/test.iml b/domain/src/test/test.iml
new file mode 100644
index 0000000..8cc6e96
--- /dev/null
+++ b/domain/src/test/test.iml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library" scope="TEST">
+ <library name="JUnit5.7.0">
+ <CLASSES>
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.7.0/junit-jupiter-5.7.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.7.0/junit-jupiter-api-5.7.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.7.0/junit-platform-commons-1.7.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-params/5.7.0/junit-jupiter-params-5.7.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-engine/5.7.0/junit-jupiter-engine-5.7.0.jar!/" />
+ <root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.7.0/junit-platform-engine-1.7.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module" module-name="main" scope="TEST" />
+ </component>
+</module> \ No newline at end of file