Last active
February 4, 2018 16:48
-
-
Save eliperkins/3f33a403e7a1c1c38c659783771c06a4 to your computer and use it in GitHub Desktop.
Generate Super Bowl Squares in a Xcode Playground
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
//: Playground - noun: a place where people can play | |
//: Super Bowl Squares - noun: free money | |
import Foundation | |
import PlaygroundSupport | |
enum Player: String { | |
case eli = "Eli" | |
case brian = "Brian" | |
case brendan = "Brendan" | |
case pat = "Pat" | |
static let allPlayers: Array<Player> = [.eli, .brendan, .brian, .pat] | |
static func randomPlayer() -> Player { | |
return allPlayers[Int(arc4random_uniform(UInt32(allPlayers.count)))] | |
} | |
} | |
extension Collection where Index == Int { | |
func random() -> Element { | |
return self[Int(arc4random_uniform(UInt32(count)))] | |
} | |
} | |
struct Square { | |
let patsScore: Int | |
let eaglesScore: Int | |
let player: Player | |
} | |
extension Square: Equatable, Hashable { | |
static func ==(lhs: Square, rhs: Square) -> Bool { | |
return lhs.patsScore == rhs.patsScore && lhs.eaglesScore == rhs.eaglesScore && lhs.player == rhs.player | |
} | |
var hashValue: Int { | |
return patsScore ^ eaglesScore ^ player.hashValue | |
} | |
} | |
extension Square: CustomDebugStringConvertible { | |
var debugDescription: String { | |
return "\(player.rawValue): Pats \(patsScore) - Eagles \(eaglesScore)" | |
} | |
} | |
extension Square: Codable { | |
enum CodingKeys: String, CodingKey { | |
case pats | |
case eagles | |
case player | |
} | |
func encode(to encoder: Encoder) throws { | |
var container = encoder.container(keyedBy: CodingKeys.self) | |
try container.encode(patsScore, forKey: .pats) | |
try container.encode(eaglesScore, forKey: .eagles) | |
try container.encode(player.rawValue, forKey: .player) | |
} | |
init(from decoder: Decoder) throws { | |
let values = try decoder.container(keyedBy: CodingKeys.self) | |
self.patsScore = try values.decode(Int.self, forKey: .pats) | |
self.eaglesScore = try values.decode(Int.self, forKey: .eagles) | |
self.player = Player(rawValue: try values.decode(String.self, forKey: .player)) ?? .eli | |
} | |
} | |
func randomPlayer(from players: Array<Player>, with squareCounts: NSCountedSet, maxSquares: Int) -> Player { | |
while (true) { | |
let player = players.random() | |
if squareCounts.count(for: player) < maxSquares { | |
return player | |
} | |
} | |
} | |
typealias Board = Array<Array<Square>> | |
func generateBoard(with players: [Player]) -> Board { | |
let squareSize = (0...9).count | |
let totalSquares = squareSize * squareSize | |
let (baseSquares, remainder) = totalSquares.quotientAndRemainder(dividingBy: players.count) | |
let squaresPerPerson = remainder == 0 ? baseSquares : baseSquares + 1 | |
let squareCounts = NSCountedSet(capacity: players.count) | |
return (0...9).map({ pats in | |
return (0...9).map({ eagles in | |
let player = randomPlayer(from: players, with: squareCounts, maxSquares: squaresPerPerson) | |
squareCounts.add(player) | |
return Square(patsScore: pats, eaglesScore: eagles, player: player) | |
}) | |
}) | |
} | |
func print(_ board: Board) { | |
let maxNameLength = Player.allPlayers.map({ $0.rawValue.count }).max() ?? 5 | |
let header = (0...9).map(String.init) | |
.map({ $0.padding(toLength: maxNameLength, withPad: " ", startingAt: 0) }) | |
.joined(separator: "|") | |
print(" |\(header)") | |
board.enumerated().forEach { (rowIndex, row) in | |
let rowString = row.map({ | |
$0.player.rawValue.padding(toLength: maxNameLength, withPad: " ", startingAt: 0) | |
}).joined(separator: "|") | |
print("\(rowIndex) |\(rowString)") | |
} | |
} | |
func printPlayerSquares(for board: Board) { | |
let allSquares = board.reduce([], +) | |
let grouped = Dictionary(grouping: allSquares, by: { $0.player }) | |
grouped.forEach { (player, squares) in | |
let squaresString = squares.map({ "\($0.patsScore), \($0.eaglesScore)" }).joined(separator: "\n") | |
print("\(player.rawValue): \n\(squaresString)") | |
} | |
} | |
func squareFor(score score: (Int, Int), from board: Board) -> Square { | |
let pats = score.0 % 10 | |
let eagles = score.1 % 10 | |
return board[pats][eagles] | |
} | |
let fileURL = URL(fileURLWithPath: "board.json", isDirectory: false, relativeTo: playgroundSharedDataDirectory) | |
func save(_ board: Board) { | |
let encoder = JSONEncoder() | |
encoder.outputFormatting = .prettyPrinted | |
guard let data = try? encoder.encode(board) else { fatalError() } | |
do { | |
try data.write(to: fileURL) | |
} catch { | |
fatalError() | |
} | |
} | |
func loadBoard() -> Board { | |
guard let data = try? Data(contentsOf: fileURL) else { fatalError() } | |
let decoder = JSONDecoder() | |
guard let board = try? decoder.decode(Board.self, from: data) else { fatalError() } | |
return board | |
} | |
//let board = generateBoard(with: Player.allPlayers) | |
//save(board) | |
let board = loadBoard() | |
let firstQuarter = squareFor(score: (0, 0), from: board) | |
let halftime = squareFor(score: (0, 0), from: board) | |
let thirdQuarter = squareFor(score: (0, 0), from: board) | |
let final = squareFor(score: (0, 0), from: board) | |
print(board) | |
printPlayerSquares(for: board) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment