Skip to contentMethod: getColumnCount()
      1: package de.fhdw.gaming.ipspiel23.c4.domain.impl.validation;
2: 
3: import de.fhdw.gaming.core.ui.InputProviderException;
4: 
5: /**
6:  * Represents the absolute limits, and currently set dimensions of a Connect-N board.
7:  * User-provided values are stored in this class, and validated against the limits.
8:  */
9: public class C4BoardLimits {
10: 
11:     /**
12:      * The minimum number of rows a board must have.
13:      */
14:     // for the incredible "Connect Two" experience where the first player wins by default after the second move :)
15:     public static final int MIN_ROW_COUNT = 2;
16: 
17:     /**
18:      * The minimum number of columns a board must have.
19:      */
20:     // for the incredible "Connect Two" experience where the first player wins by default after the second move :)
21:     public static final int MIN_COLUMN_COUNT = 2;
22: 
23:     /**
24:      * The maximum number of rows a board can have.
25:      */
26:     // these are theoretical maximums. In the end, actualColumnCount * actualRowCount must be <= MAX_FIELD_COUNT
27:     public static final int MAX_ROW_COUNT = Integer.MAX_VALUE / MIN_COLUMN_COUNT;
28: 
29:     /**
30:      * The maximum number of columns a board can have.
31:      */
32:     // these are theoretical maximums. In the end, actualColumnCount * actualRowCount must be <= MAX_FIELD_COUNT
33:     public static final int MAX_COLUMN_COUNT = Integer.MAX_VALUE / MIN_ROW_COUNT;
34: 
35:     /**
36:      * The maximum number of fields a board can have.
37:      */
38:     // we use 32 bit indices for our internal token-state array, so if more than 4 * 2^31 - 1 = 8 GiB of RAM are 
39:     // available we can use the whole 31 bit range for indexing (also: why doesn't java have unsigned integers???).
40:     // fun fact:
41:     // at 1 second per move a draw could actually happen within our life time at
42:     // just over 68 Years of 24/7 exciting Connect-N gameplay :)
43:     public static final int MAX_FIELD_COUNT = Integer.MAX_VALUE;
44: 
45:     /**
46:      * The minimum allowed number that can be set as the number of tokens that need to be matched to form a solution.
47:      */
48:     // "Connect One" wouldn't be too exciting TBH. Also I don't think our board-state-validation algorithm would 
49:     // support it.
50:     public static final int MIN_SOLUTION_SIZE = 2;
51: 
52:     /**
53:      * The maximum allowed number that can be set as the number of tokens that need to be matched to form a solution.
54:      */
55:     // Its probably a good idea to keep the solution size below the maximum theoretical board boundaries
56:     public static final int MAX_SOLUTION_SIZE = Math.max(MAX_ROW_COUNT, MAX_COLUMN_COUNT);
57: 
58:     /**
59:      * The minimum number of players that can play on a board.
60:      */
61:     // to me it's questionable how exciting a Connect Four game with a single player would be,
62:     // but who am I to judge what gets other people thrilled ¯\_(ツ)_/¯
63:     public static final int MIN_NUMBER_OF_PLAYERS = 2;
64: 
65:     /**
66:      * The maximum number of players that can play on a board.
67:      */
68:     // let's assume we actually want each player to have at least the theoretical possibility to win
69:     // fun fact:
70:     // at the theoretical maximum we would still would support 33.5 times more players than RGB24 has colors available
71:     // to differentiate between the pieces :P
72:     // so the GUI team would have to start playing around with the alpha channel in RGB32 to give every player a unique
73:     // color.
74:     // also: assuming 16:9 aspect ratio you'd have to own at least a 30897x17379 px monitor to display the whole board
75:     // at once, so a 32k display would *just* not suffice at "only" 30720x17280 px :)
76:     //public static final int MAX_NUMBER_OF_PLAYERS = C4BoardLimits.MAX_FIELD_COUNT / C4BoardLimits.MIN_SOLUTION_SIZE;
77:     public static final int MAX_NUMBER_OF_PLAYERS = 2;
78: 
79:     /**
80:      * The currently specified board dimensions.
81:      */
82:     private final C4BoardDimensions boardDimensions;
83: 
84:     /**
85:      * The currently specified number of tokens that need to be matched to form a solution.
86:      */
87:     private int solutionSize;
88: 
89:     /**
90:      * The total number of players that will play on the board.
91:      */
92:     private final int playerCount;
93: 
94:     /**
95:      * Creates a new instance of {@link C4BoardLimits}.
96:      * @param playerCount the actual number of players that will play on the board
97:      * @param initialRowCount the initial number of rows the board will have
98:      * @param initialColumnCount the initial number of columns the board will have
99:      * @param initialSolutionSize the initial number of tokens that need to be matched to form a solution
100:      */
101:     public C4BoardLimits(final int playerCount, final int initialRowCount,
102:             final int initialColumnCount, final int initialSolutionSize) {
103:         this.playerCount = playerCount;
104:         this.boardDimensions = new C4BoardDimensions(initialRowCount, initialColumnCount);
105:         this.solutionSize = initialSolutionSize;
106:     }
107: 
108:     /**
109:      * Returns the number of players that will play on the board.
110:      */
111:     public int getPlayerCount() {
112:         return playerCount;
113:     }
114: 
115:     /**
116:      * Returns the number of rows the board will have.
117:      */
118:     public int getRowCount() {
119:         return this.boardDimensions.getRowCount();
120:     }
121: 
122:     /**
123:      * Updates the number of rows the board will have to the specified value.
124:      * @param rowCount the new number of rows the board will have
125:      */
126:     public void setRowCount(final int rowCount) {
127:         this.boardDimensions.setRowCount(rowCount);
128:     }
129: 
130:     /**
131:      * Returns the number of columns the board will have.
132:      */
133:     public int getColumnCount() {
134:         return this.boardDimensions.getColumnCount();
135:     }
136: 
137:     /**
138:      * Updates the number of columns the board will have to the specified value.
139:      * @param columnCount the new number of columns the board will have
140:      */
141:     public void setColumnCount(final int columnCount) {
142:         this.boardDimensions.setColumnCount(columnCount);
143:     }
144: 
145:     /**
146:      * Returns the number of tokens that need to be matched to form a solution.
147:      */
148:     public int getSolutionSize() {
149:         return solutionSize;
150:     }
151: 
152:     /**
153:      * Updates the number of tokens that need to be matched to form a solution to the specified value.
154:      * @param solutionSize the new number of tokens that need to be matched to form a solution
155:      */
156:     public void setSolutionSize(final int solutionSize) {
157:         this.solutionSize = solutionSize;
158:     }
159: 
160:     /**
161:      * Checks if the current board settings comply with the board limits.
162:      * @throws InputProviderException if the current board limits are invalid
163:      */
164:     public void assertIsValid() throws InputProviderException {
165:         // validate board size
166:         this.assertStaticLimits();
167:         this.boardDimensions.assertStaticLimits();
168: 
169:         final int fieldCount = this.boardDimensions.getRowCount() * this.boardDimensions.getColumnCount();
170:         // check for fieldCount > MAX_FIELD_COUNT
171:         if (fieldCount < 0) { // 32 bit signed integer overflow
172:             throw new InputProviderException("The board is too large: the total number of fields exceeds "
173:                 + "the maximum allowed value (" + MAX_FIELD_COUNT + ").");
174:         }
175: 
176:         // validate solution size
177:         // does the solution fit on the board?
178:         if (this.solutionSize > Math.max(this.boardDimensions.getRowCount(), this.boardDimensions.getColumnCount())) {
179:             throw new InputProviderException("The required solution size is too large: the solution size exceeds "
180:                 + "the number of rows and columns on the board. This is dumb.");
181:         }
182:         // has every player the possibility to win?
183:         if (fieldCount < this.playerCount * this.solutionSize) {
184:             throw new InputProviderException("The current board settings do not allow every player to win: "
185:                 + "the number of fields is too small to allow every player to form a solution, if players "
186:                 + "take turns placing tokens.");
187:         }
188:     }
189:     
190:     /**
191:      * Checks if the current board settings comply with the static board limits.
192:      * @throws InputProviderException if they don't comply...
193:      */
194:     private void assertStaticLimits() throws InputProviderException {
195:         if (this.solutionSize < MIN_SOLUTION_SIZE) {
196:             throw new InputProviderException("The specified solution size is too small: the solution size "
197:                 + "must be at least " + MIN_SOLUTION_SIZE + ".");
198:         }
199:         if (this.solutionSize > MAX_SOLUTION_SIZE) {
200:             throw new InputProviderException("The specified solution size is too large: the solution size "
201:                 + "must not exceed " + MAX_SOLUTION_SIZE + ".");
202:         }
203:     }
204: 
205:     @Override
206:     public boolean equals(final Object object) {
207:         if (object == null) {
208:             return false;
209:         }
210:         if (object == this) {
211:             return true;
212:         }
213:         if (!(object instanceof C4BoardLimits)) {
214:             return false;
215:         }
216:         final C4BoardLimits other = (C4BoardLimits) object;
217:         return this.boardDimensions.equals(other.boardDimensions)
218:             && this.solutionSize == other.solutionSize
219:             && this.playerCount == other.playerCount;
220:     }
221: 
222:     @Override
223:     public int hashCode() {
224:         int hash = 7;
225:         hash = hash * 31 + this.boardDimensions.hashCode();
226:         hash = hash * 31 + this.solutionSize;
227:         hash = hash * 31 + this.playerCount;
228:         return hash;
229:     }
230: }