Created
October 10, 2015 16:14
-
-
Save jakubpetrik/9fcc57cdeae43caa2a7c to your computer and use it in GitHub Desktop.
Flipping bits game in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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