class SwordfishStrategy implements Strategy { static getTests() { def t = new Test('...47.6....4...3.592........31.........936.........28........164.8...9....7.52...') [ new Test( /* * (2,1) and (9,1) are only col 1 cells with '1' as candidate * (6,4) and (9,4) are the same * (2,6) and (6,6) are the same * thus rows 2, 9, and 9 cannot have a '1' anywhere else (namely (2,2) and (6,5)) */ '000479620004000395926000000' + '031000069000936000009000283' + '050894716408000952097052030', { for (c in [it.getCell(2, 2), it.getCell(6, 5)]) { if (c.hasMark(1)) { return false } } true } ), t, new Test( t.spec.flipPrimaryDiagonal() ), new Test('5.......4.89..3.7..672.......3.7.....2..6..9.....1.8.......943..4.8..65.8.......1') ] } boolean play(Board board) { def madePlay = false // the rows/col and cols/row pairings are identical, so we parameterize and loop // the former is what we're looking for matches in, the latter is what we clear for (dir in [[houses: "rows", house: "col"], [houses: "cols", house: "row"]]) { for (top in board[dir.houses]) { for (n in 1..9) { def topCells = top.findAll { ! it.isKnown() && it.hasMark(n) } if (topCells.size() == 2 || topCells.size() == 3) { // kick ass, we have the top of a potential swordfish for (middle in board[dir.houses].findAll { it.num > top.num }) { def middleCells = middle.findAll { ! it.isKnown() && it.hasMark(n) } if ((middleCells.size() == 2 || middleCells.size() == 3) && (topCells*."$dir.house" + middleCells*."$dir.house").unique().size <= 3) { // ok, we found a valid middle for (bottom in board[dir.houses].findAll { it.num > middle.num }) { def bottomCells = bottom.findAll { ! it.isKnown() && it.hasMark(n) } if ((bottomCells.size() == 2 || bottomCells.size() == 3) && (topCells*."$dir.house" + middleCells*."$dir.house" + bottomCells*."$dir.house").unique().size() == 3) { // sweet, it's a swordfish (topCells*."$dir.house" + middleCells*."$dir.house" + bottomCells*."$dir.house").flatten().each { if (! (it in topCells) && ! (it in middleCells) && ! (it in bottomCells)) { if (! it.isKnown() && it.hasMark(n)) { madePlay = it.removeMark(n, this) || madePlay } } } if (madePlay) { return true } } } } } } } } } madePlay } }