Skip to contentMethod: scanRemaining(int, int, int)
      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 horizontally (rows).
14:  */
15: public class C4SolutionAnalyzerHorizontal extends C4SolutionAnalyzer {
16: 
17:     /**
18:      * The last row which is updated while searching for a solution to 
19:      * speed up the search process.
20:      */
21:     private int optimizedRowMax;
22: 
23:     /**
24:      * Creates a new {@link C4SolutionAnalyzerHorizontal}.
25:      * @param board The board to analyze.
26:      */
27:     public C4SolutionAnalyzerHorizontal(final C4BoardSlim board) {
28:         super(board, C4Direction.EAST);
29:         optimizedRowMax = super.rowMax();
30:     }
31: 
32:     @Override
33:     public IC4SolutionSlim tryFindFirstSolution(final IC4SolutionSlim currentSolution, final boolean updateCache) {
34: 
35:         if (currentSolution != null) {
36:             return currentSolution;
37:         }
38:         
39:         boolean isRowEmpty = false;
40:         // count row by row, EAST from bottom to top for faster matches
41:         // abort as soon as we reach an empty row (gravity)
42:         for (int row = this.optimizedRowMax - 1; row >= 0 && !isRowEmpty; row--) {
43:             int token;
44:             int lastToken = 0;
45:             int count = 0;
46:             isRowEmpty = true;
47:             boolean isRowFull = true;
48:             for (int col = 0; col < colMax(); col++, lastToken = token) {
49:                 token = board().getTokenUnsafe(row, col);
50:                 count = countConsecutivesBranchless(count, token, lastToken);
51:                 if (count >= targetCount()) {
52:                     return scanRemaining(token, row, col);
53:                 }
54:                 isRowFull &= token != EMPTY_TOKEN;
55:                 isRowEmpty &= token == EMPTY_TOKEN;
56:             }
57:             // if the current row is full and contains no solution we can remember that
58:             // and don't have to re-evaluate that row next time
59:             if (updateCache && isRowFull) {
60:                 this.optimizedRowMax = row;
61:             }
62:         }
63:         return null;
64:     }
65: 
66:     @Override
67:     public void findAllSolutions(final Set<IC4SolutionSlim> resultSet, final boolean updateCache) {
68:         // count row by row, EAST from bottom to top for faster matches
69:         boolean isRowEmpty = false;
70:         for (int row = this.optimizedRowMax - 1; row >= 0 && !isRowEmpty; row--) {
71:             isRowEmpty = true;
72:             int token;
73:             int lastToken = 0;
74:             int count = 0;
75:             boolean isRowFull = true;
76:             boolean rowContainsSolution = false;
77:             int col = 0;
78:             for (; col < colMax(); col++, lastToken = token) {
79:                 token = board().getTokenUnsafe(row, col);
80:                 count = countConsecutivesBranchless(count, token, lastToken);
81:                 if (count >= targetCount()) {
82:                     count = 0;
83:                     final C4SolutionSlim solution = scanRemaining(token, row, col);
84:                     resultSet.add(solution);
85:                     rowContainsSolution = true;
86:                     // skip to the end of the solution
87:                     col = solution.getColumnIndexEnd();
88:                 }
89:                 isRowFull &= token != EMPTY_TOKEN;
90:                 isRowEmpty &= token == EMPTY_TOKEN;
91:             }
92:             // if the current row is full and contains no solution we can remember that
93:             // and don't have to re-evaluate that row the next time
94:             if (updateCache && isRowFull && !rowContainsSolution) {
95:                 this.optimizedRowMax = row;
96:             }
97:         }
98:     }
99:     
100:     @Override
101:     protected C4SolutionSlim scanRemaining(final int token, final int startRow, final int startCol) {
102:         int col = startCol + 1;
103:•        while (col < colMax() && board().getTokenUnsafe(startRow, col) == token) {
104:             col++;
105:         }
106:         // revert last change to get inclusive upper bound
107:         col--;
108:         return solutionOf(token, startRow, col, board().getMinimumSolutionSize() + col - startCol);
109:     }
110: 
111:     @Override
112:     public void resetCache() {
113:         this.optimizedRowMax = super.rowMax();
114:     }
115: }