summaryrefslogtreecommitdiff
path: root/domain/src/main/java/mancala/domain/SmallBowl.java
blob: 0a00bdeb88ef4fa27d1d7194f1bff149ea71a6e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package mancala.domain;

public class SmallBowl implements Bowl {
    private int myRocks;
    private final Player playerThatOwnsMe;
    private final Bowl nextBowl;

    public SmallBowl() {
        this.myRocks = 4;

        this.playerThatOwnsMe = new Player();
        int boardSize = 14;

        this.nextBowl = new SmallBowl(boardSize, --boardSize, this, this.getPlayerThatOwnsMe());
    }

    SmallBowl(int boardSize, int remainingBowls, Bowl startBowl, Player playerOwningThisSide) {
        this.myRocks = 4;
        this.playerThatOwnsMe = playerOwningThisSide;

        boolean startingFromKalaha = startBowl.getClass() == Kalaha.class;
        int startingFromKalahaAdjustment = 0;
        if (startingFromKalaha)
            startingFromKalahaAdjustment = -1;

        // One more connection to make?
        if (remainingBowls == 1) {
            this.nextBowl = startBowl;
        } // Where are the Kalahas?
        else if (remainingBowls == boardSize / 2 + 2 + startingFromKalahaAdjustment || (remainingBowls == 2 && !startingFromKalaha)) {
            this.nextBowl = new Kalaha(boardSize, --remainingBowls, startBowl, playerOwningThisSide);
        } else {
            this.nextBowl = new SmallBowl(boardSize, --remainingBowls, startBowl, playerOwningThisSide);
        }
    }

    @Override
    public int getMyRocks() {
        return myRocks;
    }

    @Override
    public Bowl getNextBowl() {
        return nextBowl;
    }

    @Override
    public Player getPlayerThatOwnsMe() {
        return playerThatOwnsMe;
    }

    public SmallBowl getNextSmallBowlTimes(int remainingTimes) {
        if (remainingTimes == 0)
            return this;
        else {
            return getNextSmallBowl().getNextSmallBowlTimes(--remainingTimes);
        }
    }

    public void play() {
        if ((!playerThatOwnsMe.hasTheTurn())) return;
        if (myRocks == 0) return;

        Bowl lastToReceiveRock;
        int myRocksBefore = myRocks;
        // Which distribute method do we need?
        if (getNextBowl().getClass() == Kalaha.class) {
            lastToReceiveRock = getNextKalaha().distribute(myRocks);
        } else {
            lastToReceiveRock = getNextSmallBowl().distribute(myRocks);
        }
        myRocks = (myRocks - myRocksBefore);

        // Did play end in smallbowl of my player? steal, otherwise do nothing
        if (lastToReceiveRock.getClass() == SmallBowl.class && lastToReceiveRock.getPlayerThatOwnsMe().equals(getPlayerThatOwnsMe())) {
            stealTheBooty((SmallBowl) lastToReceiveRock);
        }

        // Did play end in Kalaha? do nothing, otherwise switch turn
        if (!(lastToReceiveRock.getClass() == Kalaha.class)) {
            getPlayerThatOwnsMe().switchTurn();
        }

        // Should a player win or is it a draw? tell player he won/ drew, otherwise do nothing
        endTheGame();
    }

    Bowl distribute(int remainingRocks) {
        this.myRocks++;
        // last?
        if (remainingRocks == 1)
            return this;
        else {
            if (getNextBowl().getClass() == SmallBowl.class) {
                return getNextSmallBowl().distribute(--remainingRocks);
            } else {
                return getNextKalaha().distribute(--remainingRocks);
            }
        }
    }

    private void stealTheBooty(SmallBowl thievingBowl) {
        SmallBowl victim = thievingBowl.getOpposite();
        int booty;
        if (thievingBowl.getMyRocks() == 1 && victim.getMyRocks() != 0) {
            booty = victim.getMyRocks();
            booty++;
            thievingBowl.myRocks = 0;
            victim.myRocks = 0;
            getNextKalaha().claimStolenBooty(booty);
        }
    }

    private void endTheGame() {
        SmallBowl firstBowlPlayer = (SmallBowl) getOpposite().getNextKalaha().getNextBowl();
        int playerRocks = firstBowlPlayer.countRocksInSmallBowlsUntilOpponentBowls();

        if (playerRocks == 0) return;

        SmallBowl firstBowlOpponent = (SmallBowl) getNextKalaha().getNextBowl();
        int opponentRocks = firstBowlOpponent.countRocksInSmallBowlsUntilOpponentBowls();

        int playerKalaha = getNextKalaha().getMyRocks();
        int opponentKalaha = getOpposite().getNextKalaha().getMyRocks();

        if ((playerRocks + playerKalaha) == (opponentRocks + opponentKalaha)) {
            getPlayerThatOwnsMe().gotADraw();
        } else if ((playerRocks + playerKalaha) > (opponentRocks + opponentKalaha)) {
            getPlayerThatOwnsMe().isTheWinner();
        } else {
            getPlayerThatOwnsMe().getOpponent().isTheWinner();
        }
    }

    private SmallBowl getNextSmallBowl() {
        if (getNextBowl().getClass() == Kalaha.class) {
            return (SmallBowl) getNextBowl().getNextBowl();
        } else {
            return (SmallBowl) getNextBowl();
        }
    }

    private Kalaha getNextKalaha() {
        if (!(getNextBowl().getClass() == Kalaha.class)) {
            return getNextSmallBowl().getNextKalaha();
        } else {
            return (Kalaha) getNextBowl();
        }
    }

    private SmallBowl getOpposite() {
        SmallBowl opponentFirst = (SmallBowl) getNextKalaha().getNextBowl();
        return opponentFirst.getNextSmallBowlTimes(countStepsToKalaha());
    }

    private int countStepsToKalaha() {
        if (getNextBowl().getClass() == Kalaha.class) {
            return 0;
        } else {
            return 1 + getNextSmallBowl().countStepsToKalaha();
        }
    }

    private int countRocksInSmallBowlsUntilOpponentBowls() {
        if (!(getNextSmallBowl().getPlayerThatOwnsMe().equals(getPlayerThatOwnsMe()))) {
            return this.myRocks;
        } else {
            return this.myRocks + getNextSmallBowl().countRocksInSmallBowlsUntilOpponentBowls();
        }
    }
}