Skip to content

Instantly share code, notes, and snippets.

@glukianets
Created August 15, 2024 15:38
Show Gist options
  • Save glukianets/d55b4231601ed2f7cf95cebc8fb72663 to your computer and use it in GitHub Desktop.
Save glukianets/d55b4231601ed2f7cf95cebc8fb72663 to your computer and use it in GitHub Desktop.
Naive 8Queens puzzle solution with bitmasks
func queen(atFile file: Int, rank: Int) -> UInt64 {
0b00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001 << (file) |
0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_11111111 << (rank * 8) |
0b10000000_01000000_00100000_00010000_00001000_00000100_00000010_00000001 >> ((file - rank) * 8) |
0b00000001_00000010_00000100_00001000_00010000_00100000_01000000_10000000 >> ((7 - file - rank) * 8)
}
func occupiedIndices(in board: UInt64) -> some Sequence<(file: Int, rank: Int)> {
sequence(state: (board, 0)) { state in
let offset = state.0.trailingZeroBitCount
state.1 += offset
state.0 >>= offset + 1
defer { state.1 += 1 }
guard state.1 < MemoryLayout<UInt64>.size * 8 else { return nil }
return (file: state.1 % 8, rank: state.1 / 8)
}
}
func traverse(_ board: UInt64 = 0, mask: UInt64 = 0, results: inout Set<UInt64>) {
if board.nonzeroBitCount == 8 {
results.insert(board)
} else {
for (file, rank) in occupiedIndices(in: ~mask) {
let queen = queen(atFile: file, rank: rank)
guard board & queen == 0 else { continue }
traverse(board | (1 << (rank * 8 + file)), mask: mask | queen, results: &results)
}
}
}
var results: Set<UInt64> = []
traverse(results: &results)
for result in results {
print(occupiedIndices(in: result).map {
"\(Character(UnicodeScalar($0 + 97)!))\(Character(UnicodeScalar($1 + 49)!))"
}.joined(separator: ", "))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment