Skip to content

Instantly share code, notes, and snippets.

@jakubpetrik
Created October 10, 2015 16:14
Show Gist options
  • Save jakubpetrik/9fcc57cdeae43caa2a7c to your computer and use it in GitHub Desktop.
Save jakubpetrik/9fcc57cdeae43caa2a7c to your computer and use it in GitHub Desktop.
Flipping bits game in Swift
/**
http://rosettacode.org/wiki/Flipping_bits_game
The game
Given an N by N square array of zeroes or ones in an initial configuration,
and a target configuration of zeroes and ones The task is to transform one to the other in as
few moves as possible by inverting whole numbered rows or whole lettered columns at once, as one move.
In an inversion any 1 becomes 0, and any 0 becomes 1 for that whole row or column.
The Task
The task is to create a program to score for the Flipping bits game.
The game should create an original random target configuration and a starting configuration.
Ensure that the starting position is never the target position.
The target position must be guaranteed as reachable from the starting position.
(One possible way to do this is to generate the start position by legal flips from a random target position.
The flips will always be reversible back to the target from the given start position).
The number of moves taken so far should be shown.
Show an example of a short game here, on this page, for a 3 by 3 array of bits.
*/
import Foundation
struct Board: Equatable, CustomStringConvertible {
let size: Int
private var tiles: [Bool]
init(size: Int) {
self.size = size
tiles = Array(count: size * size, repeatedValue: false)
}
subscript(x: Int, y: Int) -> Bool {
get {
return tiles[y * size + x]
}
set {
tiles[y * size + x] = newValue
}
}
mutating func randomize() {
for i in 0..<tiles.count {
tiles[i] = Bool(random() % 2)
}
}
mutating func flipRow(row: Int) {
for i in 0..<size {
self[row, i] = !self[row, i]
}
}
mutating func flipColumn(column: Int) {
for i in 0..<size {
self[i, column] = !self[i, column]
}
}
var description: String {
var desc = "\n\ta\tb\tc\n"
for i in 0..<size {
desc += "\(i+1):\t"
for j in 0..<size {
desc += "\(Int(self[i, j]))\t"
}
desc += "\n"
}
return desc
}
}
func ==(lhs: Board, rhs: Board) -> Bool {
return lhs.tiles == rhs.tiles
}
class FlippingGame: CustomStringConvertible {
var board: Board
var target: Board
var solved: Bool { return board == target }
init(boardSize: Int) {
target = Board(size: 3)
board = Board(size: 3)
generateTarget()
}
func generateTarget() {
target.randomize()
board = target
let size = board.size
while solved {
for _ in 0..<size + (random() % size + 1) {
if random() % 2 == 0 {
board.flipColumn(random() % size)
}
else {
board.flipRow(random() % size)
}
}
}
}
func getMove() -> Bool {
print(self)
print("Flip what? ", terminator: "")
guard
let move = readLine(stripNewline: true)
where move.characters.count == 1
else { return false }
var moveValid = true
if let row = Int(move) {
board.flipRow(row - 1)
}
else if let column = move.lowercaseString.utf8.first where column < 100 && column > 96 {
board.flipColumn(numericCast(column) - 97)
}
else {
moveValid = false
}
return moveValid
}
var description: String {
var str = ""
print("Target: \n \(target)", toStream: &str)
print("Board: \n \(board)", toStream: &str)
return str
}
}
func playGame(game: FlippingGame) -> String {
game.generateTarget()
var numMoves = 0
while !game.solved {
numMoves++
print("Move #\(numMoves)")
while !game.getMove() {}
}
print("You win!")
print("Number of moves: \(numMoves)")
print("\n\nPlay Again? ", terminator: "")
return readLine(stripNewline: true)!.lowercaseString
}
let game = FlippingGame(boardSize: 3)
repeat { } while playGame(game) == "y"
/**
Outputs:
Move #1
Target:
a b c
1: 1 1 0
2: 0 0 1
3: 1 0 1
Board:
a b c
1: 0 1 0
2: 1 0 1
3: 0 0 1
Flip what? a
You win!
Number of moves: 1
Play Again? n
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment