Skip to content

Method: C4SolutionAnalyzerDiagonalLeft(C4BoardSlim)

1: package de.fhdw.gaming.ipspiel23.c4.domain.impl.evaluation;
2:
3: import java.util.Set;
4:
5: import de.fhdw.gaming.ipspiel23.c4.domain.C4Direction;
6: import de.fhdw.gaming.ipspiel23.c4.domain.IC4SolutionSlim;
7: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim;
8: import de.fhdw.gaming.ipspiel23.c4.domain.impl.C4SolutionSlim;
9:
10: import static de.fhdw.gaming.ipspiel23.c4.domain.impl.C4BoardSlim.EMPTY_TOKEN;
11:
12: /**
13: * A {@link C4SolutionAnalyzer} that analyzes the board on the diagonal from the bottom left to the top right.
14: */
15: public class C4SolutionAnalyzerDiagonalLeft extends C4SolutionAnalyzerDiagonal {
16:
17: /**
18: * Creates a new {@link C4SolutionAnalyzerDiagonalLeft}.
19: * @param board The board to analyze.
20: */
21: public C4SolutionAnalyzerDiagonalLeft(final C4BoardSlim board) {
22: super(board, C4Direction.NORTH_EAST);
23: }
24:
25: @Override
26: public IC4SolutionSlim tryFindFirstSolution(final IC4SolutionSlim currentSolution, final boolean updateCache) {
27: // "Assignment of parameter 'currentSolution' is not allowed." :P
28: IC4SolutionSlim solution = currentSolution;
29:
30: int iteration = 0;
31: // determine start row of column 0 (skip first targetCount rows)
32: for (int startRow = targetCount(); solution == null && startRow < rowMax(); startRow++, iteration++) {
33: if (mayContainSolution(iteration)) {
34: solution = tryFindFirstSolution(startRow, 0, iteration, updateCache);
35: }
36: }
37: // determine start column of last row (ignore last targetCount columns)
38: // don't evaluate diagonal starting in bottom left twice (startCol = 1)
39: for (int startCol = 1; solution == null && startCol < colMax() - targetCount(); startCol++, iteration++) {
40: if (mayContainSolution(iteration)) {
41: solution = tryFindFirstSolution(rowMax() - 1, startCol, iteration, updateCache);
42: }
43: }
44: return solution;
45: }
46:
47: /**
48: * Lazily searches for the first solution on the board starting at the specified position.
49: * @param startRow the row to start at
50: * @param startCol the column to start at
51: * @param iteration the current iteration of the search
52: * @param updateCache whether to update the solution cache, preventing the same line to be checked again
53: * @return The first solution on the board or null if no solution was found.
54: */
55: private IC4SolutionSlim tryFindFirstSolution(final int startRow, final int startCol,
56: final int iteration, final boolean updateCache) {
57: int count = 0;
58: int lastToken = 0;
59: // "ForLoopVariableCount: Too many control variables in the for statement" :P
60: int row = startRow;
61: int col = startCol;
62: boolean isDiagonalFull = true;
63: for (; row >= 0 && col < colMax(); row--, col++) {
64: final int token = board().getTokenUnsafe(row, col);
65: count = countConsecutivesBranchless(count, token, lastToken);
66: if (count >= targetCount()) {
67: return scanRemaining(token, row, col);
68: }
69: isDiagonalFull &= token != EMPTY_TOKEN;
70: lastToken = token;
71: }
72: if (updateCache && isDiagonalFull) {
73: noSolutionIn(iteration);
74: }
75: return null;
76: }
77:
78: @Override
79: public void findAllSolutions(final Set<IC4SolutionSlim> resultSet, final boolean updateCache) {
80:
81: int iteration = 0;
82: // determine start row of column 0 (skip first targetCount rows)
83: for (int startRow = targetCount(); startRow < rowMax(); startRow++, iteration++) {
84: if (mayContainSolution(iteration)) {
85: findAllSolutions(resultSet, startRow, 0, iteration, updateCache);
86: }
87: }
88: // determine start column of last row (ignore last targetCount columns)
89: // don't evaluate diagonal starting in bottom left twice (startCol = 1)
90: for (int startCol = 1; startCol < colMax() - targetCount(); startCol++, iteration++) {
91: if (mayContainSolution(iteration)) {
92: findAllSolutions(resultSet, rowMax() - 1, startCol, iteration, updateCache);
93: }
94: }
95: }
96:
97: /**
98: * Eagerly searches for all solutions on the board starting at the specified position.
99: * @param startRow the row to start at
100: * @param startCol the column to start at
101: * @param iteration the current iteration of the search
102: * @param updateCache whether to update the solution cache, preventing the same line to be checked again
103: * @param resultSet the set to which any solutions are added
104: */
105: private void findAllSolutions(final Set<IC4SolutionSlim> resultSet, final int startRow,
106: final int startCol, final int iteration, final boolean updateCache) {
107: int count = 0;
108: int lastToken = 0;
109: int row = startRow;
110: int col = startCol;
111: boolean isDiagonalFull = true;
112: boolean diagonalContainsSolution = false;
113: for (; row >= 0 && col < colMax(); row--, col++) {
114: final int token = board().getTokenUnsafe(row, col);
115: count = countConsecutivesBranchless(count, token, lastToken);
116: if (count >= targetCount()) {
117: count = 0;
118:
119: final C4SolutionSlim solution = scanRemaining(token, row, col);
120: resultSet.add(solution);
121: diagonalContainsSolution = true;
122: // skip to end of solution
123: row = solution.getRowIndexEnd();
124: col = solution.getColumnIndexEnd();
125: }
126: isDiagonalFull &= token != EMPTY_TOKEN;
127: lastToken = token;
128: }
129: if (updateCache && isDiagonalFull && !diagonalContainsSolution) {
130: noSolutionIn(iteration);
131: }
132: }
133:
134: @Override
135: protected C4SolutionSlim scanRemaining(final int token, final int startRow, final int startCol) {
136: int row = startRow - 1;
137: int col = startCol + 1;
138: while (row >= 0 && col < colMax() && board().getTokenUnsafe(row, col) == token) {
139: row--;
140: col++;
141: }
142: // revert last change to get inclusive upper bound
143: row++;
144: col--;
145: // determine true solution size
146: return solutionOf(token, row, col, board().getMinimumSolutionSize() + col - startCol);
147: }
148: }