Showing preview only (517K chars total). Download the full file or copy to clipboard to get everything.
Repository: joalbright/Gameboard
Branch: master
Commit: 0c14a0a928f8
Files: 99
Total size: 478.1 KB
Directory structure:
gitextract_tij_wt8g/
├── .gitignore
├── Gameboards.playground/
│ ├── Pages/
│ │ ├── Checkers.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── Chess.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── Go.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── Mancala.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── Minesweeper.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── Sudoku.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ └── TicTacToe.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Sources/
│ │ ├── Boards/
│ │ │ ├── Alquerque.swift
│ │ │ ├── Backgammon.swift
│ │ │ ├── Bombsweeper.swift
│ │ │ ├── Checkers.swift
│ │ │ ├── Chess.swift
│ │ │ ├── Dots.swift
│ │ │ ├── Doubles.swift
│ │ │ ├── Four.swift
│ │ │ ├── Go.swift
│ │ │ ├── InProgress/
│ │ │ │ ├── Battleship.swift
│ │ │ │ ├── Dominos.swift
│ │ │ │ ├── Majong.swift
│ │ │ │ ├── Pilare.swift
│ │ │ │ ├── Tetris.swift
│ │ │ │ └── Trouble.swift
│ │ │ ├── Ludo.swift
│ │ │ ├── Mancala.swift
│ │ │ ├── Memory.swift
│ │ │ ├── Pegs.swift
│ │ │ ├── Sudoku.swift
│ │ │ ├── TicTacToe.swift
│ │ │ └── Words.swift
│ │ ├── Core/
│ │ │ ├── Extensions.swift
│ │ │ ├── Grid.swift
│ │ │ ├── Operators.swift
│ │ │ └── Views/
│ │ │ ├── BackgammonView.swift
│ │ │ ├── DotsView.swift
│ │ │ ├── FourView.swift
│ │ │ ├── GoView.swift
│ │ │ ├── MancalaView.swift
│ │ │ ├── MatrixView.swift
│ │ │ ├── PegsView.swift
│ │ │ ├── SudokuView.swift
│ │ │ ├── TicTacToeView.swift
│ │ │ └── WordsView.swift
│ │ ├── Gameboard.swift
│ │ └── Validation.swift
│ └── contents.xcplayground
├── Games/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Colors/
│ │ │ ├── Accent.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── Background.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Offest.colorset/
│ │ │ │ └── Contents.json
│ │ │ └── Text.colorset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── BoardController/
│ │ ├── BoardViewController.swift
│ │ ├── BoardViews/
│ │ │ ├── BackgammonBoardView.swift
│ │ │ ├── BombsweeperBoardView.swift
│ │ │ ├── CheckersBoardView.swift
│ │ │ ├── ChessBoardView.swift
│ │ │ ├── DotsBoardView.swift
│ │ │ ├── DoublesBoardView.swift
│ │ │ ├── FourBoardView.swift
│ │ │ ├── GoBoardView.swift
│ │ │ ├── MancalaBoardView.swift
│ │ │ ├── MemoryBoardView.swift
│ │ │ ├── PegsBoardView.swift
│ │ │ ├── SudokuBoardView.swift
│ │ │ ├── TicTacToeBoardView.swift
│ │ │ └── WordsBoardView.swift
│ │ └── Boards/
│ │ ├── Backgammon.storyboard
│ │ ├── Bombsweeper.storyboard
│ │ ├── Checkers.storyboard
│ │ ├── Chess.storyboard
│ │ ├── Dots.storyboard
│ │ ├── Doubles.storyboard
│ │ ├── Four.storyboard
│ │ ├── Go.storyboard
│ │ ├── Mancala.storyboard
│ │ ├── Memory.storyboard
│ │ ├── Pegs.storyboard
│ │ ├── Sudoku.storyboard
│ │ ├── TicTacToe.storyboard
│ │ └── Words.storyboard
│ ├── Info.plist
│ └── MainViewController.swift
├── Games.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── README.md
├── RM_Checkers.md
├── RM_Chess.md
├── RM_Go.md
├── RM_Minesweeper.md
├── RM_Sudoku.md
├── RM_TicTacToe.md
└── icon.ai
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/
.DS_Store
================================================
FILE: Gameboards.playground/Pages/Checkers.xcplaygroundpage/Contents.swift
================================================
import UIKit
var checkers = Gameboard(.Checkers)
// setup colors
var colors = BoardColors()
colors.background = UIColor(red:0.66, green:0.62, blue:0.48, alpha:1)
colors.foreground = UIColor(red:0.62, green:0.58, blue:0.44, alpha:1)
colors.player1 = UIColor(red:0.8, green:0.13, blue:0, alpha:1)
colors.player2 = UIColor(red:0.13, green:0.13, blue:0.13, alpha:1)
colors.selected = UIColor.whiteColor()
colors.highlight = UIColor.whiteColor()
checkers.boardColors = colors
// collection of moves
let moves: [(Square,Square)] = [
((2,1),(3,2)), // move
((5,2),(4,3)), // move
((2,3),(3,4)), // move
((4,3),(2,1)), // jump
((2,5),(4,3)), // cannot jump yourself
((2,5),(3,4)), // cannot land on your own piece
((1,0),(2,1)), // cannot land on another piece
]
// loop moves
for move in moves {
do {
try checkers.move(pieceAt: move.0, toSquare: move.1)
} catch {
print(error)
}
}
checkers.showAvailable((1,2))
checkers.visualize()
================================================
FILE: Gameboards.playground/Pages/Chess.xcplaygroundpage/Contents.swift
================================================
import UIKit
var chess = Gameboard(.Chess)
// setup colors
var colors = BoardColors()
colors.background = UIColor(red:0.52, green:0.68, blue:0.43, alpha:1)
colors.foreground = UIColor(red:0.48, green:0.64, blue:0.39, alpha:1)
colors.player1 = UIColor.whiteColor()
colors.player2 = UIColor.blackColor()
colors.selected = UIColor(red:0.06, green:0.46, blue:0.71, alpha:1)
colors.highlight = UIColor(red:0.06, green:0.46, blue:0.71, alpha:1)
chess.boardColors = colors
// collection of moves
let moves: [(ChessSquare,ChessSquare)] = [
(B7,B5), // pawn leaps
(C2,C4), // pawn leaps
(B5,C4), // pawn takes pawn
(B1,C3), // knight charges
(C8,A6), // bishop advances
(E2,E4), // pawn leaps
(G7,G6), // pawn creeps
(F1,C4), // bishop take pawn
(A6,D3), // blocked move throws error
]
// loop moves
for move in moves {
do {
try chess.move(pieceAt: move.0, toSquare: move.1)
} catch {
print(error)
}
}
chess.showAvailable(A6)
chess.visualize()
================================================
FILE: Gameboards.playground/Pages/Go.xcplaygroundpage/Contents.swift
================================================
import UIKit
var go = Gameboard(.Go)
// setup colors
var colors = BoardColors()
colors.background = UIColor(red:0.36, green:0.29, blue:0.16, alpha:1)
colors.foreground = UIColor(red:0.11, green:0.08, blue:0.03, alpha:1)
colors.player1 = UIColor.whiteColor()
colors.player2 = UIColor.blackColor()
go.boardColors = colors
// collection of guesses
let moves: [Square] = [
// moves
(1,1),
(6,7),
(1,7),
(6,0),
(4,4),
(4,5),
(1,2),
]
// loop moves
for move in moves {
do {
try go.move(toSquare: move)
} catch {
print(error)
}
}
go.visualize()
================================================
FILE: Gameboards.playground/Pages/Mancala.xcplaygroundpage/Contents.swift
================================================
import UIKit
================================================
FILE: Gameboards.playground/Pages/Minesweeper.xcplaygroundpage/Contents.swift
================================================
import UIKit
enum MoveType { case Guess, Mark }
var minesweeper = Gameboard(.Minesweeper, testing: true)
// setup colors
var colors = BoardColors()
colors.background = UIColor(red:0.5, green:0.5, blue:0.5, alpha:1)
colors.foreground = UIColor(red:0.6, green:0.6, blue:0.6, alpha:1)
colors.player1 = UIColor.yellowColor()
colors.player2 = UIColor.blackColor()
colors.highlight = UIColor.blueColor()
colors.selected = UIColor.redColor()
minesweeper.boardColors = colors
// collection of guesses
let guesses: [(Square,MoveType)] = [
((4,3),.Guess), // guess
((9,0),.Mark), // mark
((7,4),.Mark), // mark
((4,1),.Mark), // mark
((4,0),.Guess), // guess
((0,9),.Guess), // guess
((2,7),.Mark), // guess
((6,9),.Guess), // guess
((1,0),.Guess), // game over
]
// loop guesses
for guess in guesses {
do {
switch guess.1 {
case .Guess: try minesweeper.guess(toSquare: guess.0)
case .Mark: try minesweeper.mark(toSquare: guess.0)
}
} catch {
print(error)
}
}
minesweeper.visualize(CGRect(x: 0, y: 0, width: 199, height: 199))
================================================
FILE: Gameboards.playground/Pages/Sudoku.xcplaygroundpage/Contents.swift
================================================
import UIKit
var sudoku = Gameboard(.Sudoku, testing: true)
// setup colors
var colors = BoardColors()
colors.background = UIColor(red:0.19, green:0.78, blue:0.71, alpha:1)
colors.foreground = UIColor(red:0.09, green:0.4, blue:0.44, alpha:1)
sudoku.boardColors = colors
// collection of guesses
let guesses: [(Square,Guess)] = [
// guesses
((0,2),"5"),
((8,8),"4"),
((6,5),"4"),
((2,7),"4"),
((3,0),"4"),
((5,3),"1"),
((6,2),"1"),
((7,8),"1"),
((2,5),"2"),
]
// loop guesses
for guess in guesses {
do {
try sudoku.guess(toSquare: guess.0, withGuess: guess.1)
} catch {
print(error)
}
}
sudoku.visualize(CGRect(x: 0, y: 0, width: 198, height: 198))
================================================
FILE: Gameboards.playground/Pages/TicTacToe.xcplaygroundpage/Contents.swift
================================================
import UIKit
var tictactoe = Gameboard(.TicTacToe)
// setup colors
var colors = BoardColors()
colors.player1 = UIColor(red:0.43, green:0.98, blue:0.7, alpha:1)
colors.player2 = UIColor(red:1, green:0.15, blue:0.18, alpha:1)
tictactoe.boardColors = colors
// collection of moves
let moves: [Square] = [
(1,1),
(0,0),
(0,2),
(2,0),
(1,0),
(1,2),
(0,1),
(1,1), // cant play filled spot
(2,1),
(2,2), // stalemate
]
// loop moves
for move in moves {
do {
try tictactoe.move(toSquare: move)
} catch {
print(error)
}
}
tictactoe.visualize()
================================================
FILE: Gameboards.playground/Sources/Boards/Alquerque.swift
================================================
import UIKit
public struct Alquerque {
}
================================================
FILE: Gameboards.playground/Sources/Boards/Backgammon.swift
================================================
import UIKit
public struct Backgammon {
public static var board: Grid {
return Grid([
"● ○ ○ ●".array(),
"● ○ ○ ●".array(),
"● ○ ○ ".array(),
"● ○ ".array(),
"● ○ ".array(),
"○ ● ".array(),
"○ ● ".array(),
"○ ● ● ".array(),
"○ ● ● ○".array(),
"○ ● ● ○".array()
])
}
public static let playerPieces = ["●","○"]
}
extension Grid {
public func backgammon(_ rect: CGRect) -> UIView {
let view = BackgammonView(frame: rect)
let w = (rect.width - 50.0) / 12
let h = (rect.height - 110.0) / 10
view.backgroundColor = colors.background
view.backgroundColor2 = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let y = r > 4 ? 95 : 15
let x = c > 5 ? 35 : 15
var piece = "\(item)"
let label = UILabel(frame: CGRect(x: c * w + x, y: r * h + y, width: w, height: h))
label.textColor = player(piece) == 0 ? colors.player1 : colors.player2
if player(piece) == 1 {
if let index = playerPieces[1].array().index(of: piece) { piece = playerPieces[0].array()[index] }
}
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2, weight: .regular)
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Bombsweeper.swift
================================================
import UIKit
extension Difficulty {
var bombFlags: Int {
switch self {
case .easy: return 20
case .medium: return 20
case .hard: return 20
}
}
var bombs: Int {
switch self {
case .easy: return 10
case .medium: return 15
case .hard: return 20
}
}
var bombsize: Int {
switch self {
case .easy: return 10
case .medium: return 15
case .hard: return 20
}
}
}
public struct Bombsweeper {
public static var board: Grid {
// randomize play area
let grid = Grid(10 ✕ (10 ✕ EmptyPiece))
for (r,_) in grid.content.enumerated() { grid[r,4] = "•" }
for (r,row) in grid.content.enumerated() { grid[r] = row.randomize().randomize().randomize() }
return addBombCount(grid)
}
public static var staticboard: Grid {
let grid = Grid([
" • ".array(),
"• • ".array(),
" • • • ".array(),
" •".array(),
" • ".array(),
" • ".array(),
" ".array(),
" • ".array(),
" • ".array(),
"• •• ".array()
])
return addBombCount(grid)
}
public static var field: Grid { return Grid(10 ✕ (10 ✕ "•")) }
public static let playerPieces = ["⚑","✘","⚐"]
public static func validateGuess(_ s1: Square, _ grid: Grid, _ solution: Grid) throws {
let a1 = solution[s1.0,s1.1]
guard a1 != "⚑" else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = a1
guard a1 != "•" else { grid[s1.0,s1.1] = "✘"; throw GameStatus.gameover }
guard a1 == EmptyPiece else { return }
try checkAdjacent(s1, grid, solution)
}
public static func validateMark(_ s1: Square, _ grid: Grid, _ solution: Grid) throws {
let g1 = grid[s1.0,s1.1]
guard ["⚑","•"].contains(g1) else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = g1 == "•" ? "⚑" : "•"
}
public static func checkAdjacent(_ s1: Square, _ grid: Grid, _ solution: Grid) throws {
let adjacent = [ (-1,-1),(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1) ]
for a in adjacent {
let s = (s1.0 + a.0, s1.1 + a.1)
guard grid.onBoard(s) else { continue }
let a1 = solution[s.0,s.1]
guard a1 != grid[s.0,s.1] else { continue }
grid[s.0,s.1] = a1
guard a1 == EmptyPiece else { continue }
try checkAdjacent(s, grid, solution)
}
}
public static func addBombCount(_ grid: Grid) -> Grid {
for r in grid.rowRange {
for c in grid.colRange {
guard grid[r,c] != "•" else { continue }
let bombs = bombCount((r,c), grid)
grid[r,c] = bombs == 0 ? EmptyPiece : "\(bombs)"
}
}
return grid
}
public static func bombCount(_ s1: Square, _ grid: Grid) -> Int {
var count = 0
let adjacent = [ (-1,-1),(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1) ]
for a in adjacent {
let s = (s1.0 + a.0, s1.1 + a.1)
guard grid.onBoard(s) else { continue }
if grid[s.0,s.1] == "•" { count += 1 }
}
return count
}
}
extension Grid {
public func bomb(_ rect: CGRect) -> UIView {
let view = UIView(frame: rect)
view.backgroundColor = colors.background
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - content.count + 1) / content.count
let h = (rect.height - content.count + 1) / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let piece = "\(item)"
let holder = UIView(frame: CGRect(x: c * w + c, y: r * h + r, width: w, height: h))
holder.backgroundColor = player(piece) == 1 ? colors.selected : colors.background
let label = UILabel(frame: CGRect(x: 0, y: 0, width: w, height: h))
label.text = player(piece) == 2 ? playerPieces[0] : piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 10, weight: .regular)
label.textColor = [0,2].contains(player(piece)) ? colors.player1 : colors.player2
label.backgroundColor = .clear
if piece == "•" {
label.textColor = colors.foreground
label.backgroundColor = colors.foreground
}
if let num = Int("\(item)"), num > 0 { label.textColor = colors.highlight }
holder.addSubview(label)
view.addSubview(holder)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Checkers.swift
================================================
import UIKit
public struct Checkers {
public enum PieceType: String {
case none = " "
case checker1 = "●"
case checker2 = "○"
case king1 = "◉"
case king2 = "◎"
}
public static var board: Grid {
return Grid([
8 ✕ (EmptyPiece %% "●"),
8 ✕ ("●" %% EmptyPiece),
8 ✕ (EmptyPiece %% "●"),
8 ✕ EmptyPiece,
8 ✕ EmptyPiece,
8 ✕ ("○" %% EmptyPiece),
8 ✕ (EmptyPiece %% "○"),
8 ✕ ("○" %% EmptyPiece)
])
}
public static let playerPieces = ["●◉","○◎"]
public static func validateJump(_ s1: Square, _ s2: Square, _ p1: Piece, _ p2: Piece, _ grid: Grid, _ hint: Bool = false) -> Bool {
let m1 = s2.0 - s1.0
let m2 = s2.1 - s1.1
let e1 = s1.0 + m1 / 2
let e2 = s1.1 + m2 / 2
guard let jumpedPieceType: PieceType = PieceType(rawValue: grid[e1,e2]), jumpedPieceType != .none else { return false }
switch PieceType(rawValue: p1) ?? .none {
case .checker1:
guard m1 == 2 && abs(m2) == 2 else { return false }
guard jumpedPieceType != .checker1, jumpedPieceType != .king1 else { return false }
case .checker2:
guard m1 == -2 && abs(m2) == 2 else { return false }
guard jumpedPieceType != .checker2, jumpedPieceType != .king2 else { return false }
case .king1:
guard abs(m1) == 2 && abs(m2) == 2 else { return false }
guard jumpedPieceType != .checker1, jumpedPieceType != .king1 else { return false }
case .king2:
guard abs(m1) == 2 && abs(m2) == 2 else { return false }
guard jumpedPieceType != .checker2, jumpedPieceType != .king2 else { return false }
case .none: return false
}
guard !hint else { return true }
grid[e1,e2] = EmptyPiece // remove other player piece
return true
}
public static func validateMove(_ s1: Square, _ s2: Square, _ p1: Piece, _ p2: Piece, _ grid: Grid, _ hint: Bool = false) throws -> Piece? {
let m1 = s2.0 - s1.0
let m2 = s2.1 - s1.1
var kingPiece: PieceType?
guard p2 == EmptyPiece else { throw MoveError.invalidmove }
switch PieceType(rawValue: p1) ?? .none {
case .checker1:
guard (m1 == 1 && abs(m2) == 1) || validateJump(s1, s2, p1, p2, grid, hint) else { throw MoveError.invalidmove }
if s2.c == grid.content.count - 1 { kingPiece = .king1 }
case .checker2:
guard (m1 == -1 && abs(m2) == 1) || validateJump(s1, s2, p1, p2, grid, hint) else { throw MoveError.invalidmove }
if s2.c == 0 { kingPiece = .king2 }
case .king1, .king2:
guard (abs(m1) == 1 && abs(m2) == 1) || validateJump(s1, s2, p1, p2, grid, hint) else { throw MoveError.invalidmove }
case .none: throw MoveError.incorrectpiece
}
guard !hint else { return nil }
let piece = grid[s2.0,s2.1]
grid[s2.0,s2.1] = kingPiece?.rawValue ?? p1 // place my piece in target square
grid[s1.0,s1.1] = EmptyPiece // remove my piece from original square
return piece
}
}
extension Grid {
public func checker(_ rect: CGRect, highlights: [Square], selected: Square?) -> UIView {
let view = UIView(frame: rect)
let w = rect.width / content.count
let h = rect.height / content.count
view.backgroundColor = colors.background
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
var piece = "\(item)"
let holder = UIView(frame: CGRect(x: c * w, y: r * h, width: w, height: h))
holder.backgroundColor = (c + r) % 2 == 0 ? colors.background : colors.foreground
let label = HintLabel(frame: CGRect(x: 0, y: 0, width: w, height: h))
label.backgroundColor = .clear
label.textColor = player(piece) == 0 ? colors.player1 : colors.player2
label.highlightColor = colors.highlight
if player(piece) == 1 {
if let index = playerPieces[1].array().index(of: piece) { piece = playerPieces[0].array()[index] }
}
if let selected = selected, selected.0 == r && selected.1 == c { label.textColor = colors.selected }
for highlight in highlights { label.highlight = label.highlight ? true : highlight.0 == r && highlight.1 == c }
label.text = piece
label.textAlignment = .center
label.font = UIFont(name: "Apple Symbols", size: (w + h) / 2 - 10)
holder.addSubview(label)
view.addSubview(holder)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Chess.swift
================================================
import UIKit
public struct Chess {
public enum PieceType: String {
case none = " "
case rook1 = "♜"
case knight1 = "♞"
case bishop1 = "♝"
case queen1 = "♛"
case king1 = "♚"
case pawn1 = "♟"
case rook2 = "♖"
case knight2 = "♘"
case bishop2 = "♗"
case queen2 = "♕"
case king2 = "♔"
case pawn2 = "♙"
}
public static var board: Grid {
return Grid([
"♜♞♝♛♚♝♞♜".array(),
8 ✕ "♟",
8 ✕ EmptyPiece,
8 ✕ EmptyPiece,
8 ✕ EmptyPiece,
8 ✕ EmptyPiece,
8 ✕ "♙",
"♖♘♗♕♔♗♘♖".array()
])
}
public static let playerPieces = ["♜♞♝♛♚♝♞♜♟","♖♘♗♕♔♗♘♖♙"]
public static func validateEmptyPath(_ s1: Square, _ s2: Square, _ grid: Grid) throws {
let mRow = s2.0 - s1.0
let mCol = s2.1 - s1.1
let d1 = mRow == 0 ? 0 : mRow > 0 ? 1 : -1
let d2 = mCol == 0 ? 0 : mCol > 0 ? 1 : -1
var p1 = s1.0 + d1, p2 = s1.1 + d2
while p1 != s2.0 || p2 != s2.1 {
guard grid[p1,p2] == EmptyPiece else { throw MoveError.blockedmove }
p1 += d1
p2 += d2
}
}
public static func validateMove(_ s1: Square, _ s2: Square, _ p1: Piece, _ p2: Piece, _ grid: Grid, _ hint: Bool = false) throws -> Piece? {
let mRow = s2.0 - s1.0
let mCol = s2.1 - s1.1
// let dR = mRow == 0 ? 0 : mRow > 0 ? 1 : -1
// let dC = mCol == 0 ? 0 : mCol > 0 ? 1 : -1
switch PieceType(rawValue: p1) ?? .none {
case .bishop1, .bishop2:
guard abs(mRow) == abs(mCol) else { throw MoveError.invalidmove }
try validateEmptyPath(s1, s2, grid)
case .king1, .king2:
guard abs(mRow) < 2 && abs(mCol) < 2 else { throw MoveError.invalidmove }
case .knight1, .knight2:
guard (abs(mRow) == 2 && abs(mCol) == 1) || (abs(mRow) == 1 && abs(mCol) == 2) else { throw MoveError.invalidmove }
case .pawn1:
guard (abs(mCol) == 0 && p2 == EmptyPiece) || (abs(mCol) == 1 && mRow == 1 && p2 != EmptyPiece) else { throw MoveError.invalidmove }
guard (mRow < 2 && mRow > 0) || (s1.0 == 1 && mRow == 2) else { throw MoveError.invalidmove }
try validateEmptyPath(s1, s2, grid)
case .pawn2:
guard (abs(mCol) == 0 && p2 == EmptyPiece) || (abs(mCol) == 1 && mRow == -1 && p2 != EmptyPiece) else { throw MoveError.invalidmove }
guard (mRow > -2 && mRow < 0) || (s1.0 == 6 && mRow == -2) else { throw MoveError.invalidmove }
try validateEmptyPath(s1, s2, grid)
case .queen1, .queen2:
guard mRow == 0 || mCol == 0 || abs(mRow) == abs(mCol) else { throw MoveError.invalidmove }
try validateEmptyPath(s1, s2, grid)
case .rook1, .rook2:
guard mRow == 0 || mCol == 0 else { throw MoveError.invalidmove }
try validateEmptyPath(s1, s2, grid)
case .none: throw MoveError.incorrectpiece
}
guard !hint else { return nil }
let piece = grid[s2.0,s2.1]
grid[s2.0,s2.1] = p1 // place my piece in target square
grid[s1.0,s1.1] = EmptyPiece // remove my piece from original square
return piece
}
}
// Coordinates
public let A8 = ("a",8), A7 = ("a",7), A6 = ("a",6), A5 = ("a",5), A4 = ("a",4), A3 = ("a",3), A2 = ("a",2), A1 = ("a",1)
public let B8 = ("b",8), B7 = ("b",7), B6 = ("b",6), B5 = ("b",5), B4 = ("b",4), B3 = ("b",3), B2 = ("b",2), B1 = ("b",1)
public let C8 = ("c",8), C7 = ("c",7), C6 = ("c",6), C5 = ("c",5), C4 = ("c",4), C3 = ("c",3), C2 = ("c",2), C1 = ("c",1)
public let D8 = ("d",8), D7 = ("d",7), D6 = ("d",6), D5 = ("d",5), D4 = ("d",4), D3 = ("d",3), D2 = ("d",2), D1 = ("d",1)
public let E8 = ("e",8), E7 = ("e",7), E6 = ("e",6), E5 = ("e",5), E4 = ("e",4), E3 = ("e",3), E2 = ("e",2), E1 = ("e",1)
public let F8 = ("f",8), F7 = ("f",7), F6 = ("f",6), F5 = ("f",5), F4 = ("f",4), F3 = ("f",3), F2 = ("f",2), F1 = ("f",1)
public let G8 = ("g",8), G7 = ("g",7), G6 = ("g",6), G5 = ("g",5), G4 = ("g",4), G3 = ("g",3), G2 = ("g",2), G1 = ("g",1)
public let H8 = ("h",8), H7 = ("h",7), H6 = ("h",6), H5 = ("h",5), H4 = ("h",4), H3 = ("h",3), H2 = ("h",2), H1 = ("h",1)
================================================
FILE: Gameboards.playground/Sources/Boards/Dots.swift
================================================
import UIKit
public struct Dots {
public static var board: Grid { return Grid(17 ✕ (17 ✕ ("●" %% "0") %% 17 ✕ ("0" %% EmptyPiece))) }
// public static var board: Grid { return Grid(8 ✕ (8 ✕ "00000")) }
public static let playerPieces = ["1","2"]
public static func validateMove(_ s1: Square, _ p1: Piece, _ grid: Grid, _ player: Int) throws {
guard p1 == "0" else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = playerPieces[player]
checkSpaces(s1, grid, player: player)
}
public static func checkSpaces(_ s1: Square, _ grid: Grid, player: Int) {
let adjacent2 = [ (-1,0),(0,1),(1,0),(0,-1) ]
for a in adjacent2 {
let s = (s1.0 + a.0, s1.1 + a.1)
guard grid.onBoard(s) else { continue }
guard grid[s.0,s.1] == EmptyPiece, checkClosed(s, grid) else { continue }
grid[s.0,s.1] = playerPieces[player]
}
}
public static func checkClosed(_ s1: Square, _ grid: Grid) -> Bool {
var count = 0
let adjacent2 = [ (-1,0),(0,1),(1,0),(0,-1) ]
for a in adjacent2 {
let s = (s1.0 + a.0, s1.1 + a.1)
guard grid.onBoard(s) else { continue }
if grid[s.0,s.1] != "0" { count += 1 }
}
return count == 4
}
}
extension Grid {
public func dots(_ rect: CGRect) -> UIView {
let view = DotsView(frame: rect)
view.p = padding
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = rect.width / 17
let h = rect.height / 17
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let player = "\(item)"
guard ["1","2"].contains(player) else { continue }
if (r + c) % 2 == 0 {
/// Space
let dotView = DotsSquareView(frame: CGRect(x: c * w - padding / 2, y: r * h - padding / 2, width: w, height: h).insetBy(dx: -5, dy: -5))
dotView.backgroundColor = .clear
dotView.playerColor = player == "1" ? colors.player1 : colors.player2
view.addSubview(dotView)
} else {
/// Line
// let (dx,dy) = sp[s]
//
// let width = dx == 0 ? w + 14 : 14
// let height = dy == 0 ? h + 14 : 14
// let x = c * w + padding + w / 2 + (dx * w / 2)
// let y = r * h + padding + w / 2 + (dy * h / 2)
//
// let lineView = DotsLineView(frame: CGRect(x: 0, y: 0, width: width, height: height))
//
// lineView.backgroundColor = .clear
// lineView.center = CGPoint(x: x, y: y)
// lineView.playerColor = side == "1" ? colors.player1 : colors.player2
// lineView.lineColor = colors.foreground
//
// view.addSubview(lineView)
}
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Doubles.swift
================================================
import UIKit
public struct Doubles {
public static var board: Grid { return Grid(4 ✕ (4 ✕ EmptyPiece)) }
public static let playerPieces: [String] = []
public static var staticboard: Grid {
return Grid([
" 2 ".array(),
" ".array(),
" 8".array(),
[EmptyPiece,EmptyPiece,"16","128"],
])
}
public static func validateMove(_ s1: Square, _ s2: Square, _ p1: Piece, _ p2: Piece, _ grid: Grid) throws -> Piece? {
guard p1 != EmptyPiece && (p1 == p2 || p2 == EmptyPiece) else { throw MoveError.invalidmove }
let double = "\((Int(p1) ?? 0) + (Int(p2) ?? 0))"
grid[s2.0][s2.1] = p2 == EmptyPiece ? p1 : double
grid[s1.0][s1.1] = EmptyPiece // remove initial piece
return p1 == p2 && p1 != EmptyPiece ? double : nil
}
public static func random(_ grid: Grid) -> Bool {
let c = Int(arc4random_uniform(4))
let r = Int(arc4random_uniform(4))
guard EmptyPiece == grid[c][r] else { return random(grid) }
grid[c][r] = "2"
return true
}
}
extension String {
var doublesColor: UIColor {
switch self {
case "2": return #colorLiteral(red: 0.721568644, green: 0.8862745166, blue: 0.5921568871, alpha: 1)
case "4": return #colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1)
case "8": return #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
case "16": return #colorLiteral(red: 0.9764705896, green: 0.850980401, blue: 0.5490196347, alpha: 1)
case "32": return #colorLiteral(red: 0.9686274529, green: 0.78039217, blue: 0.3450980484, alpha: 1)
case "64": return #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
case "128": return #colorLiteral(red: 0.9568627477, green: 0.6588235497, blue: 0.5450980663, alpha: 1)
case "256": return #colorLiteral(red: 0.9411764741, green: 0.4980392158, blue: 0.3529411852, alpha: 1)
case "512": return #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)
case "1024": return #colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)
case "2048": return #colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1)
case "4096": return #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
default: return .clear
}
}
}
extension Grid {
public func doubles(_ rect: CGRect) -> UIView {
let view = UIView(frame: rect)
view.backgroundColor = colors.background
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - padding * 2) / 4
let h = (rect.height - padding * 2) / 4
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let piece = "\(item)"
let holder = UIView(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h).insetBy(dx: 2, dy: 2))
holder.backgroundColor = piece == EmptyPiece ? colors.foreground : piece.doublesColor
holder.layer.cornerRadius = 10
holder.layer.masksToBounds = true
let label = UILabel(frame: CGRect(x: 0, y: 0, width: w - 4, height: h - 4))
label.backgroundColor = .clear
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 4 - 5, weight: .heavy)
label.textColor = colors.player1
label.adjustsFontSizeToFitWidth = true
holder.addSubview(label)
view.addSubview(holder)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Four.swift
================================================
import UIKit
public struct Four {
public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }
public static let playerPieces = ["◉","◎"]
public static var staticboard: Grid {
return Grid([
7 ✕ EmptyPiece,
7 ✕ EmptyPiece,
" ◎ ".array(),
" ◉ ".array(),
" ◎◉ ".array(),
" ◎◉◉ ".array()
])
}
public static func validateDrop(_ s1: Square, _ p1: Piece, _ grid: Grid) throws {
guard grid[s1.0 + 1][s1.1] == EmptyPiece else { throw MoveError.invalidmove }
grid[s1.0 + 1][s1.1] = p1
guard grid.onBoard(s1) else { return }
grid[s1.0][s1.1] = EmptyPiece
}
}
extension Grid {
public func four(_ rect: CGRect) -> UIView {
let view = FourView(frame: rect)
let w = (rect.width - padding * 2) / 7
let h = (rect.height - padding * 2) / 7
view.backgroundColor = colors.foreground
view.holeColor = colors.background
view.spotColor = colors.selected
view.p = padding
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
var piece = "\(item)"
let label = UILabel(frame: CGRect(x: c * w + padding, y: r * h + padding + h, width: w, height: h))
label.textColor = player(piece) == 0 ? colors.player1 : colors.player2
if player(piece) == 1 {
if let index = playerPieces[1].array().index(of: piece) { piece = playerPieces[0].array()[index] }
}
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 10, weight: .regular)
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Go.swift
================================================
import UIKit
enum GoError: Error {
case openchain
}
public struct Go {
public static var board: Grid { return Grid(9 ✕ (9 ✕ EmptyPiece)) }
public static let playerPieces = ["●","○"]
public static func checkCapture(_ s1: Square, _ p1: Piece, _ grid: Grid) {
let points = [ (-1,0),(0,1),(1,0),(0,-1) ]
func checkChain(_ s1: Square, _ chain: [Square]) throws -> [Square] {
var chain = chain
var squares = [s1]
for p in points {
let s = (s1.0 + p.0, s1.1 + p.1)
guard !(chain.contains { $0.0 == s.0 && $0.1 == s.1 }) else { continue }
guard grid.onBoard(s) else { continue }
let a1 = grid[s.0,s.1]
guard a1 != p1 else { continue }
guard a1 != EmptyPiece else { throw GoError.openchain }
chain.append(s)
do { squares += try checkChain(s, chain) } catch { throw error }
}
return squares
}
for p in points {
let s = (s1.0 + p.0, s1.1 + p.1)
guard grid.onBoard(s) else { continue }
let a1 = grid[s.0,s.1]
guard a1 != EmptyPiece && a1 != p1 else { continue }
if let squares = try? checkChain(s, [s]) {
for s in squares { grid[s.0,s.1] = EmptyPiece }
}
}
}
public static func validateMove(_ s1: Square, _ p1: Piece, _ grid: Grid, _ player: Int) throws {
guard p1 == EmptyPiece else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = playerPieces[player]
checkCapture(s1, playerPieces[player], grid)
}
}
extension Grid {
public func go(_ rect: CGRect) -> UIView {
let view = GoView(frame: rect)
view.p = padding
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - padding * 2) / 8
let h = (rect.height - padding * 2) / 8
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
var piece = "\(item)"
let label = UILabel(frame: CGRect(x: c * w + padding - w / 2, y: r * h + padding - h / 2, width: w, height: h))
label.textColor = player(piece) == 0 ? colors.player1 : colors.player2
if player(piece) == 1 {
if let index = playerPieces[1].array().index(of: piece) { piece = playerPieces[0].array()[index] }
}
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2, weight: .thin)
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Battleship.swift
================================================
import UIKit
public struct Battleship {
public enum PieceType: String {
case carrier
case battleship
case cruiser
case destoyer
var horizontal: String {
switch self {
case .carrier: return "◀︎◼︎◼︎◼︎▶︎"
case .battleship: return "◀︎◼︎◼︎▶︎"
case .cruiser: return "◀︎◼︎▶︎"
case .destoyer: return "◀︎▶︎"
}
}
var vertical: String {
switch self {
case .carrier: return "▲◼︎◼︎◼︎▼"
case .battleship: return "▲◼︎◼︎▼"
case .cruiser: return "▲◼︎▼"
case .destoyer: return "▲▼"
}
}
}
public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }
public static let playerPieces = ["",""]
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Dominos.swift
================================================
import UIKit
public struct Dominos {
public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }
public static let playerPieces = ["🀰🀱🀲🀳🀴🀵🀶🀷🀸🀹🀺🀻🀼🀽🀾🀿🁀🁁🁂🁃🁄🁅🁆🁇🁈🁉🁊🁋🁌🁍🁎🁏🁐🁑🁒🁓🁔🁕🁖🁗🁘🁙🁚🁛🁜🁝🁞🁟🁠🁡🁢🁣🁤🁥🁦🁧🁨🁩🁪🁫🁬🁭🁮🁯🁰🁱🁲🁳🁴🁵🁶🁷🁸🁹🁺🁻🁼🁽🁾🁿🂀🂁🂂🂃🂄🂅🂆🂇🂈🂉🂊🂋🂌🂍🂎🂏🂐🂑🂒🂓"]
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Majong.swift
================================================
import UIKit
public struct Majong {
public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }
public static let playerPieces = ["🀄︎🀀🀁🀂🀃🀅🀆🀇🀈🀉🀊🀋🀌🀍🀎🀏🀐🀑🀒🀓🀔🀕🀖🀗🀘🀙🀚🀛🀜🀝🀞🀟🀠🀡🀢🀣🀤🀥🀦🀧🀨🀩🀪🀫"]
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Pilare.swift
================================================
import UIKit
public struct Pilare {
public static var board: Grid {
return Grid([
6 ✕ "∙●",
["∙●","∙","∙","∙","∙","∙●"],
["∙●","∙","∙","∙","∙","∙●"],
["∙○","∙","∙","∙","∙","∙○"],
["∙○","∙","∙","∙","∙","∙○"],
6 ✕ "∙○"
])
}
public static let playerPieces = ["●","○"]
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Tetris.swift
================================================
//
// Tetris.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class Tetris: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
================================================
FILE: Gameboards.playground/Sources/Boards/InProgress/Trouble.swift
================================================
//
// Trouble.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class Trouble: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
================================================
FILE: Gameboards.playground/Sources/Boards/Ludo.swift
================================================
import UIKit
public struct Ludo {
public static var board: Grid {
return Grid([
5 ✕ "●",
5 ✕ "●",
"●● ○○".array(),
5 ✕ "○",
5 ✕ "○",
])
}
public static let playerPieces = ["●","○"]
}
================================================
FILE: Gameboards.playground/Sources/Boards/Mancala.swift
================================================
import UIKit
public struct Mancala {
public static var board: Grid {
return Grid([
"333333".array(),
"333333".array(),
"000000".array(),
"000000".array(),
"333333".array(),
"333333".array()
])
}
public static let playerPieces = ["123456789","123456789"]
public static var staticboard: Grid {
return Grid([
"341433".array(),
"345033".array(),
"000000".array(),
"000001".array(),
"333444".array(),
"330404".array()
])
}
}
extension Grid {
public func mancala(_ rect: CGRect) -> UIView {
let view = MancalaView(frame: rect)
let w = (rect.width - padding * 2) / 6
let h = (rect.height - padding * 2) / 6
view.holeColor = colors.foreground
view.backgroundColor = colors.background
view.p = padding
view.layer.cornerRadius = 20
view.layer.masksToBounds = true
for (r,row) in content.enumerated() {
guard r > 3 || r < 2 else { continue }
for (c,item) in row.enumerated() {
let label = MancalaSpotView(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h))
label.stones = Int("\(item)") ?? 0
label.textColor = colors.foreground
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 4 - 10, weight: .heavy)
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Memory.swift
================================================
import UIKit
enum MemoryError: Error {
case badmatch
case nocard
case samecard
}
extension Difficulty {
var memoryDeck: String {
switch self {
case .easy: return "🂡🂭🂮🂱🂽🂾🃁🃍🃎🃑🃝🃞🃟"
case .medium: return "🂡🂫🂬🂭🂮🂱🂻🂼🂽🂾🃁🃋🃌🃍🃎🃑🃛🃜🃝🃞🃟"
case .hard: return "🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂬🂭🂮🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂼🂽🂾🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃌🃍🃎🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃜🃝🃞🃟"
}
}
var memoryDeckPairs: [String] {
return Array(memoryDeck.randomize().prefix(memoryCount.unique))
}
var memoryDeckRandomized: [String] {
return (memoryDeckPairs * memoryCount.pairs).randomize().randomize()
}
var memoryCount: (unique: Int, pairs: Int) {
switch self {
case .easy: return (4,4)
case .medium: return (18,2)
case .hard: return (32,2)
}
}
var memoryBoard: Grid {
switch self {
case .easy: return Grid(4 ✕ (4 ✕ "🂠"))
case .medium: return Grid(6 ✕ (6 ✕ "🂠"))
case .hard: return Grid(8 ✕ (8 ✕ "🂠"))
}
}
}
extension String {
var memoryColor: UIColor {
switch self {
case "🂡","🂢","🂣","🂤","🂥","🂦","🂧","🂨","🂩","🂪","🂫","🂬","🂭","🂮","🃑","🃒","🃓","🃔","🃕","🃖","🃗","🃘","🃙","🃚","🃛","🃜","🃝","🃞": return .darkText
case "🂱","🂲","🂳","🂴","🂵","🂶","🂷","🂸","🂹","🂺","🂻","🂼","🂽","🂾","🃁","🃂","🃃","🃄","🃅","🃆","🃇","🃈","🃉","🃊","🃋","🃌","🃍","🃎": return .systemRed
case "🃟": return .orange
default: return .clear
}
}
}
public struct Memory {
public static let playerPieces = ["🂠"]
static func solution(_ difficulty: Difficulty) -> Grid {
let grid = difficulty.memoryBoard
let deck = difficulty.memoryDeckRandomized
for r in grid.rowRange {
for c in grid.colRange {
grid[c,r] = deck[c+r*4]
}
}
return grid
}
static func puzzle(_ difficulty: Difficulty) -> Grid {
return difficulty.memoryBoard
}
public static func validateSelection(_ s1: Square, _ c1: Card, _ grid: Grid) throws {
guard grid[s1.0,s1.1] != EmptyPiece else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = c1
}
public static func validateMatch(_ s1: Square, _ s2: Square, _ c1: Card, _ c2: Card, _ grid: Grid, _ reset: Bool = false) throws -> Card? {
if reset {
let card = c1 == c2 ? EmptyPiece : "🂠"
grid[s1.0][s1.1] = card
grid[s2.0][s2.1] = card
} else {
guard grid[s1.0,s1.1] != EmptyPiece else { throw MemoryError.nocard }
grid[s1.0,s1.1] = c1
}
guard s1 != s2 else { throw MemoryError.samecard }
guard c1 == c2 else { throw MemoryError.badmatch }
return c1
}
}
extension Grid {
public func memory(_ rect: CGRect) -> UIView {
let view = UIView(frame: rect)
view.backgroundColor = colors.background
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - content.count + 1) / content.count
let h = (rect.height - content.count + 1) / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let piece = "\(item)"
let label = UILabel(frame: CGRect(x: c * w + c, y: r * h + r, width: w, height: h))
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 10, weight: .regular)
label.textColor = player(piece) == 0 ? colors.player1 : piece.memoryColor
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Pegs.swift
================================================
//
// Pegs.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class Pegs: NSObject {
public static var board: Grid {
return Grid([
"!!●●●!!".array(),
"!!●●●!!".array(),
"●●●●●●●".array(),
"●●● ●●●".array(),
"●●●●●●●".array(),
"!!●●●!!".array(),
"!!●●●!!".array()
])
}
public static let playerPieces = ["●"]
public static func validateMove(_ s1: Square, _ s2: Square, _ p1: Piece, _ p2: Piece, _ grid: Grid, _ hint: Bool = false) throws -> Piece? {
let m1 = s2.0 - s1.0
let m2 = s2.1 - s1.1
guard p1 == "●" && p2 == EmptyPiece else { throw MoveError.invalidmove }
guard (abs(m1) == 2 && abs(m2) == 0) || (abs(m1) == 0 && abs(m2) == 2) else { throw MoveError.invalidmove }
let e1 = s1.0 + m1 / 2
let e2 = s1.1 + m2 / 2
let piece = grid[e1,e2]
guard piece == "●" else { throw MoveError.invalidmove }
guard !hint else { return nil }
grid[s2.0,s2.1] = p1
grid[s1.0,s1.1] = EmptyPiece // remove initial piece
grid[e1,e2] = EmptyPiece // remove jumped piece
return piece
}
}
extension Grid {
public func pegs(_ rect: CGRect, highlights: [Square], selected: Square?) -> UIView {
let view = PegsView(frame: rect)
view.backgroundColor = colors.background
view.p = padding
view.color = colors.foreground
view.lineColor = colors.player2
let w = (rect.width - padding * 2) / content.count
let h = (rect.height - padding * 2) / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
guard "\(item)" != "!" else { continue }
let label = HintLabel(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h))
label.text = "\(item)"
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 15, weight: .regular)
label.textColor = colors.player1
label.highlightColor = colors.highlight
if let selected = selected, selected.0 == r && selected.1 == c { label.textColor = colors.selected }
for highlight in highlights { label.highlight = label.highlight ? true : highlight.0 == r && highlight.1 == c }
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Sudoku.swift
================================================
import UIKit
extension Difficulty {
var sudokuRange: CountableClosedRange<Int> {
switch self {
case .easy: return 2...6
case .medium: return 3...5
case .hard: return 4...4
}
}
}
public struct Sudoku {
public static var board: Grid {
let grid = Grid([
"123456789".array(),
"456789123".array(),
"789123456".array(),
"234567891".array(),
"567891234".array(),
"891234567".array(),
"345678912".array(),
"678912345".array(),
"912345678".array()
])
return randomize(grid)
}
public static var staticboard: Grid {
let grid = Grid([
"123456789".array(),
"456789123".array(),
"789123456".array(),
"234567891".array(),
"567891234".array(),
"891234567".array(),
"345678912".array(),
"678912345".array(),
"912345678".array()
])
return Grid([ grid[6], grid[8], grid[7], grid[1], grid[0], grid[2], grid[5], grid[3], grid[4] ])
}
public static let playerPieces = ["123456789"]
public static func validateGuess(_ s1: Square, _ g1: Guess, _ grid: Grid, _ solution: Grid) throws {
guard g1 != EmptyPiece else { throw MoveError.invalidmove }
guard g1 == solution[s1.0,s1.1] else { throw MoveError.incorrectguess }
grid[s1.0,s1.1] = g1
}
static func randomize(_ grid: Grid) -> Grid {
var grid = grid
for _ in 0...2 {
let g1: [[String]] = [grid[0],grid[1],grid[2]].randomize()
let g2: [[String]] = [grid[3],grid[4],grid[5]].randomize()
let g3: [[String]] = [grid[6],grid[7],grid[8]].randomize()
grid = Grid([ g1[0], g1[1], g1[2], g2[0], g2[1], g2[2], g3[0], g3[1], g3[2] ])
grid = flipGrid(grid)
}
return grid
}
static func flipGrid(_ grid: Grid) -> Grid {
let newGrid = Grid(9 ✕ (9 ✕ EmptyPiece))
for r in newGrid.rowRange {
for c in newGrid.colRange {
newGrid[c,r] = grid[r,c]
}
}
return newGrid
}
static func puzzle(_ grid: Grid, difficulty: Difficulty) -> Grid {
let grid = Grid(grid.content)
for r in 0...8 {
var cols = [0,1,2,3,4,5,6,7,8].randomize()
cols.removeSubrange(difficulty.sudokuRange)
for c in cols {
grid[r,c] = EmptyPiece
}
}
return grid
}
static func staticpuzzle(_ grid: Grid) -> Grid {
let grid = Grid(grid.content)
let hide = [
[0,2,3,4,6,7],
[0,1,3,6,7,8],
[1,2,3,5,6,7],
[0,1,2,4,5,8],
[0,1,4,6,7,8],
[2,3,4,5,7,8],
[0,1,2,5,6,7],
[0,3,4,5,6,8],
[1,3,4,6,7,8]
]
for (r,row) in hide.enumerated() {
for c in row {
grid[r,c] = EmptyPiece
}
}
return grid
}
}
extension Grid {
public func sudoku(_ rect: CGRect, highlights: [Square]) -> UIView {
let view = SudokuView(frame: rect)
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = rect.width / content.count
let h = rect.height / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let holder = UIView(frame: CGRect(x: c * w, y: r * h, width: w, height: h))
let label = UILabel(frame: CGRect(x: 0, y: 0, width: w, height: h))
label.text = "\(item)"
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 15, weight: .regular)
label.textColor = colors.foreground
for highlight in highlights {
guard highlight.0 == r && highlight.1 == c else { continue }
label.textColor = colors.highlight
holder.backgroundColor = colors.foreground
}
holder.addSubview(label)
view.addSubview(holder)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/TicTacToe.swift
================================================
import UIKit
public struct TicTacToe {
public static var board: Grid { return Grid(3 ✕ (3 ✕ EmptyPiece)) }
public static let playerPieces = ["○","✕"]
public static func validateMove(_ s1: Square, _ p1: Piece, _ grid: Grid, _ player: Int) throws {
guard p1 == EmptyPiece else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = playerPieces[player] // place my piece in target square
}
}
extension Grid {
public func ttt(_ rect: CGRect) -> UIView {
let view = TicTacToeView(frame: rect)
view.p = padding
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - padding * 2) / content.count
let h = (rect.height - padding * 2) / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let piece = "\(item)"
let label = UILabel(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h))
label.text = piece
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 10, weight: .thin)
label.textColor = player(piece) == 0 ? colors.player1 : colors.player2
view.addSubview(label)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Boards/Words.swift
================================================
import UIKit
public struct Words {
public enum PieceType: String {
static var all: [PieceType] { return [.start,.doubleword,.doubleletter,.tripleword,.tripleletter] }
static var names: [String] { return all.map { $0.rawValue } }
case empty = " "
case start = "★"
case doubleword = "DW"
case tripleword = "TW"
case doubleletter = "DL"
case tripleletter = "TL"
var backgroundColor: UIColor {
switch self {
case .empty: return .clear
case .start: return #colorLiteral(red: 0.4582899487, green: 0.1780638536, blue: 0.4886863426, alpha: 1)
case .doubleletter: return #colorLiteral(red: 0.0121835285, green: 0.524357516, blue: 0.8901960784, alpha: 1)
case .tripleletter: return #colorLiteral(red: 0.1972305775, green: 0.7161869407, blue: 0.3783127069, alpha: 1)
case .doubleword: return #colorLiteral(red: 0.8, green: 0, blue: 0.2666666667, alpha: 1)
case .tripleword: return #colorLiteral(red: 0.968627451, green: 0.5960784314, blue: 0.2666666667, alpha: 1)
}
}
var textColor: UIColor { return .white }
}
public enum Letter: String {
static var all: [Letter] { return [.a,.b,.c,.d,.e,.f,.g,.h,.i,.j,.k,.l,.m,.n,.o,.p,.q,.r,.s,.t,.u,.v,.w,.x,.y,.z,.blank,.none] }
static var bag: [Letter] {
return all.reduce([]) { $0 + Array(repeating: $1, count: $1.count) }.randomize().randomize()
}
case a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
case blank = "_"
case none = " "
var count: Int {
switch self {
case .none: return 0
case .j, .k, .q, .x, .z: return 1
case .blank, .b, .c, .f, .m, .p, .v, .w, .y: return 2
case .g: return 3
case .h, .l, .u: return 4
case .d, .n, .s: return 5
case .r: return 6
case .t: return 7
case .i, .o: return 8
case .a: return 9
case .e: return 13
}
}
var point: Int {
switch self {
case .blank, .none: return 0
case .a, .e, .i, .o, .r, .s, .t: return 1
case .d, .l, .n, .u: return 2
case .g, .h, .y: return 3
case .b, .c, .f, .m, .p, .w: return 4
case .k, .v: return 5
case .x: return 8
case .j, .q, .z: return 10
}
}
}
public static var board: Grid {
let grid = Grid([
[" "," "," ","TW"," "," ","TL"," ","TL"," "," ","TW"," "," "," "],
[" "," ","DL"," "," ","DW"," "," "," ","DW"," "," ","DL"," "," "],
[" ","DL"," "," ","DL"," "," "," "," "," ","DL"," "," ","DL"," "],
["TW"," "," ","TL"," "," "," ","DW"," "," "," ","TL"," "," ","TW"],
[" "," ","DL"," "," "," ","DL"," ","DL"," "," "," ","DL"," "," "],
[" ","DW"," "," "," ","TL"," "," "," ","TL"," "," "," ","DW"," "],
["TL"," "," "," ","DL"," "," "," "," "," ","DL"," "," "," ","TL"],
[" "," "," ","DW"," "," "," ","★"," "," "," ","DW"," "," "," "],
["TL"," "," "," ","DL"," "," "," "," "," ","DL"," "," "," ","TL"],
[" ","DW"," "," "," ","TL"," "," "," ","TL"," "," "," ","DW"," "],
[" "," ","DL"," "," "," ","DL"," ","DL"," "," "," ","DL"," "," "],
["TW"," "," ","TL"," "," "," ","DW"," "," "," ","TL"," "," ","TW"],
[" ","DL"," "," ","DL"," "," "," "," "," ","DL"," "," ","DL"," "],
[" "," ","DL"," "," ","DW"," "," "," ","DW"," "," ","DL"," "," "],
[" "," "," ","TW"," "," ","TL"," ","TL"," "," ","TW"," "," "," "]
])
return grid
}
public static let playerPieces = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ_"]
public static func validate(_ tile: Letter, _ s1: Square, _ grid: Grid) throws {
guard PieceType(rawValue: grid[s1.0,s1.1]) != nil else { throw MoveError.invalidmove }
grid[s1.0,s1.1] = tile.rawValue.uppercased()
}
}
extension Grid {
public func words(_ rect: CGRect) -> UIView {
let view = WordsView(frame: rect)
view.p = padding
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 6
view.layer.masksToBounds = true
let w = (rect.width - padding * 2) / content.count
let h = (rect.height - padding * 2) / content.count
for (r,row) in content.enumerated() {
for (c,item) in row.enumerated() {
let piece = Words.PieceType(rawValue: "\(item)")
let holder = UIView(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h).insetBy(dx: 1, dy: 1))
holder.backgroundColor = piece?.backgroundColor ?? colors.player2
holder.layer.cornerRadius = 4
holder.layer.masksToBounds = true
let label = UILabel(frame: CGRect(x: 0, y: 0, width: w - 2, height: h - 2))
label.text = "\(item)"
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / ("\(item)".count > 1 ? 3 : 2) - 5, weight: .black)
label.textColor = piece?.textColor ?? colors.player1
label.backgroundColor = .clear
holder.addSubview(label)
view.addSubview(holder)
}
}
return view
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Extensions.swift
================================================
import UIKit
public typealias Square = (c: Int, r: Int)
public typealias ChessSquare = (c: String, r: Int)
public typealias Piece = String
public typealias Guess = String
public typealias Card = String
extension String {
public func array() -> [String] {
return map { "\($0)" }
}
public func randomize() -> [String] {
return array().sorted { _,_ in arc4random() % 2 == 0 }
}
}
extension Int {
public func within(_ r: CountableRange<Int>) -> Bool {
return self >= r.lowerBound && self < r.upperBound
}
public func set(_ advanced: Int, _ count: Int) -> [Int] {
var set: [Int] = []
for i in 0..<count { set += [advanced * i + self] }
return set
}
}
extension Array {
public func randomize() -> [Element] {
return sorted { _,_ in arc4random() % 2 == 0 }
}
static func *(lhs: [Element], rhs: Int) -> [Element] {
var multipliedArray = lhs
for _ in 1..<rhs { multipliedArray += lhs }
return multipliedArray
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Grid.swift
================================================
import UIKit
let EmptyPiece: String = " "
public class Grid {
public var content: [[String]]
public var rowRange: CountableRange<Int> { return 0..<content.count }
public var colRange: CountableRange<Int> { return content.count > 0 ? 0..<content[0].count : 0..<0 }
public var padding: CGFloat = 0
public var colors = BoardColors()
public var playerPieces: [Piece] = []
public init(_ content: [[String]]) {
self.content = content
}
public subscript(c: Int, r: Int) -> String {
get { return content[c][r] }
set { content[c][r] = newValue }
}
public subscript(c: Int) -> [String] {
get { return content[c] }
set { content[c] = newValue }
}
public subscript(c: Int) -> String {
get { return content[c / colRange.endIndex][c % colRange.endIndex] }
set { content[c / colRange.endIndex][c % colRange.endIndex] = newValue }
}
public func matrix(_ rect: CGRect) -> UIView {
let view = MatrixView(frame: rect)
view.p = padding
view.backgroundColor = colors.background
view.lineColor = colors.foreground
view.layer.cornerRadius = 10
view.layer.masksToBounds = true
let w = (rect.width - padding * 2) / content.count
let h = (rect.height - padding * 2) / content.count
for (c,col) in content.enumerated() {
for (r,item) in col.enumerated() {
let label = UILabel(frame: CGRect(x: c * w + padding, y: r * h + padding, width: w, height: h))
label.text = "\(item)"
label.textAlignment = .center
label.font = .systemFont(ofSize: (w + h) / 2 - 10, weight: .thin)
view.addSubview(label)
}
}
return view
}
public func onBoard(_ s1: Square, _ s2: Square) -> Bool {
return s1.0.within(rowRange) && s1.1.within(colRange) && s2.0.within(rowRange) && s2.1.within(colRange)
}
public func onBoard(_ s1: Square) -> Bool {
return s1.0.within(rowRange) && s1.1.within(colRange)
}
func player(_ piece: Piece) -> Int {
for (p,player) in playerPieces.enumerated() {
if player.contains(piece) { return p }
}
return -1
}
public func piecesOnBoard() -> [Piece] {
return content.reduce([]) { $0 + $1 }.filter { $0 != EmptyPiece }
}
}
class HintLabel: UILabel {
var highlight: Bool = false { didSet { setNeedsDisplay() } }
var highlightColor: UIColor = .systemRed
override func drawText(in rect: CGRect) {
guard highlight else { return super.drawText(in: rect) }
let c = UIGraphicsGetCurrentContext()
highlightColor.set()
c?.setLineJoin(.round)
c?.setLineWidth(1)
c?.stroke(rect.insetBy(dx: 3, dy: 3))
super.drawText(in: rect)
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Operators.swift
================================================
import UIKit
public func * (lhs: CGFloat, rhs: Int) -> CGFloat {
return lhs * CGFloat(rhs)
}
public func * (lhs: Int, rhs: CGFloat) -> CGFloat {
return CGFloat(lhs) * rhs
}
public func / (lhs: CGFloat, rhs: Int) -> CGFloat {
return lhs / CGFloat(rhs)
}
public func / (lhs: Int, rhs: CGFloat) -> CGFloat {
return CGFloat(lhs) / rhs
}
public func + (lhs: CGFloat, rhs: Int) -> CGFloat {
return lhs + CGFloat(rhs)
}
public func + (lhs: Int, rhs: CGFloat) -> CGFloat {
return CGFloat(lhs) + rhs
}
public func - (lhs: CGFloat, rhs: Int) -> CGFloat {
return lhs - CGFloat(rhs)
}
public func - (lhs: Int, rhs: CGFloat) -> CGFloat {
return CGFloat(lhs) - rhs
}
// MATRIX
infix operator ✕: AdditionPrecedence
public func ✕ (lhs: Int, rhs: (Int) -> String) -> [String] {
var a: [String] = []
for i in 0..<lhs { let r = rhs(i); a.append(r) }
return a
}
public func ✕ (lhs: Int, rhs: (Int) -> [String]) -> [[String]] {
var a: [[String]] = []
for i in 0..<lhs { let r = rhs(i); a.append(r) }
return a
}
public func ✕ (lhs: Int, rhs: String) -> [String] {
return [String](repeating: rhs, count: lhs)
}
public func ✕ (lhs: Int, rhs: [String]) -> [[String]] {
return [[String]](repeating: rhs, count: lhs)
}
infix operator %% : AssignmentPrecedence
public func %% (lhs: String, rhs: String) -> (Int) -> String {
return { $0 % 2 == 0 ? lhs : rhs }
}
public func %% (lhs: [String], rhs: [String]) -> (Int) -> [String] {
return { $0 % 2 == 0 ? lhs : rhs }
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/BackgammonView.swift
================================================
//
// BackgammonView.swift
// Games
//
// Created by Jo Albright on 4/20/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class BackgammonView: UIView {
public var p: CGFloat = 15
public var backgroundColor2: UIColor = .black
public override func draw(_ rect: CGRect) {
let lineColor1 = backgroundColor2.withAlphaComponent(0.3)
let lineColor2 = backgroundColor2.withAlphaComponent(0.7)
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
let vG: CGFloat = 20
let hG: CGFloat = 50
backgroundColor2.set()
context?.addPath(UIBezierPath(roundedRect: rect.insetBy(dx: 15, dy: 15), cornerRadius: 0).cgPath)
context?.fillPath()
backgroundColor?.set()
context?.addRect(CGRect(x: rect.midX - vG / 2, y: 0, width: vG, height: rect.height))
context?.fillPath()
context?.setBlendMode(.multiply)
let w = (rect.width - p * 2 - vG) / 12
let h = (rect.height - p * 2 - hG) / 10
for c in 0..<12 {
let x = c > 5 ? 35 : 15
(c % 2 == 0 ? lineColor1 : lineColor2).set()
context?.move(to: CGPoint(x: w * c + x, y: 15))
context?.addLine(to: CGPoint(x: w * c + x + w, y: 15))
context?.addLine(to: CGPoint(x: w * c + x + w / 2, y: h * 5 + 15))
context?.closePath()
context?.fillPath()
(c % 2 == 1 ? lineColor1 : lineColor2).set()
context?.move(to: CGPoint(x: w * c + x, y: rect.height - 15))
context?.addLine(to: CGPoint(x: w * c + x + w, y: rect.height - 15))
context?.addLine(to: CGPoint(x: w * c + x + w / 2, y: h * 5 + 65))
context?.closePath()
context?.fillPath()
}
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/DotsView.swift
================================================
//
// DotsView.swift
// Games
//
// Created by Jo Albright on 4/22/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class DotsView: UIView {
public var p: CGFloat = 10
public var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(6)
lineColor.set()
let w = (rect.width - p * 2) / 8
let h = (rect.height - p * 2) / 8
for r in 0...8 {
for c in 0...8 {
context?.move(to: CGPoint(x: w * c + p, y: h * r + p))
context?.addLine(to: CGPoint(x: w * c + p, y: h * r + p))
context?.strokePath()
}
}
}
}
class DotsLineView: UIView {
public var playerColor: UIColor = .white
public var lineColor: UIColor = .black
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(1)
lineColor.set()
let h: Bool = rect.width > rect.height
let p: CGFloat = 2
let d: CGFloat = h ? rect.height - p * 2 : rect.width - p * 2
context?.strokeEllipse(in: CGRect(x: p, y: p, width: d, height: d))
context?.strokeEllipse(in: CGRect(x: rect.width - (d + p), y: rect.height - (d + p), width: d, height: d))
let x = h ? d + 7 : d / 2 + p
let y = h ? d / 2 + p : d + 7
context?.setLineWidth(2)
context?.setLineDash(phase: 0, lengths: [0,4])
context?.move(to: CGPoint(x: x, y: y))
context?.addLine(to: CGPoint(x: rect.width - x, y: rect.height - y))
context?.strokePath()
}
}
class DotsSquareView: UIView {
public var playerColor: UIColor = .white
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
playerColor.set()
context?.fillEllipse(in: rect.insetBy(dx: 5, dy: 5))
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/FourView.swift
================================================
//
// FourView.swift
// Games
//
// Created by Jo Albright on 4/21/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class FourView: UIView {
public var p: CGFloat = 15
public var holeColor: UIColor = .white
public var spotColor: UIColor = UIColor(white: 0.90, alpha: 1)
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(2)
holeColor.set()
let w = (rect.width - p * 2) / 7
let h = (rect.height - p * 2) / 7
context?.fill(CGRect(x: 0, y: 0, width: rect.width, height: h + 10))
backgroundColor?.set()
context?.addPath(UIBezierPath(roundedRect: CGRect(x: 0, y: h, width: rect.width, height: 20), cornerRadius: 10).cgPath)
context?.fillPath()
for c in 0..<7 {
holeColor.set()
context?.addPath(UIBezierPath(roundedRect: CGRect(x: w * c + p + 5, y: 10, width: w - 10, height: h), cornerRadius: 10).cgPath)
context?.fillPath()
for r in 0..<6 {
context?.fillEllipse(in: CGRect(x: w * c + p, y: h * r + p + h, width: w, height: h).insetBy(dx: 5, dy: 5))
}
spotColor.set()
context?.strokeEllipse(in: CGRect(x: w * c + p, y: 0, width: w, height: h).insetBy(dx: 10, dy: 10))
context?.fillEllipse(in: CGRect(x: w * c + p, y: 0, width: w, height: h).insetBy(dx: 15, dy: 15))
}
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/GoView.swift
================================================
import UIKit
public class GoView: UIView {
public var p: CGFloat = 20
public var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
lineColor.set()
let w = (rect.width - p * 2) / 8
let h = (rect.height - p * 2) / 8
for r in 0...8 {
for c in 0...8 {
context?.move(to: CGPoint(x: w * c + p, y: p))
context?.addLine(to: CGPoint(x: w * c + p, y: rect.height - p))
context?.move(to: CGPoint(x: p, y: h * r + p))
context?.addLine(to: CGPoint(x: rect.width - p, y: h * r + p))
}
}
context?.strokePath()
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/MancalaView.swift
================================================
//
// MancalaView.swift
// Games
//
// Created by Jo Albright on 4/22/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class MancalaView: UIView {
public var p: CGFloat = 15
public var holeColor: UIColor = .white
public var spotColor: UIColor = UIColor(white: 0.90, alpha: 1)
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(4)
let w = (rect.width - p * 2) / 6
let h = (rect.height - p * 2) / 6
holeColor.set()
for c in 0..<6 {
if c % 2 == 1 {
context?.move(to: CGPoint(x: w * c + p, y: h / 2 + p))
context?.addLine(to: CGPoint(x: w * c + p, y: h / 2 + p))
context?.strokePath()
}
context?.fillEllipse(in: CGRect(x: w * c + p, y: p, width: w, height: h).insetBy(dx: 5, dy: 5))
if c % 2 == 0, c > 0 {
context?.move(to: CGPoint(x: w * c + p, y: h + h / 2 + p))
context?.addLine(to: CGPoint(x: w * c + p, y: h + h / 2 + p))
context?.strokePath()
}
context?.fillEllipse(in: CGRect(x: w * c + p, y: h + p, width: w, height: h).insetBy(dx: 5, dy: 5))
context?.move(to: CGPoint(x: w * c + w / 2 + p, y: h + p))
context?.addLine(to: CGPoint(x: w * c + w / 2 + p, y: h + p))
context?.strokePath()
if c == 0 || c == 5 {
context?.move(to: CGPoint(x: w * c + w / 2 + p, y: h * 2 + p))
context?.addLine(to: CGPoint(x: w * c + w / 2 + p, y: h * 2 + p))
context?.strokePath()
context?.move(to: CGPoint(x: w * c + w / 2 + p, y: rect.height - (h * 2 + p)))
context?.addLine(to: CGPoint(x: w * c + w / 2 + p, y: rect.height - (h * 2 + p)))
context?.strokePath()
}
context?.move(to: CGPoint(x: w * c + w / 2 + p, y: rect.height - (h + p)))
context?.addLine(to: CGPoint(x: w * c + w / 2 + p, y: rect.height - (h + p)))
context?.strokePath()
context?.fillEllipse(in: CGRect(x: w * c + p, y: rect.height - (h * 2 + p), width: w, height: h).insetBy(dx: 5, dy: 5))
if c % 2 == 0, c > 0 {
context?.move(to: CGPoint(x: w * c + p, y: rect.height - (h + h / 2 + p)))
context?.addLine(to: CGPoint(x: w * c + p, y: rect.height - (h + h / 2 + p)))
context?.strokePath()
}
context?.fillEllipse(in: CGRect(x: w * c + p, y: rect.height - (h + p), width: w, height: h).insetBy(dx: 5, dy: 5))
if c % 2 == 1 {
context?.move(to: CGPoint(x: w * c + p, y: rect.height - (h / 2 + p)))
context?.addLine(to: CGPoint(x: w * c + p, y: rect.height - (h / 2 + p)))
context?.strokePath()
}
}
context?.addPath(UIBezierPath(roundedRect: CGRect(x: p, y: h * 2 + p, width: w * 2, height: h * 2).insetBy(dx: 5, dy: 5), cornerRadius: w / 4).cgPath)
context?.addPath(UIBezierPath(roundedRect: CGRect(x: rect.width - (w * 2 + p), y: h * 2 + p, width: w * 2, height: h * 2).insetBy(dx: 5, dy: 5), cornerRadius: w / 4).cgPath)
context?.fillPath()
}
}
class MancalaSpotView: UILabel {
var stoneColor: UIColor = .black
var stones: Int = 0 {
didSet {
setNeedsDisplay()
// text = stones == 0 ? EmptyPiece : "\(stones)"
}
}
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
let d: CGFloat = rect.width / 4
let r: CGFloat = stones > 4 ? d / 2 : (CGFloat(stones) / 4) * (d / 2)
let s: CGFloat = 360 / CGFloat(stones)
var a: CGFloat = 0
stoneColor.withAlphaComponent(0.4).set()
context?.setLineCap(.round)
context?.setLineWidth(d)
context?.setBlendMode(.multiply)
for _ in 0..<stones {
a += CGFloat(arc4random_uniform(30) + UInt32(s))
let radian = a * .pi / 180
let x = r * cos(radian)
let y = r * sin(radian)
let p = CGPoint(x: x + rect.midX, y: y + rect.midY)
context?.move(to: p)
context?.addLine(to: p)
context?.strokePath()
}
super.draw(rect)
}
}
class MancalaHomeView: UIView {
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/MatrixView.swift
================================================
import UIKit
public class MatrixView: UIView {
public var p: CGFloat = 10
var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let c = UIGraphicsGetCurrentContext()
c?.setLineCap(.round)
c?.setLineJoin(.round)
c?.setLineWidth(2)
lineColor.set()
c?.move(to: CGPoint(x: p * 2, y: p))
c?.addLine(to: CGPoint(x: p, y: p))
c?.addLine(to: CGPoint(x: p, y: rect.height - p))
c?.addLine(to: CGPoint(x: p * 2, y: rect.height - p))
c?.move(to: CGPoint(x: rect.width - p * 2, y: p))
c?.addLine(to: CGPoint(x: rect.width - p, y: p))
c?.addLine(to: CGPoint(x: rect.width - p, y: rect.height - p))
c?.addLine(to: CGPoint(x: rect.width - p * 2, y: rect.height - p))
c?.strokePath()
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/PegsView.swift
================================================
//
// PegsView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class PegsView: UIView {
var p: CGFloat = 20
var color: UIColor = .lightGray
var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(p)
backgroundColor?.set()
context?.fill(rect)
let w = (rect.width - p * 2) / 7
let h = (rect.height - p * 2) / 7
color.set()
context?.move(to: CGPoint(x: rect.width / 2, y: p / 2))
context?.addLine(to: CGPoint(x: rect.width - p / 2, y: rect.height / 2))
context?.addLine(to: CGPoint(x: rect.width / 2, y: rect.height - p / 2))
context?.addLine(to: CGPoint(x: p / 2, y: rect.height / 2))
context?.fillPath()
context?.move(to: CGPoint(x: rect.width / 2, y: p / 2))
context?.addLine(to: CGPoint(x: rect.width - p / 2, y: rect.height / 2))
context?.addLine(to: CGPoint(x: rect.width / 2, y: rect.height - p / 2))
context?.addLine(to: CGPoint(x: p / 2, y: rect.height / 2))
context?.closePath()
context?.strokePath()
lineColor.set()
context?.setLineWidth(6)
let skip: [(Int,Int)] = [(0,0),(0,1),(1,0),(1,1),(5,0),(5,1),(6,0),(6,1),(0,5),(1,5),(0,6),(1,6),(5,5),(5,6),(6,5),(6,6)]
for r in 0..<7 {
for c in 0..<7 {
guard !(skip.contains { $0.0 == c && $0.1 == r }) else { continue }
context?.move(to: CGPoint(x: w * c + w / 2 + p, y: h * r + h / 2 + p))
context?.addLine(to: CGPoint(x: w * c + w / 2 + p, y: h * r + h / 2 + p))
context?.strokePath()
}
}
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/SudokuView.swift
================================================
import UIKit
public class SudokuView: UIView {
var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
lineColor.set()
let w9 = rect.width / 9
let h9 = rect.height / 9
for row in 1...8 {
for col in 1...8 {
context?.setLineWidth(col % 3 == 0 ? 3 : 1)
context?.move(to: CGPoint(x: w9 * col, y: 0))
context?.addLine(to: CGPoint(x: w9 * col, y: rect.height))
context?.strokePath()
context?.setLineWidth(row % 3 == 0 ? 3 : 1)
context?.move(to: CGPoint(x: 0, y: h9 * row))
context?.addLine(to: CGPoint(x: rect.width, y: h9 * row))
context?.strokePath()
}
}
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/TicTacToeView.swift
================================================
import UIKit
public class TicTacToeView: UIView {
public var p: CGFloat = 10
public var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(2)
lineColor.set()
let w = (rect.width - p * 2) / 3
let h = (rect.height - p * 2) / 3
context?.move(to: CGPoint(x: w + p, y: p))
context?.addLine(to: CGPoint(x: w + p, y: rect.height - p))
context?.move(to: CGPoint(x: w * 2 + p, y: p))
context?.addLine(to: CGPoint(x: w * 2 + p, y: rect.height - p))
context?.move(to: CGPoint(x: p, y: h + p))
context?.addLine(to: CGPoint(x: rect.width - p, y: h + p))
context?.move(to: CGPoint(x: p, y: h * 2 + p))
context?.addLine(to: CGPoint(x: rect.width - p, y: h * 2 + p))
context?.strokePath()
}
}
================================================
FILE: Gameboards.playground/Sources/Core/Views/WordsView.swift
================================================
//
// WordsView.swift
// Games
//
// Created by Jo Albright on 4/23/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class WordsView: UIView {
public var p: CGFloat = 2
var lineColor: UIColor = .black
public override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineCap(.round)
context?.setLineJoin(.round)
context?.setLineWidth(1)
lineColor.set()
let w = (rect.width - p * 2) / 15
let h = (rect.height - p * 2) / 15
for r in 0..<15 {
for c in 0..<15 {
context?.addPath(UIBezierPath(roundedRect: CGRect(x: w * c + p, y: h * r + p, width: w, height: h).insetBy(dx: 1, dy: 1), cornerRadius: 4).cgPath)
context?.fillPath()
}
}
}
}
class TileView: UIView {
var color: UIColor = .lightGray { didSet { setNeedsDisplay() } }
var selectedColor: UIColor = .lightGray
var letterLabel: UILabel!
var valueLabel: UILabel!
var tile: Words.Letter = .none {
didSet {
letterLabel?.removeFromSuperview()
valueLabel?.removeFromSuperview()
guard tile != .none else { return }
letterLabel = UILabel()
letterLabel.text = tile == .blank ? EmptyPiece : tile.rawValue.uppercased()
letterLabel.textAlignment = .center
letterLabel.font = .systemFont(ofSize: 18, weight: .heavy)
addSubview(letterLabel)
valueLabel = UILabel()
valueLabel.text = tile.point == 0 ? EmptyPiece : "\(tile.point)"
valueLabel.textAlignment = .right
valueLabel.font = .systemFont(ofSize: 10, weight: .heavy)
addSubview(valueLabel)
}
}
var selected: (Words.Letter) -> Void = { _ in }
override func draw(_ rect: CGRect) {
super.draw(rect)
letterLabel?.frame = rect
valueLabel?.frame = CGRect(x: 0, y: 4, width: frame.width - 4, height: 10)
let context = UIGraphicsGetCurrentContext()
context?.clear(rect)
guard tile != .none else { return }
color.set()
context?.addPath(UIBezierPath(roundedRect: rect.insetBy(dx: 1, dy: 1), cornerRadius: 6).cgPath)
context?.fillPath()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard tile != .none else { return }
selected(tile)
color = selectedColor
}
}
================================================
FILE: Gameboards.playground/Sources/Gameboard.swift
================================================
import UIKit
enum Difficulty {
case easy, medium, hard
var name: String {
switch self {
case .easy: return "Easy"
case .medium: return "Medium"
case .hard: return "Hard"
}
}
init(_ i: Int) {
switch i {
case 1: self = .medium
case 2: self = .hard
default: self = .easy
}
}
}
public struct Gameboard {
public enum BoardType: String {
case backgammon, bombsweeper, checkers, chess, dots, doubles, four, go, mancala, memory, pegs, sudoku, tictactoe, words
static var playable: [BoardType] = [ .backgammon, .bombsweeper, .checkers, .chess, .dots, .doubles, .four, .go, .memory, .pegs, .sudoku, .tictactoe, .words ]
public var name: String {
switch self {
case .backgammon: return "Backgammon"
case .bombsweeper: return "Bombsweeper"
case .checkers: return "Checkers"
case .chess: return "Chess"
case .dots: return "Dots"
case .doubles: return "Doubles"
case .four: return "Four"
case .go: return "Go"
case .mancala: return "Mancala"
case .memory: return "Memory"
case .pegs: return "Pegs"
case .sudoku: return "Sudoku"
case .tictactoe: return "Tic Tac Toe"
case .words: return "Words"
}
}
public var emblem: String {
switch self {
case .backgammon: return "⚄"
case .bombsweeper: return "⚑"
case .checkers: return "●"
case .chess: return "♞"
case .dots: return "⦿"
case .doubles: return "⚭"
case .four: return "◉"
case .go: return "●"
case .mancala: return "✾"
case .memory: return "🂠"
case .pegs: return "✜"
case .sudoku: return "9"
case .tictactoe: return "⌗"
case .words: return "☐"
}
}
var controller: UINavigationController? {
guard let vc = UIStoryboard(name: name.replacingOccurrences(of: " ", with: ""), bundle: nil).instantiateInitialViewController() as? BoardViewController else { return nil }
return UINavigationController(rootViewController: vc)
}
}
public var padding: CGFloat = 0 { didSet { grid.padding = padding } }
public var colors = BoardColors() { didSet { grid.colors = colors } }
var _type: BoardType
var playerCount: Int = 2
var playerTurn: Int = 0 { didSet { playerChange?(playerTurn + 1) } }
var playerPieces: [Piece] = [] {
didSet {
grid.playerPieces = playerPieces
playerCount = playerPieces.count
}
}
var grid: Grid = Grid(1 ✕ (1 ✕ EmptyPiece))
var solution: Grid = Grid(1 ✕ (1 ✕ EmptyPiece))
var gridSize: Int { return grid.content.count }
var totalSpaces: Int { return grid.content.count == 0 ? 0 : grid.content.count * grid.content[0].count }
var difficulty: Difficulty = .easy { didSet { reset() } }
var _size: Int?
public var playerChange: ((Int) -> Void)?
public var showAlert: ((String, String) -> Void)?
public init(_ type: BoardType) {
_type = type
reset()
}
public init(_ type: BoardType, testing: Bool) {
_type = type
reset(testing)
}
public init(_ type: BoardType, size: Int) {
_type = type
_size = size
reset()
}
mutating func changePlayer() {
playerTurn = playerTurn < playerCount - 1 ? playerTurn + 1 : 0
}
public mutating func showAvailable(_ s1: Square) {
highlights = []
switch _type {
case .chess, .checkers, .pegs:
selected = nil
for r in grid.rowRange {
for c in grid.colRange {
guard let _ = try? validateMove(s1, (r,c), true) else { continue }
selected = s1
highlights.append((r,c))
}
}
default: break
}
}
public mutating func showAvailable(_ s1: ChessSquare) {
let cols: [String] = "abcdefgh".map { "\($0)" }
guard let c1 = cols.firstIndex(of: s1.0) else { return }
let r1 = 8 - s1.1
showAvailable((r1,c1))
}
public mutating func drop(pieceAt s1: Square) throws { try validateDrop(s1) }
public mutating func place(tile t1: Words.Letter, at s1: Square) throws { try validate(t1, s1) }
public mutating func guess(toSquare s1: Square) throws { try validateGuess(s1) }
public mutating func guess(toSquare s1: Square, withGuess g1: Guess) throws { try validateGuess(s1, g1) }
public mutating func mark(toSquare s1: Square) throws { try validateMark(s1) }
public mutating func move(toSquare s1: Square) throws {
try validateMove(s1)
changePlayer()
}
public mutating func move(pieceAt s1: Square, toSquare s2: Square) throws -> Piece? {
let piece = try validateMove(s1,s2)
changePlayer()
return piece
}
public mutating func move(pieceAt s1: ChessSquare, toSquare s2: ChessSquare) throws -> Piece? {
let cols = "abcdefgh".array()
guard let c1 = cols.firstIndex(of: s1.0), let c2 = cols.firstIndex(of: s2.0) else { return nil }
let r1 = 8 - s1.1, r2 = 8 - s2.1
let piece = try validateMove((r1,c1), (r2,c2))
changePlayer()
return piece
}
public mutating func select(cardAt s1: Square) throws { return try validateSelection(s1) }
public mutating func match(cardAt s1: Square, withCard s2: Square, reset: Bool = false) throws -> Card? { return try validateMatch(s1, s2, reset) }
public mutating func reset(_ testing: Bool = false) {
highlights = []
selected = nil
switch _type {
case .backgammon:
grid = Backgammon.board
playerPieces = Backgammon.playerPieces
case .bombsweeper:
solution = Bombsweeper.board
grid = Bombsweeper.field
playerPieces = Bombsweeper.playerPieces
guard testing else { break }
solution = Bombsweeper.staticboard
playerPieces = Bombsweeper.playerPieces
case .checkers:
grid = Checkers.board
playerPieces = Checkers.playerPieces
case .chess:
grid = Chess.board
playerPieces = Chess.playerPieces
case .dots:
grid = Dots.board
playerPieces = Dots.playerPieces
case .doubles:
grid = Doubles.board
playerPieces = Doubles.playerPieces
let _ = Doubles.random(grid)
let _ = Doubles.random(grid)
guard testing else { break }
grid = Doubles.staticboard
playerPieces = Doubles.playerPieces
case .four:
grid = Four.board
playerPieces = Four.playerPieces
guard testing else { break }
grid = Four.staticboard
playerPieces = Four.playerPieces
case .go:
grid = Go.board
playerPieces = Go.playerPieces
playerTurn = 0
case .mancala:
grid = Mancala.board
playerPieces = Mancala.playerPieces
guard testing else { break }
grid = Mancala.staticboard
playerPieces = Mancala.playerPieces
case .memory:
solution = Memory.solution(difficulty)
grid = Memory.puzzle(difficulty)
playerPieces = Memory.playerPieces
case .pegs:
grid = Pegs.board
playerPieces = Pegs.playerPieces
case .sudoku:
solution = Sudoku.board
grid = Sudoku.puzzle(solution, difficulty: difficulty)
playerPieces = Sudoku.playerPieces
guard testing else { break }
solution = Sudoku.staticboard
grid = Sudoku.staticpuzzle(solution)
playerPieces = Sudoku.playerPieces
case .tictactoe:
grid = TicTacToe.board
playerPieces = TicTacToe.playerPieces
case .words:
grid = Words.board
playerPieces = Words.playerPieces
}
}
public var highlights: [Square] = []
public var selected: Square?
public func visualize(_ rect: CGRect = CGRect(x: 0, y: 0, width: 200, height: 200)) -> UIView {
switch _type {
case .backgammon: return grid.backgammon(rect)
case .bombsweeper: return grid.bomb(rect)
case .checkers, .chess: return grid.checker(rect, highlights: highlights, selected: selected)
case .four: return grid.four(rect)
case .dots: return grid.dots(rect)
case .doubles: return grid.doubles(rect)
case .go: return grid.go(rect)
case .mancala: return grid.mancala(rect)
case .memory: return grid.memory(rect)
case .pegs: return grid.pegs(rect, highlights: highlights, selected: selected)
case .sudoku: return grid.sudoku(rect, highlights: highlights)
case .tictactoe: return grid.ttt(rect)
case .words: return grid.words(rect)
}
}
}
public struct BoardColors {
public var background: UIColor = .white
public var foreground: UIColor = .black
public var player1: UIColor = .systemRed
public var player2: UIColor = .systemBlue
public var highlight: UIColor = .systemGreen
public var selected: UIColor = .systemGreen
public init() { }
}
================================================
FILE: Gameboards.playground/Sources/Validation.swift
================================================
import UIKit
public enum MoveError: Error {
/// Good try. Need a hint?
case incorrectguess
/// Seriously??? There is no reason to go off the board.
case outofbounds
/// Piece cannot move to that square
case invalidmove
/// Cannot take out your own piece
case friendlyfire
/// Another piece is in the way
case blockedmove
/// Piece is not of the current player
case notyourturn
/// Ummm... I think you may be lost
case noplayer
/// What type of game are you playing???
case incorrectpiece
/// Validation is unfinished... not letting you cheat.
case validationfailed
}
public enum GameStatus: Error {
/// Ouch. Why don't you try again?
case gameover
/// You win! Don't let it go to your head.
case winner
/// This is awkward.
case stalemate
}
public enum FunctionalityError: Error {
/// Can't do this... maybe a future feature if you bug me enough.
case unavailable
}
extension Gameboard {
func validateNotFriendlyFire(_ p1: Piece, _ p2: Piece) throws -> Bool {
var _player1: Int?
var _player2: Int?
for (p,pieces) in playerPieces.enumerated() {
if pieces.contains(p1) { _player1 = p }
if pieces.contains(p2) { _player2 = p }
}
guard let player1 = _player1 else { throw MoveError.noplayer }
if let player2 = _player2 {
guard player1 != player2 else { throw MoveError.friendlyfire }
}
return true
}
func validatePlayer(_ piece: Piece) -> Bool {
guard playerPieces.count > 0 else { return true }
return playerPieces[playerTurn].contains(piece)
}
// moves, guesses, etc
mutating func validate(_ t1: Words.Letter, _ s1: Square) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
switch _type {
case .words: try Words.validate(t1, s1, grid)
default: throw MoveError.incorrectpiece
}
}
mutating func validateGuess(_ s1: Square) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
switch _type {
case .bombsweeper: try Bombsweeper.validateGuess(s1, grid, solution)
default: throw MoveError.incorrectpiece
}
}
mutating func validateGuess(_ s1: Square, _ g1: Guess) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
switch _type {
case .sudoku: try Sudoku.validateGuess(s1, g1, grid, solution)
default: throw MoveError.incorrectpiece
}
highlights.append(s1)
}
mutating func validateSelection(_ s1: Square) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
let c1 = solution[s1.0,s1.1]
switch _type {
case .memory: return try Memory.validateSelection(s1, c1, grid)
default: throw MoveError.incorrectpiece
}
}
mutating func validateMatch(_ s1: Square, _ s2: Square, _ reset: Bool = false) throws -> Card? {
guard grid.onBoard(s1, s2) else { throw MoveError.outofbounds }
let c1 = solution[s1.0,s1.1]
let c2 = solution[s2.0,s2.1]
switch _type {
case .memory: return try Memory.validateMatch(s1, s2, c1, c2, grid, reset)
default: throw MoveError.incorrectpiece
}
}
mutating func validateDrop(_ s1: Square) throws {
guard grid.onBoard((s1.0 + 1,s1.1)) else { throw MoveError.outofbounds }
var p1 = playerPieces[playerTurn]
if grid.onBoard(s1) { p1 = grid[s1.0][s1.1] }
if s1.0 == 0 { changePlayer() }
switch _type {
case .four: try Four.validateDrop(s1, p1, grid)
default: throw MoveError.incorrectpiece
}
}
mutating func validateMark(_ s1: Square) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
switch _type {
case .bombsweeper: try Bombsweeper.validateMark(s1, grid, solution)
default: throw MoveError.incorrectpiece
}
}
mutating func validateMove(_ s1: Square) throws {
guard grid.onBoard(s1) else { throw MoveError.outofbounds }
let p1 = grid[s1.0,s1.1]
switch _type {
case .go: try Go.validateMove(s1, p1, grid, playerTurn)
case .tictactoe: try TicTacToe.validateMove(s1, p1, grid, playerTurn)
case .dots: try Dots.validateMove(s1, p1, grid, playerTurn)
default: throw MoveError.incorrectpiece
}
}
mutating func validateMove(_ s1: Square, _ s2: Square, _ hint: Bool = false) throws -> Piece? {
guard grid.onBoard(s1, s2) else { throw MoveError.outofbounds }
let p1 = grid[s1.0,s1.1]
let p2 = grid[s2.0,s2.1]
guard validatePlayer(p1) else { throw MoveError.notyourturn }
if playerCount > 1 { _ = try validateNotFriendlyFire(p1, p2) }
switch _type {
case .checkers: return try Checkers.validateMove(s1, s2, p1, p2, grid, hint)
case .chess: return try Chess.validateMove(s1, s2, p1, p2, grid, hint)
case .doubles: return try Doubles.validateMove(s1, s2, p1, p2, grid)
case .pegs: return try Pegs.validateMove(s1, s2, p1, p2, grid, hint)
default: throw MoveError.incorrectpiece
}
}
}
================================================
FILE: Gameboards.playground/contents.xcplayground
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='6.0' target-platform='ios'>
<pages>
<page name='Checkers'/>
<page name='Chess'/>
<page name='Go'/>
<page name='Mancala'/>
<page name='Minesweeper'/>
<page name='Sudoku'/>
<page name='TicTacToe'/>
</pages>
</playground>
================================================
FILE: Games/AppDelegate.swift
================================================
//
// AppDelegate.swift
// Games
//
// Created by Jo Albright on 2/3/16.
// Copyright © 2016 Jo Albright. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
}
================================================
FILE: Games/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "20x20",
"idiom": "iphone",
"filename" : "icon-20@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom": "iphone",
"filename" : "icon-20@3x.png",
"scale": "3x"
},
{
"size" : "20x20",
"idiom": "ipad",
"filename" : "icon-20.png",
"scale": "1x"
},
{
"size" : "20x20",
"idiom": "ipad",
"filename" : "icon-20@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-60@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "icon-1024.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Games/Assets.xcassets/Colors/Accent.colorset/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0xCC",
"alpha" : "1.000",
"blue" : "0xCC",
"green" : "0xCC"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0x55",
"alpha" : "1.000",
"blue" : "0x55",
"green" : "0x55"
}
}
}
]
}
================================================
FILE: Games/Assets.xcassets/Colors/Background.colorset/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0xEE",
"alpha" : "1.000",
"blue" : "0xEE",
"green" : "0xEE"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0x33",
"alpha" : "1.000",
"blue" : "0x33",
"green" : "0x33"
}
}
}
]
}
================================================
FILE: Games/Assets.xcassets/Colors/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Games/Assets.xcassets/Colors/Offest.colorset/Contents.json
================================================
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xAA",
"green" : "0xAA",
"red" : "0xAA"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x77",
"green" : "0x77",
"red" : "0x77"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: Games/Assets.xcassets/Colors/Text.colorset/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0x55",
"alpha" : "1.000",
"blue" : "0x55",
"green" : "0x55"
}
}
},
{
"idiom" : "universal",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0xCC",
"alpha" : "1.000",
"blue" : "0xCC",
"green" : "0xCC"
}
}
}
]
}
================================================
FILE: Games/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Games/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
================================================
FILE: Games/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="juB-no-UMs">
<device id="retina4_7" orientation="portrait" appearance="dark"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Games-->
<scene sceneID="YGs-fQ-K8c">
<objects>
<viewController automaticallyAdjustsScrollViewInsets="NO" id="46n-er-ZX8" customClass="MainViewController" customModule="Games" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="xsY-Ns-WVS"/>
<viewControllerLayoutGuide type="bottom" id="v6Y-kV-MId"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="NPR-U0-s2j">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView autoresizesSubviews="NO" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="60" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="uDv-h5-uCf">
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
<color key="backgroundColor" name="Background"/>
<color key="separatorColor" name="Accent"/>
<inset key="separatorInset" minX="50" minY="0.0" maxX="0.0" maxY="0.0"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="GameCell" id="YsV-KJ-ifM" customClass="GameCell" customModule="Games" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="YsV-KJ-ifM" id="oFF-8F-Wd1">
<rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chess" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cpK-ws-RF2">
<rect key="frame" x="50" y="19.5" width="305" height="21.5"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="18"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="251" text="♞" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dHJ-gO-ycq">
<rect key="frame" x="0.0" y="14.5" width="50" height="29"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="fqK-EB-O8W"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="cpK-ws-RF2" secondAttribute="trailing" constant="20" id="BbH-Rf-PJD"/>
<constraint firstItem="cpK-ws-RF2" firstAttribute="leading" secondItem="dHJ-gO-ycq" secondAttribute="trailing" id="PI0-1s-ONd"/>
<constraint firstItem="cpK-ws-RF2" firstAttribute="centerY" secondItem="oFF-8F-Wd1" secondAttribute="centerY" id="Uot-Ac-KrT"/>
<constraint firstItem="dHJ-gO-ycq" firstAttribute="leading" secondItem="oFF-8F-Wd1" secondAttribute="leading" id="px8-JB-Pb0"/>
<constraint firstItem="dHJ-gO-ycq" firstAttribute="centerY" secondItem="oFF-8F-Wd1" secondAttribute="centerY" constant="-1" id="wFQ-Cw-23H"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" name="Background"/>
<connections>
<outlet property="emblem" destination="dHJ-gO-ycq" id="WZl-wf-e9W"/>
<outlet property="name" destination="cpK-ws-RF2" id="scf-qm-l6z"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="46n-er-ZX8" id="dSw-xN-Cm0"/>
<outlet property="delegate" destination="46n-er-ZX8" id="bCi-7k-DJ1"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" name="Background"/>
<constraints>
<constraint firstItem="uDv-h5-uCf" firstAttribute="leading" secondItem="NPR-U0-s2j" secondAttribute="leading" id="33z-hv-0Ed"/>
<constraint firstAttribute="bottom" secondItem="uDv-h5-uCf" secondAttribute="bottom" id="Agx-bO-Dxe"/>
<constraint firstItem="uDv-h5-uCf" firstAttribute="top" secondItem="xsY-Ns-WVS" secondAttribute="bottom" id="ZMH-40-2EG"/>
<constraint firstAttribute="trailing" secondItem="uDv-h5-uCf" secondAttribute="trailing" id="zei-um-rHR"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Games" id="vvu-dp-mjV"/>
<connections>
<outlet property="tableView" destination="uDv-h5-uCf" id="7xT-jy-dbU"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYr-Ge-4kb" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1938.4000000000001" y="-216.34182908545728"/>
</scene>
<!--Split View Controller-->
<scene sceneID="nAC-Z0-sX5">
<objects>
<splitViewController id="juB-no-UMs" sceneMemberID="viewController">
<connections>
<segue destination="Shv-Tj-LcY" kind="relationship" relationship="masterViewController" id="wCZ-YH-izo"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aQN-4X-cDc" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-3487" y="-216"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="iwJ-jH-Atn">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Shv-Tj-LcY" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="yx3-5Q-5Mk">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" name="Background"/>
<color key="tintColor" name="Text"/>
<color key="barTintColor" name="Background"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" name="Text"/>
</textAttributes>
<textAttributes key="largeTitleTextAttributes">
<color key="textColor" name="Text"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="46n-er-ZX8" kind="relationship" relationship="rootViewController" id="CuE-R3-QbA"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="cPC-MF-oNW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2713" y="-215"/>
</scene>
</scenes>
<resources>
<namedColor name="Accent">
<color red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Background">
<color red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Text">
<color red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Text">
<color red="0.93333333333333335" green="0.93333333333333335" blue="0.93333333333333335" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>
================================================
FILE: Games/BoardController/BoardViewController.swift
================================================
//
// ViewController.swift
// Games
//
// Created by Jo Albright on 2/3/16.
// Copyright © 2016 Jo Albright. All rights reserved.
//
import UIKit
enum Direction: UInt {
case right = 1
case left = 2
case down = 8
case up = 4
var name: String {
switch self {
case .down: return "Down"
case .up: return "Up"
case .left: return "Left"
case .right: return "Right"
}
}
}
class BoardViewController: UIViewController {
@IBOutlet weak var boardView: BoardView!
@IBOutlet weak var playerLabel: UILabel!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
boardView?.board?.playerChange = { [weak self] player in self?.playerLabel?.text = "Player \(player)" }
boardView?.board?.showAlert = { [weak self] title, message in
let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
let resetAction = UIAlertAction(title: "Reset", style: .default) { [weak self] _ in
self?.boardView?.board?.reset()
self?.boardView?.updateBoard()
}
alertVC.addAction(resetAction)
// present VC
self?.present(alertVC, animated: true)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
guard let square = boardView?.coordinate(touch) else { return }
boardView?.selectSquare(square)
}
@IBAction func swipe(_ sender: UISwipeGestureRecognizer) {
guard let direction = Direction(rawValue: sender.direction.rawValue) else { return }
boardView?.swipe(direction)
}
// @IBAction func chooseDifficulty(sender: UISegmentedControl) {
//
// boardView?.board?.difficulty = Difficulty(sender.selectedSegmentIndex)
// boardView?.updateBoard()
//
// }
@IBAction func resetBoard(sender: Any) {
boardView?.board?.reset()
boardView?.updateBoard()
}
}
@IBDesignable class GradientView: UIView {
@IBInspectable var startColor: UIColor = .white
@IBInspectable var endColor: UIColor = .black
override func draw(_ rect: CGRect) {
let startPoint = CGPoint(x: 0, y: 0)
let endPoint = CGPoint(x: 1, y: 1)
let context = UIGraphicsGetCurrentContext()
let colors: CFArray = [startColor.cgColor,endColor.cgColor] as CFArray
guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors, locations: [0, 1]) else { return }
let s = CGPoint(x: frame.width * startPoint.x, y: frame.height * startPoint.y)
let e = CGPoint(x: frame.width * endPoint.x, y: frame.height * endPoint.y)
context?.drawLinearGradient(gradient, start: s, end: e, options: .drawsAfterEndLocation)
}
}
@IBDesignable class BoardView : UIView {
var board: Gameboard!
var boardView: UIView?
@IBInspectable var padding: CGFloat = 0
@IBInspectable var bgColor: UIColor = .white
@IBInspectable var fgColor: UIColor = .black
@IBInspectable var player1Color: UIColor = .systemRed
@IBInspectable var player2Color: UIColor = .systemBlue
@IBInspectable var selectedColor: UIColor = .white
@IBInspectable var highlightColor: UIColor = .white
override func prepareForInterfaceBuilder() { updateBoard() }
override func didMoveToWindow() { updateBoard() }
override func layoutSubviews() { updateBoard() }
func updateBoard() {
board?.padding = padding
board?.colors.background = bgColor
board?.colors.foreground = fgColor
board?.colors.player1 = player1Color
board?.colors.player2 = player2Color
board?.colors.selected = selectedColor
board?.colors.highlight = highlightColor
boardView?.removeFromSuperview()
boardView = board?.visualize(bounds)
guard let boardView = boardView else { return }
addSubview(boardView)
}
func coordinate(_ touch: UITouch) -> Square? {
guard let board = board else { return nil }
let w = (frame.width - board.padding * 2) / board.gridSize
let h = (frame.height - board.padding * 2) / board.gridSize
let loc = touch.location(in: self)
let c = Int((loc.x - board.padding) / w)
let r = Int((loc.y - board.padding) / h)
return (r,c)
}
func selectSquare(_ square: Square) { }
func swipe(_ direction: Direction) { }
func checkDone() { }
}
================================================
FILE: Games/BoardController/BoardViews/BackgammonBoardView.swift
================================================
//
// BackgammonBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class BackgammonBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.backgammon)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.backgammon)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
// do {
//
// try board.move(toSquare: square)
//
// } catch {
//
// print(error)
//
// }
updateBoard()
}
override func coordinate(_ touch: UITouch) -> Square {
let p = 30
let w = (frame.width - p * 2) / (board.gridSize - 1)
let h = (frame.height - p * 2) / (board.gridSize - 1)
let loc = touch.location(in: self)
let c = Int((loc.x - (w / 2)) / w)
let r = Int((loc.y - (w / 2)) / h)
return (r,c)
}
}
================================================
FILE: Games/BoardController/BoardViews/BombsweeperBoardView.swift
================================================
//
// BombsweeperBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class BombsweeperBoardView : BoardView {
var bombsweeperGuess: Bool = true
override func prepareForInterfaceBuilder() {
board = Gameboard(.bombsweeper, testing: true)
_ = try? board.guess(toSquare: (4,4))
_ = try? board.mark(toSquare: (7,4))
_ = try? board.guess(toSquare: (9,0))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.bombsweeper)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
do {
if bombsweeperGuess {
try board.guess(toSquare: square)
} else {
try board.mark(toSquare: square)
}
} catch {
print(error)
}
updateBoard()
checkDone()
}
override func checkDone() {
guard let board = board else { return }
let noMoves = !(board.grid.content.reduce([]) { $0 + $1 }.contains("•"))
let boom = (board.grid.content.reduce([]) { $0 + $1 }.contains("✘"))
if boom {
board.showAlert?("Game Over", "You stepped on a mine.")
} else if noMoves {
board.showAlert?("Game Over", "You flagged all mines.")
}
}
}
extension BoardViewController {
@IBAction func chooseBombsweeperMark(sender: UISegmentedControl) {
(boardView as? BombsweeperBoardView)?.bombsweeperGuess = sender.selectedSegmentIndex == 0
}
}
================================================
FILE: Games/BoardController/BoardViews/CheckersBoardView.swift
================================================
//
// CheckersBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class CheckersBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.checkers)
board.showAvailable((2,3))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.checkers)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
if let selected = board.selected {
do {
_ = try board.move(pieceAt: selected, toSquare: square)
board.selected = nil
board.highlights = []
} catch {
print(error)
board.showAvailable(square)
}
} else {
board.showAvailable(square)
}
updateBoard()
checkDone()
}
override func checkDone() {
if checkLost(player: 0) {
board?.showAlert?("Game Over", "Player 2 Wins")
} else if checkLost(player: 1) {
board?.showAlert?("Game Over", "Player 1 Wins")
}
}
private func checkLost(player: Int) -> Bool {
return board.grid.piecesOnBoard().filter({ board.playerPieces[player].contains($0) }).isEmpty
}
}
================================================
FILE: Games/BoardController/BoardViews/ChessBoardView.swift
================================================
//
// ChessBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class ChessBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.chess)
board.showAvailable(C7)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.chess)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
if let selected = board.selected {
do {
_ = try board.move(pieceAt: selected, toSquare: square)
board.selected = nil
board.highlights = []
} catch {
print(error)
board.showAvailable(square)
}
} else {
board.showAvailable(square)
}
updateBoard()
}
override func checkDone() {
}
}
================================================
FILE: Games/BoardController/BoardViews/DotsBoardView.swift
================================================
//
// DotsBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class DotsBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.dots, testing: true)
_ = try? board.move(toSquare: (3,6))
_ = try? board.move(toSquare: (2,5))
_ = try? board.move(toSquare: (2,7))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.dots, testing: true)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
do {
try board.move(toSquare: square)
} catch {
print(error)
}
updateBoard()
}
}
================================================
FILE: Games/BoardController/BoardViews/DoublesBoardView.swift
================================================
//
// DoublesBoardView.swift
// Games
//
// Created by Jo Albright on 4/27/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class DoublesBoardView: BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.doubles, testing: true)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.doubles)
super.awakeFromNib()
}
var initialgrid: [[String]] = []
override func swipe(_ direction: Direction) {
initialgrid = board.grid.content
swipe(direction, 0)
}
func swipe(_ direction: Direction, _ loop: Int, _ changed: Bool = false) {
var moved: Bool = changed
switch direction {
case .left:
for r in board.grid.colRange {
for c in board.grid.rowRange {
do {
_ = try board.move(pieceAt: (c,r), toSquare: (c,r-1))
moved = true
} catch {
print(error)
}
}
}
case .right:
for r in board.grid.colRange {
let row = board.grid.rowRange.upperBound - 1 - r
print(r,row)
for c in board.grid.colRange {
do {
_ = try board.move(pieceAt: (c,row), toSquare: (c,row+1))
moved = true
} catch {
print(error)
}
}
}
case .up:
for c in board.grid.colRange {
for r in board.grid.rowRange {
do {
_ = try board.move(pieceAt: (c,r), toSquare: (c-1,r))
moved = true
} catch {
print(error)
}
}
}
case .down:
for c in board.grid.colRange {
let col = board.grid.colRange.upperBound - 1 - c
print(c,col)
for r in board.grid.rowRange {
do {
_ = try board.move(pieceAt: (col,r), toSquare: (col+1,r))
moved = true
} catch {
print(error)
}
}
}
}
updateBoard()
guard loop == 3 else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) {
self.swipe(direction, loop + 1, moved)
}
return
}
guard moved else { return }
let _ = Doubles.random(board.grid)
updateBoard()
}
}
================================================
FILE: Games/BoardController/BoardViews/FourBoardView.swift
================================================
//
// FourBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class FourBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.four, testing: true)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.four)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
do {
try board.drop(pieceAt: square)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.selectSquare((square.0 + 1,square.1))
}
} catch MoveError.invalidmove {
checkDone()
} catch MoveError.outofbounds {
checkDone()
} catch {
print(error)
}
updateBoard()
}
override func coordinate(_ touch: UITouch) -> Square {
let w = (frame.width - board.padding * 2) / 7
let loc = touch.location(in: self)
let c = Int((loc.x - board.padding) / w)
return (-1,c)
}
lazy var combinations: [[Int]] = {
var combinations: [[Int]] = []
// Side to Side (+1)
for i in [1,2,3,4,8,9,10,11,15,16,17,18,22,23,24,25,29,30,31,32,36,37,38,39] {
combinations += [i.set(1, 4)]
}
// Up & Down (+7)
for i in [1,8,15,2,9,16,3,10,17,4,11,18,5,12,19,6,13,20,7,14,21] {
combinations += [i.set(7, 4)]
}
// Diagnol from Left (+8)
for i in [1,8,15,2,9,16,3,10,17,4,11,18] {
combinations += [i.set(8, 4)]
}
// Diagnol from Right (+6)
for i in [4,11,18,5,12,19,6,13,20,7,14,21] {
combinations += [i.set(6, 4)]
}
return combinations
}()
override func checkDone() {
for set in combinations {
let (winner,gameover) = checkWin(indexes: set)
guard gameover else { continue }
if let w = winner {
board?.showAlert?("Game Over", "Player \(w) Wins")
} else {
board?.showAlert?("Game Over", "Stalemate")
}
return
}
}
private func checkWin(indexes: [Int]) -> (Int?,Bool) {
let p1: String = board.grid[indexes[0] - 1]
let p2: String = board.grid[indexes[1] - 1]
let p3: String = board.grid[indexes[2] - 1]
let p4: String = board.grid[indexes[3] - 1]
if p1 == p2, p2 == p3, p3 == p4, p1 != EmptyPiece {
guard let index = board?.playerPieces.firstIndex(of: p1) else { return (nil,false) }
return (index + 1,true)
}
return (nil,false)
}
}
================================================
FILE: Games/BoardController/BoardViews/GoBoardView.swift
================================================
//
// GoBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class GoBoardView : BoardView {
var passes: Int = 0
override func prepareForInterfaceBuilder() {
board = Gameboard(.go)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.go)
super.awakeFromNib()
}
@IBAction func pass() {
passes += 1
board.changePlayer()
checkDone()
}
override func selectSquare(_ square: Square) {
do {
try board.move(toSquare: square)
} catch {
print(error)
}
updateBoard()
checkDone()
}
override func coordinate(_ touch: UITouch) -> Square {
let p = 30
let w = (frame.width - p * 2) / (board.gridSize - 1)
let h = (frame.height - p * 2) / (board.gridSize - 1)
let loc = touch.location(in: self)
let c = Int((loc.x - (w / 2)) / w)
let r = Int((loc.y - (w / 2)) / h)
return (r,c)
}
override func checkDone() {
guard board.grid.piecesOnBoard().count == board.totalSpaces || passes == 2 else { return }
let pieces1 = board.grid.piecesOnBoard().filter { board.playerPieces[0].contains($0) }
let pieces2 = board.grid.piecesOnBoard().filter { board.playerPieces[1].contains($0) }
if pieces1.count == pieces2.count {
board?.showAlert?("Game Over", "Stalemate")
} else {
board?.showAlert?("Game Over", "Player \(pieces1.count > pieces2.count ? 1 : 2) Wins")
}
passes = 0
}
}
================================================
FILE: Games/BoardController/BoardViews/MancalaBoardView.swift
================================================
//
// MancalaBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class MancalaBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.mancala, testing: true)
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.mancala, testing: true)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
// do {
//
// try board.move(toSquare: square)
//
// } catch {
//
// print(error)
//
// }
updateBoard()
}
// override func coordinate(_ touch: UITouch) -> Square {
//
// let p = 30
// let w = (frame.width - p * 2) / (board.gridSize - 1)
// let h = (frame.height - p * 2) / (board.gridSize - 1)
//
// let loc = touch.location(in: self)
//
// let c = Int((loc.x - (w / 2)) / w)
// let r = Int((loc.y - (w / 2)) / h)
//
// return (r,c)
//
// }
}
================================================
FILE: Games/BoardController/BoardViews/MemoryBoardView.swift
================================================
//
// MemoryBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class MemoryBoardView : BoardView {
var guesses: Int = 0
override func prepareForInterfaceBuilder() {
board = Gameboard(.memory)
_ = try? board?.select(cardAt: (0,2))
_ = try? board?.match(cardAt: (2,1), withCard: (0,2))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.memory)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
let clean: () -> Void = {
self.board.highlights = [self.board.selected, square].compactMap { $0 }
self.board.selected = nil
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak self] in
guard let highlights = self?.board.highlights, highlights.count > 1 else { return }
_ = try? self?.board.match(cardAt: highlights[1], withCard: highlights[0], reset: true)
self?.board.highlights = []
self?.updateBoard()
self?.checkDone()
}
}
if board.highlights.count > 1 {
return
} else if let selected = board.selected {
guesses += 1
do {
_ = try board.match(cardAt: square, withCard: selected)
clean()
} catch MemoryError.badmatch {
clean()
} catch { }
} else {
guard let _ = try? board.select(cardAt: square) else { return }
board.selected = square
}
updateBoard()
}
override func checkDone() {
let cardCount = board.grid.content.reduce(0) {
$0 + $1.reduce(0) { $0 + ($1 != EmptyPiece ? 1 : 0) }
}
if cardCount == 0 {
board?.showAlert?("Game Over", "It took \(guesses) Guesses")
guesses = 0
}
}
}
================================================
FILE: Games/BoardController/BoardViews/PegsBoardView.swift
================================================
//
// PegSolitaireBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
class PegsBoardView: BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.pegs)
_ = try? board.validateMove((3,1), (3,3))
_ = try? board.validateMove((3,4), (3,2))
_ = try? board.validateMove((1,3), (3,3))
_ = try? board.validateMove((3,3), (3,1))
_ = try? board.validateMove((3,0), (3,2))
_ = try? board.validateMove((3,6), (3,4))
_ = try? board.validateMove((5,3), (3,3))
board.showAvailable((3,3))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.pegs)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
if let selected = board.selected {
do {
_ = try board.move(pieceAt: selected, toSquare: square)
board.selected = nil
board.highlights = []
} catch {
print(error)
board.showAvailable(square)
}
} else {
board.showAvailable(square)
}
updateBoard()
}
}
================================================
FILE: Games/BoardController/BoardViews/SudokuBoardView.swift
================================================
//
// SudokuBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class SudokuBoardView : BoardView {
var sudokuNumber: String = "1"
override func prepareForInterfaceBuilder() {
board = Gameboard(.sudoku, testing: true)
_ = try? board.guess(toSquare: (2,7), withGuess: "4")
_ = try? board.guess(toSquare: (8,8), withGuess: "4")
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.sudoku)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
do {
try board.guess(toSquare: square, withGuess: sudokuNumber)
} catch {
print(error)
}
updateBoard()
}
}
extension BoardViewController {
@IBAction func chooseSudokuNymber(sender: UISegmentedControl) {
(boardView as? SudokuBoardView)?.sudokuNumber = "\(sender.selectedSegmentIndex + 1)"
}
}
================================================
FILE: Games/BoardController/BoardViews/TicTacToeBoardView.swift
================================================
//
// TicTacToeBoardView.swift
// Games
//
// Created by Jo Albright on 4/25/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class TicTacToeBoardView : BoardView {
override func prepareForInterfaceBuilder() {
board = Gameboard(.tictactoe)
_ = try? board.move(toSquare: (1,1))
_ = try? board.move(toSquare: (0,1))
_ = try? board.move(toSquare: (1,0))
_ = try? board.move(toSquare: (1,2))
_ = try? board.move(toSquare: (2,0))
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.tictactoe)
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
do {
try board.move(toSquare: square)
} catch {
print(error)
}
updateBoard()
checkDone()
}
lazy var combinations: [[Int]] = {
var combinations: [[Int]] = []
// Side to Side (+1)
for i in [1,4,7] {
combinations += [i.set(1, 3)]
}
// Up & Down (+3)
for i in [1,2,3] {
combinations += [i.set(3, 3)]
}
// Diagonals
combinations += [
1.set(4, 3),
3.set(2, 3)
]
return combinations
}()
override func checkDone() {
for combination in combinations {
let (winner,gameover) = checkWin(indexes: combination)
guard gameover else { continue }
if let w = winner {
board?.showAlert?("Game Over", "Player \(w) Wins")
} else {
board?.showAlert?("Game Over", "Stalemate")
}
return
}
}
private func checkWin(indexes: [Int]) -> (Int?,Bool) {
let p1: String = board.grid[indexes[0] - 1]
let p2: String = board.grid[indexes[1] - 1]
let p3: String = board.grid[indexes[2] - 1]
if p1 == p2, p2 == p3, p1 != EmptyPiece {
guard let index = board?.playerPieces.firstIndex(of: p1) else { return (nil,false) }
return (index + 1,true)
}
return (nil,false)
}
}
================================================
FILE: Games/BoardController/BoardViews/WordsBoardView.swift
================================================
//
// WordsBoardView.swift
// Games
//
// Created by Jo Albright on 4/23/18.
// Copyright © 2018 Jo Albright. All rights reserved.
//
import UIKit
@IBDesignable class WordsBoardView : BoardView {
var selectedTile: Words.Letter?
var bag: [Words.Letter] = []
var rack: [Words.Letter] = [] { didSet { rackUpdated(rack) } }
var rackUpdated: ([Words.Letter]) -> Void = { _ in }
override func prepareForInterfaceBuilder() {
board = Gameboard(.words)
bag = Words.Letter.bag
super.prepareForInterfaceBuilder()
}
override func awakeFromNib() {
board = Gameboard(.words)
bag = Words.Letter.bag
super.awakeFromNib()
}
override func selectSquare(_ square: Square) {
guard let tile = selectedTile else { return }
do {
try board.place(tile: tile, at: square)
if let index = rack.index(of: tile) {
rack.remove(at: index)
rack.append(.none)
selectedTile = nil
}
} catch {
print(error)
}
updateBoard()
}
func reset() {
bag = Words.Letter.bag
rack = []
fillRack()
}
@IBAction func fillRack() {
rack = rack.filter { $0 != .none }
let tiles = 7 - rack.count
print(rack.count,tiles,bag.count)
rack += bag.prefix(tiles)
bag.removeFirst(tiles)
print(rack.count,bag.count)
}
}
class WordsBoardViewController: BoardViewController {
@IBOutlet var rackHolder: UIStackView!
var selected: Words.Letter?
override func viewDidLoad() {
super.viewDidLoad()
(boardView as? WordsBoardView)?.rackUpdated = { rack in
for view in self.rackHolder.arrangedSubviews { self.rackHolder.removeArrangedSubview(view) }
for tile in rack {
let tileView = TileView()
tileView.tile = tile
tileView.color = self.boardView.player2Color
tileView.selectedColor = self.boardView.selectedColor
tileView.backgroundColor = .clear
tileView.letterLabel?.textColor = self.boardView.player1Color
tileView.valueLabel?.textColor = self.boardView.highlightColor
tileView.selected = { tile in
(self.boardView as? WordsBoardView)?.selectedTile = tile
for view in self.rackHolder.arrangedSubviews {
guard let tileView = view as? TileView else { continue }
tileView.color = self.boardView.player2Color
}
}
self.rackHolder.addArrangedSubview(tileView)
}
}
(boardView as? WordsBoardView)?.fillRack()
}
@IBAction override func resetBoard(sender: Any) {
super.resetBoard(sender: sender)
(boardView as? WordsBoardView)?.reset()
}
}
================================================
FILE: Games/BoardController/Boards/Backgammon.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="NKc-XK-NCZ">
<device id="retina6_1" orientation="portrait" appearance="dark"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Backgammon-->
<scene sceneID="JBs-iu-twK">
<objects>
<viewController storyboardIdentifier="BackgammonBoard" id="NKc-XK-NCZ" customClass="BoardViewController" customModule="Games" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="e0z-ug-iQe">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ccH-iz-vSZ" customClass="BackgammonBoardView" customModule="Games" customModuleProvider="target">
<rect key="frame" x="32" y="286.5" width="350" height="323"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" secondItem="ccH-iz-vSZ" secondAttribute="height" multiplier="13:12" id="T6f-YS-Nei"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="bgColor">
<color key="value" red="0.40340342420000003" green="0.33316692120000002" blue="0.19125256039999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="fgColor">
<color key="value" red="0.71556712960000002" green="0.6420300176" blue="0.52321705340000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player1Color">
<color key="value" red="0.1978587963" green="0.1978587963" blue="0.1978587963" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player2Color">
<color key="value" red="1" green="0.99996998520000002" blue="0.99996998520000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Game Logic : Coming Soon" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vqY-NG-dKN">
<rect key="frame" x="77" y="609.5" width="260" height="252.5"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="20"/>
<color key="textColor" name="Accent"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" name="Background"/>
<constraints>
<constraint firstItem="vqY-NG-dKN" firstAttribute="top" secondItem="ccH-iz-vSZ" secondAttribute="bottom" id="Mhv-jI-ccv"/>
<constraint firstItem="vqY-NG-dKN" firstAttribute="centerX" secondItem="e0z-ug-iQe" secondAttribute="centerX" id="Oa5-QG-Vjm"/>
<constraint firstItem="ccH-iz-vSZ" firstAttribute="centerX" secondItem="e0z-ug-iQe" secondAttribute="centerX" id="Sb8-D2-jM1"/>
<constraint firstItem="oVX-bc-ojb" firstAttribute="bottom" secondItem="vqY-NG-dKN" secondAttribute="bottom" id="YXc-AQ-XKX"/>
<constraint firstItem="ccH-iz-vSZ" firstAttribute="top" relation="greaterThanOrEqual" secondItem="oVX-bc-ojb" secondAttribute="top" constant="100" id="eo7-Iz-vAt"/>
<constraint firstItem="ccH-iz-vSZ" firstAttribute="centerY" secondItem="e0z-ug-iQe" secondAttribute="centerY" id="vZr-Gm-1jW"/>
<constraint firstItem="ccH-iz-vSZ" firstAttribute="leading" secondItem="oVX-bc-ojb" secondAttribute="leading" priority="750" constant="32" id="vyq-9G-1ha"/>
</constraints>
<viewLayoutGuide key="safeArea" id="oVX-bc-ojb"/>
</view>
<navigationItem key="navigationItem" title="Backgammon" id="QBH-qI-nBP">
<barButtonItem key="rightBarButtonItem" systemItem="refresh" id="QBm-2U-W7J"/>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="STl-Tr-tef" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="862" y="1209"/>
</scene>
</scenes>
<resources>
<namedColor name="Accent">
<color red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Background">
<color red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>
================================================
FILE: Games/BoardController/Boards/Bombsweeper.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="N0G-Yg-5c6">
<device id="retina6_1" orientation="portrait" appearance="dark"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Bombsweeper-->
<scene sceneID="Zo0-SB-Yvu">
<objects>
<viewController storyboardIdentifier="BombsweeperBoard" id="N0G-Yg-5c6" customClass="BoardViewController" customModule="Games" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Wne-sw-N8L"/>
<viewControllerLayoutGuide type="bottom" id="6mm-r9-T1J"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="FjI-6p-UOS">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="o9a-d5-akx" customClass="BombsweeperBoardView" customModule="Games" customModuleProvider="target">
<rect key="frame" x="32" y="273" width="350" height="350"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="fgColor">
<color key="value" name="Accent"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player1Color">
<color key="value" red="0.99609655139999997" green="0.74099564770000004" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player2Color">
<color key="value" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="selectedColor">
<color key="value" red="0.74601978059999996" green="0.18476429580000001" blue="0.1849055439" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="highlightColor">
<color key="value" name="Text"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="bgColor">
<color key="value" name="Background"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="M55-xK-WZt">
<rect key="frame" x="127" y="623" width="160" height="239"/>
<subviews>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="oRc-AV-ax9">
<rect key="frame" x="0.0" y="104" width="160" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="160" id="rHt-S6-WWJ"/>
</constraints>
<segments>
<segment title="●"/>
<segment title="⚑"/>
</segments>
<color key="tintColor" name="Text"/>
<connections>
<action selector="chooseBombsweeperMarkWithSender:" destination="N0G-Yg-5c6" eventType="valueChanged" id="dv6-cC-fY3"/>
</connections>
</segmentedControl>
</subviews>
<color key="backgroundColor" name="Background"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="oRc-AV-ax9" secondAttribute="trailing" id="UO2-Gk-uUI"/>
<constraint firstItem="oRc-AV-ax9" firstAttribute="centerY" secondItem="M55-xK-WZt" secondAttribute="centerY" id="Uwf-qb-d0Y"/>
<constraint firstItem="oRc-AV-ax9" firstAttribute="leading" secondItem="M55-xK-WZt" secondAttribute="leading" id="gWO-ma-mrJ"/>
</constraints>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="tGk-Xa-V4S"/>
<color key="backgroundColor" name="Background"/>
<constraints>
<constraint firstItem="o9a-d5-akx" firstAttribute="centerY" secondItem="FjI-6p-UOS" secondAttribute="centerY" id="HcM-dz-lrI"/>
<constraint firstItem="o9a-d5-akx" firstAttribute="leading" secondItem="FjI-6p-UOS" secondAttribute="leading" priority="750" constant="32" id="MUO-BL-aeI"/>
<constraint firstItem="tGk-Xa-V4S" firstAttribute="bottom" secondItem="M55-xK-WZt" secondAttribute="bottom" id="Znl-qi-Bgf"/>
<constraint firstItem="o9a-d5-akx" firstAttribute="top" relation="greaterThanOrEqual" secondItem="tGk-Xa-V4S" secondAttribute="top" constant="100" id="cKr-NJ-Ttz"/>
<constraint firstItem="o9a-d5-akx" firstAttribute="centerX" secondItem="FjI-6p-UOS" secondAttribute="centerX" id="f8F-Lk-zKX"/>
<constraint firstItem="o9a-d5-akx" firstAttribute="width" secondItem="o9a-d5-akx" secondAttribute="height" multiplier="1:1" id="ntQ-jp-Jir"/>
<constraint firstItem="M55-xK-WZt" firstAttribute="centerX" secondItem="FjI-6p-UOS" secondAttribute="centerX" id="rU2-NQ-cJV"/>
<constraint firstItem="M55-xK-WZt" firstAttribute="top" secondItem="o9a-d5-akx" secondAttribute="bottom" id="tPa-Xr-5RY"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Bombs" id="Irc-8M-SE8"/>
<navigationItem key="navigationItem" title="Bombsweeper" id="QR5-AV-HMJ">
<barButtonItem key="rightBarButtonItem" systemItem="refresh" id="l3k-yv-0U7">
<connections>
<action selector="resetBoardWithSender:" destination="N0G-Yg-5c6" id="i77-nT-4Br"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="boardView" destination="o9a-d5-akx" id="6Rr-h8-gtQ"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ous-0Z-CVB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="264" y="165"/>
</scene>
</scenes>
<resources>
<namedColor name="Accent">
<color red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Background">
<color red="0.93333333333333335" green="0.93333333333333335" blue="0.93333333333333335" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Text">
<color red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>
================================================
FILE: Games/BoardController/Boards/Checkers.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cgA-mw-r8l">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Checkers-->
<scene sceneID="QZG-Xh-Da1">
<objects>
<viewController storyboardIdentifier="CheckersBoard" id="cgA-mw-r8l" customClass="BoardViewController" customModule="Games" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="p1z-su-fxg"/>
<viewControllerLayoutGuide type="bottom" id="XE8-pT-q9B"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Yij-Jk-BQ3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TOT-Kh-qbK" customClass="CheckersBoardView" customModule="Games" customModuleProvider="target">
<rect key="frame" x="32" y="273" width="350" height="350"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" secondItem="TOT-Kh-qbK" secondAttribute="height" multiplier="1:1" id="jaY-Eb-ONb"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="bgColor">
<color key="value" name="Accent"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="fgColor">
<color key="value" name="Offest"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player1Color">
<color key="value" red="0.86368811130000001" green="0.052148308599999998" blue="0.021709781139999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player2Color">
<color key="value" red="0.57748842590000005" green="0.13851487530000001" blue="0.14583110120000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="selectedColor">
<color key="value" red="0.034735164870000002" green="0.63069970180000001" blue="0.82797604800000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="highlightColor">
<color key="value" red="0.034735164870000002" green="0.63069970180000001" blue="0.82797604800000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Player 1" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="feG-A9-xD8">
<rect key="frame" x="168.5" y="623" width="77" height="239"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="20"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="j4b-lN-HhH"/>
<color key="backgroundColor" name="Background"/>
<constraints>
<constraint firstItem="feG-A9-xD8" firstAttribute="centerX" secondItem="Yij-Jk-BQ3" secondAttribute="centerX" id="3G1-oa-rNS"/>
<constraint firstItem="TOT-Kh-qbK" firstAttribute="centerY" secondItem="Yij-Jk-BQ3" secondAttribute="centerY" id="HFZ-cD-dJb"/>
<constraint firstItem="feG-A9-xD8" firstAttribute="top" secondItem="TOT-Kh-qbK" secondAttribute="bottom" id="QkP-gR-PfG"/>
<constraint firstItem="j4b-lN-HhH" firstAttribute="bottom" secondItem="feG-A9-xD8" secondAttribute="bottom" id="VzE-pb-w3W"/>
<constraint firstItem="TOT-Kh-qbK" firstAttribute="top" relation="greaterThanOrEqual" secondItem="j4b-lN-HhH" secondAttribute="top" constant="100" id="Wnm-EX-HCL"/>
<constraint firstItem="TOT-Kh-qbK" firstAttribute="leading" secondItem="Yij-Jk-BQ3" secondAttribute="leading" priority="750" constant="32" id="bah-ff-MWA"/>
<constraint firstItem="TOT-Kh-qbK" firstAttribute="centerX" secondItem="Yij-Jk-BQ3" secondAttribute="centerX" id="jF6-I3-fEh"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Chess" id="PQc-cK-CMu"/>
<navigationItem key="navigationItem" title="Checkers" id="Szf-EI-EPb">
<barButtonItem key="rightBarButtonItem" systemItem="refresh" id="lfC-bH-ong">
<connections>
<action selector="resetBoardWithSender:" destination="cgA-mw-r8l" id="u4w-HM-SDz"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="boardView" destination="TOT-Kh-qbK" id="9CM-lA-aVo"/>
<outlet property="playerLabel" destination="feG-A9-xD8" id="o04-ru-KH4"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="t3Q-U4-9mj" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="672" y="-229"/>
</scene>
</scenes>
<resources>
<namedColor name="Accent">
<color red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Background">
<color red="0.93333333333333335" green="0.93333333333333335" blue="0.93333333333333335" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Offest">
<color red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="Text">
<color red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>
================================================
FILE: Games/BoardController/Boards/Chess.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19162" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="sor-ud-rWl">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19144"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Chess-->
<scene sceneID="12w-pz-usa">
<objects>
<viewController storyboardIdentifier="ChessBoard" id="sor-ud-rWl" customClass="BoardViewController" customModule="Games" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="emD-eU-xyj"/>
<viewControllerLayoutGuide type="bottom" id="7Ht-uZ-af8"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="uqf-IK-afK">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fNc-VK-RLG" customClass="ChessBoardView" customModule="Games" customModuleProvider="target">
<rect key="frame" x="32" y="273" width="350" height="350"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" secondItem="fNc-VK-RLG" secondAttribute="height" multiplier="1:1" id="hAx-cA-ETU"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="bgColor">
<color key="value" red="0.61397569439999999" green="0.51956820410000004" blue="0.36703523859999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player1Color">
<color key="value" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="player2Color">
<color key="value" red="0.1978587963" green="0.1978587963" blue="0.1978587963" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="fgColor">
<color key="value" red="0.52994791669999997" green="0.45101102510000002" blue="0.32347370669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="selectedColor">
<color key="value" red="0.96359953700000001" green="0.0" blue="0.23977484830000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="highlightColor">
<color key="value" red="0.96359953700000001" green="0.0" blue="0.23977484830000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Player 1" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="29G-Ib-F4a">
<rect key="frame" x="169" y="623" width="76.5" height="239"/>
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="20"/>
<color key="textColor" name="Text"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="YoN-k0-dAd">
<rect key="frame" x="32" y="238" width="350" height="35"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="A" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f8d-1R-TyZ">
<rect key="frame" x="0.0" y="0.0" width="44" height="35"/>
<fontDescription key="fontDescription" type="system" weight="he
gitextract_tij_wt8g/ ├── .gitignore ├── Gameboards.playground/ │ ├── Pages/ │ │ ├── Checkers.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ ├── Chess.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ ├── Go.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ ├── Mancala.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ ├── Minesweeper.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ ├── Sudoku.xcplaygroundpage/ │ │ │ └── Contents.swift │ │ └── TicTacToe.xcplaygroundpage/ │ │ └── Contents.swift │ ├── Sources/ │ │ ├── Boards/ │ │ │ ├── Alquerque.swift │ │ │ ├── Backgammon.swift │ │ │ ├── Bombsweeper.swift │ │ │ ├── Checkers.swift │ │ │ ├── Chess.swift │ │ │ ├── Dots.swift │ │ │ ├── Doubles.swift │ │ │ ├── Four.swift │ │ │ ├── Go.swift │ │ │ ├── InProgress/ │ │ │ │ ├── Battleship.swift │ │ │ │ ├── Dominos.swift │ │ │ │ ├── Majong.swift │ │ │ │ ├── Pilare.swift │ │ │ │ ├── Tetris.swift │ │ │ │ └── Trouble.swift │ │ │ ├── Ludo.swift │ │ │ ├── Mancala.swift │ │ │ ├── Memory.swift │ │ │ ├── Pegs.swift │ │ │ ├── Sudoku.swift │ │ │ ├── TicTacToe.swift │ │ │ └── Words.swift │ │ ├── Core/ │ │ │ ├── Extensions.swift │ │ │ ├── Grid.swift │ │ │ ├── Operators.swift │ │ │ └── Views/ │ │ │ ├── BackgammonView.swift │ │ │ ├── DotsView.swift │ │ │ ├── FourView.swift │ │ │ ├── GoView.swift │ │ │ ├── MancalaView.swift │ │ │ ├── MatrixView.swift │ │ │ ├── PegsView.swift │ │ │ ├── SudokuView.swift │ │ │ ├── TicTacToeView.swift │ │ │ └── WordsView.swift │ │ ├── Gameboard.swift │ │ └── Validation.swift │ └── contents.xcplayground ├── Games/ │ ├── AppDelegate.swift │ ├── Assets.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Colors/ │ │ │ ├── Accent.colorset/ │ │ │ │ └── Contents.json │ │ │ ├── Background.colorset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Offest.colorset/ │ │ │ │ └── Contents.json │ │ │ └── Text.colorset/ │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj/ │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── BoardController/ │ │ ├── BoardViewController.swift │ │ ├── BoardViews/ │ │ │ ├── BackgammonBoardView.swift │ │ │ ├── BombsweeperBoardView.swift │ │ │ ├── CheckersBoardView.swift │ │ │ ├── ChessBoardView.swift │ │ │ ├── DotsBoardView.swift │ │ │ ├── DoublesBoardView.swift │ │ │ ├── FourBoardView.swift │ │ │ ├── GoBoardView.swift │ │ │ ├── MancalaBoardView.swift │ │ │ ├── MemoryBoardView.swift │ │ │ ├── PegsBoardView.swift │ │ │ ├── SudokuBoardView.swift │ │ │ ├── TicTacToeBoardView.swift │ │ │ └── WordsBoardView.swift │ │ └── Boards/ │ │ ├── Backgammon.storyboard │ │ ├── Bombsweeper.storyboard │ │ ├── Checkers.storyboard │ │ ├── Chess.storyboard │ │ ├── Dots.storyboard │ │ ├── Doubles.storyboard │ │ ├── Four.storyboard │ │ ├── Go.storyboard │ │ ├── Mancala.storyboard │ │ ├── Memory.storyboard │ │ ├── Pegs.storyboard │ │ ├── Sudoku.storyboard │ │ ├── TicTacToe.storyboard │ │ └── Words.storyboard │ ├── Info.plist │ └── MainViewController.swift ├── Games.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ ├── contents.xcworkspacedata │ └── xcshareddata/ │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── README.md ├── RM_Checkers.md ├── RM_Chess.md ├── RM_Go.md ├── RM_Minesweeper.md ├── RM_Sudoku.md ├── RM_TicTacToe.md └── icon.ai
Condensed preview — 99 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (594K chars).
[
{
"path": ".gitignore",
"chars": 622,
"preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
},
{
"path": "Gameboards.playground/Pages/Checkers.xcplaygroundpage/Contents.swift",
"chars": 1043,
"preview": "import UIKit\n\nvar checkers = Gameboard(.Checkers)\n\n// setup colors\n\nvar colors = BoardColors()\n\ncolors.background = UICo"
},
{
"path": "Gameboards.playground/Pages/Chess.xcplaygroundpage/Contents.swift",
"chars": 1070,
"preview": "import UIKit\n\nvar chess = Gameboard(.Chess)\n\n// setup colors\n\nvar colors = BoardColors()\n\ncolors.background = UIColor(re"
},
{
"path": "Gameboards.playground/Pages/Go.xcplaygroundpage/Contents.swift",
"chars": 665,
"preview": "import UIKit\n\nvar go = Gameboard(.Go)\n\n// setup colors\n\nvar colors = BoardColors()\n\ncolors.background = UIColor(red:0.36"
},
{
"path": "Gameboards.playground/Pages/Mancala.xcplaygroundpage/Contents.swift",
"chars": 12,
"preview": "import UIKit"
},
{
"path": "Gameboards.playground/Pages/Minesweeper.xcplaygroundpage/Contents.swift",
"chars": 1203,
"preview": "import UIKit\n\nenum MoveType { case Guess, Mark }\n\nvar minesweeper = Gameboard(.Minesweeper, testing: true)\n\n// setup col"
},
{
"path": "Gameboards.playground/Pages/Sudoku.xcplaygroundpage/Contents.swift",
"chars": 782,
"preview": "import UIKit\n\nvar sudoku = Gameboard(.Sudoku, testing: true)\n\n// setup colors\n\nvar colors = BoardColors()\n\ncolors.backgr"
},
{
"path": "Gameboards.playground/Pages/TicTacToe.xcplaygroundpage/Contents.swift",
"chars": 667,
"preview": "import UIKit\n\nvar tictactoe = Gameboard(.TicTacToe)\n\n// setup colors\n\nvar colors = BoardColors()\n\ncolors.player1 = UICol"
},
{
"path": "Gameboards.playground/Sources/Boards/Alquerque.swift",
"chars": 43,
"preview": "import UIKit\n\npublic struct Alquerque {\n\n}\n"
},
{
"path": "Gameboards.playground/Sources/Boards/Backgammon.swift",
"chars": 1854,
"preview": "import UIKit\n\npublic struct Backgammon {\n \n public static var board: Grid {\n \n return Grid([\n "
},
{
"path": "Gameboards.playground/Sources/Boards/Bombsweeper.swift",
"chars": 5560,
"preview": "import UIKit\n\nextension Difficulty {\n\n var bombFlags: Int {\n\n switch self {\n case .easy: return 20\n "
},
{
"path": "Gameboards.playground/Sources/Boards/Checkers.swift",
"chars": 5535,
"preview": "import UIKit\n\npublic struct Checkers {\n \n public enum PieceType: String {\n \n case none = \" \"\n "
},
{
"path": "Gameboards.playground/Sources/Boards/Chess.swift",
"chars": 4792,
"preview": "import UIKit\n\npublic struct Chess {\n \n public enum PieceType: String {\n \n case none = \" \"\n \n "
},
{
"path": "Gameboards.playground/Sources/Boards/Dots.swift",
"chars": 3259,
"preview": "import UIKit\n\npublic struct Dots {\n\n public static var board: Grid { return Grid(17 ✕ (17 ✕ (\"●\" %% \"0\") %% 17 ✕ (\"0\""
},
{
"path": "Gameboards.playground/Sources/Boards/Doubles.swift",
"chars": 4236,
"preview": "import UIKit\n\npublic struct Doubles {\n \n public static var board: Grid { return Grid(4 ✕ (4 ✕ EmptyPiece)) }\n \n"
},
{
"path": "Gameboards.playground/Sources/Boards/Four.swift",
"chars": 2214,
"preview": "import UIKit\n\npublic struct Four {\n \n public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }\n \n "
},
{
"path": "Gameboards.playground/Sources/Boards/Go.swift",
"chars": 3374,
"preview": "import UIKit\n\nenum GoError: Error {\n \n case openchain\n \n}\n\npublic struct Go {\n \n public static var board:"
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Battleship.swift",
"chars": 978,
"preview": "import UIKit\n\npublic struct Battleship {\n \n public enum PieceType: String {\n \n case carrier\n "
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Dominos.swift",
"chars": 273,
"preview": "import UIKit\n\npublic struct Dominos {\n \n public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }\n "
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Majong.swift",
"chars": 213,
"preview": "import UIKit\n\npublic struct Majong {\n \n public static var board: Grid { return Grid(6 ✕ (7 ✕ EmptyPiece)) }\n \n "
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Pilare.swift",
"chars": 424,
"preview": "import UIKit\n\npublic struct Pilare {\n \n public static var board: Grid {\n \n return Grid([\n \n "
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Tetris.swift",
"chars": 395,
"preview": "//\n// Tetris.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rights res"
},
{
"path": "Gameboards.playground/Sources/Boards/InProgress/Trouble.swift",
"chars": 397,
"preview": "//\n// Trouble.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rights re"
},
{
"path": "Gameboards.playground/Sources/Boards/Ludo.swift",
"chars": 327,
"preview": "import UIKit\n\npublic struct Ludo {\n \n public static var board: Grid {\n \n return Grid([\n \n"
},
{
"path": "Gameboards.playground/Sources/Boards/Mancala.swift",
"chars": 1874,
"preview": "import UIKit\n\npublic struct Mancala {\n \n public static var board: Grid {\n \n return Grid([\n "
},
{
"path": "Gameboards.playground/Sources/Boards/Memory.swift",
"chars": 4262,
"preview": "import UIKit\n\nenum MemoryError: Error {\n \n case badmatch\n case nocard\n case samecard\n \n}\n\nextension Diffi"
},
{
"path": "Gameboards.playground/Sources/Boards/Pegs.swift",
"chars": 2867,
"preview": "//\n// Pegs.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rights reser"
},
{
"path": "Gameboards.playground/Sources/Boards/Sudoku.swift",
"chars": 5235,
"preview": "import UIKit\n\nextension Difficulty {\n \n var sudokuRange: CountableClosedRange<Int> {\n \n switch self "
},
{
"path": "Gameboards.playground/Sources/Boards/TicTacToe.swift",
"chars": 1609,
"preview": "import UIKit\n\npublic struct TicTacToe {\n \n public static var board: Grid { return Grid(3 ✕ (3 ✕ EmptyPiece)) }\n "
},
{
"path": "Gameboards.playground/Sources/Boards/Words.swift",
"chars": 5952,
"preview": "import UIKit\n\npublic struct Words {\n \n public enum PieceType: String {\n \n static var all: [PieceType"
},
{
"path": "Gameboards.playground/Sources/Core/Extensions.swift",
"chars": 1161,
"preview": "import UIKit\n\npublic typealias Square = (c: Int, r: Int)\npublic typealias ChessSquare = (c: String, r: Int)\n\npublic type"
},
{
"path": "Gameboards.playground/Sources/Core/Grid.swift",
"chars": 3301,
"preview": "import UIKit\n\nlet EmptyPiece: String = \" \"\n\npublic class Grid {\n \n public var content: [[String]]\n \n public "
},
{
"path": "Gameboards.playground/Sources/Core/Operators.swift",
"chars": 1664,
"preview": "import UIKit\n\npublic func * (lhs: CGFloat, rhs: Int) -> CGFloat {\n \n return lhs * CGFloat(rhs)\n \n}\n\npublic func"
},
{
"path": "Gameboards.playground/Sources/Core/Views/BackgammonView.swift",
"chars": 2061,
"preview": "//\n// BackgammonView.swift\n// Games\n//\n// Created by Jo Albright on 4/20/18.\n// Copyright © 2018 Jo Albright. All ri"
},
{
"path": "Gameboards.playground/Sources/Core/Views/DotsView.swift",
"chars": 2393,
"preview": "//\n// DotsView.swift\n// Games\n//\n// Created by Jo Albright on 4/22/18.\n// Copyright © 2018 Jo Albright. All rights r"
},
{
"path": "Gameboards.playground/Sources/Core/Views/FourView.swift",
"chars": 1762,
"preview": "//\n// FourView.swift\n// Games\n//\n// Created by Jo Albright on 4/21/18.\n// Copyright © 2018 Jo Albright. All rights r"
},
{
"path": "Gameboards.playground/Sources/Core/Views/GoView.swift",
"chars": 938,
"preview": "import UIKit\n\npublic class GoView: UIView {\n \n public var p: CGFloat = 20\n public var lineColor: UIColor = .bla"
},
{
"path": "Gameboards.playground/Sources/Core/Views/MancalaView.swift",
"chars": 5100,
"preview": "//\n// MancalaView.swift\n// Games\n//\n// Created by Jo Albright on 4/22/18.\n// Copyright © 2018 Jo Albright. All right"
},
{
"path": "Gameboards.playground/Sources/Core/Views/MatrixView.swift",
"chars": 906,
"preview": "import UIKit\n\npublic class MatrixView: UIView {\n \n public var p: CGFloat = 10\n \n var lineColor: UIColor = .b"
},
{
"path": "Gameboards.playground/Sources/Core/Views/PegsView.swift",
"chars": 2082,
"preview": "//\n// PegsView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rights r"
},
{
"path": "Gameboards.playground/Sources/Core/Views/SudokuView.swift",
"chars": 1053,
"preview": "import UIKit\n\npublic class SudokuView: UIView {\n \n var lineColor: UIColor = .black\n \n public override func d"
},
{
"path": "Gameboards.playground/Sources/Core/Views/TicTacToeView.swift",
"chars": 1032,
"preview": "import UIKit\n\npublic class TicTacToeView: UIView {\n \n public var p: CGFloat = 10\n public var lineColor: UIColor"
},
{
"path": "Gameboards.playground/Sources/Core/Views/WordsView.swift",
"chars": 2821,
"preview": "//\n// WordsView.swift\n// Games\n//\n// Created by Jo Albright on 4/23/18.\n// Copyright © 2018 Jo Albright. All rights "
},
{
"path": "Gameboards.playground/Sources/Gameboard.swift",
"chars": 10881,
"preview": "import UIKit\n\nenum Difficulty {\n \n case easy, medium, hard\n \n var name: String {\n \n switch sel"
},
{
"path": "Gameboards.playground/Sources/Validation.swift",
"chars": 6071,
"preview": "import UIKit\n\npublic enum MoveError: Error {\n \n /// Good try. Need a hint?\n case incorrectguess\n /// Serious"
},
{
"path": "Gameboards.playground/contents.xcplayground",
"chars": 359,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='6.0' target-platform='ios'>\n <pages>\n "
},
{
"path": "Games/AppDelegate.swift",
"chars": 255,
"preview": "//\n// AppDelegate.swift\n// Games\n//\n// Created by Jo Albright on 2/3/16.\n// Copyright © 2016 Jo Albright. All rights"
},
{
"path": "Games/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2217,
"preview": "{\n \"images\" : [\n\t{\n \"size\" : \"20x20\",\n \"idiom\": \"iphone\",\n\t \"filename\" : \"icon-20@2x.png\",\n \"scale\": \"2"
},
{
"path": "Games/Assets.xcassets/Colors/Accent.colorset/Contents.json",
"chars": 688,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n },\n \"colors\" : [\n {\n \"idiom\" : \"universal\",\n \"c"
},
{
"path": "Games/Assets.xcassets/Colors/Background.colorset/Contents.json",
"chars": 688,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n },\n \"colors\" : [\n {\n \"idiom\" : \"universal\",\n \"c"
},
{
"path": "Games/Assets.xcassets/Colors/Contents.json",
"chars": 63,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}\n"
},
{
"path": "Games/Assets.xcassets/Colors/Offest.colorset/Contents.json",
"chars": 689,
"preview": "{\n \"colors\" : [\n {\n \"color\" : {\n \"color-space\" : \"srgb\",\n \"components\" : {\n \"alpha\" : \"1"
},
{
"path": "Games/Assets.xcassets/Colors/Text.colorset/Contents.json",
"chars": 688,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n },\n \"colors\" : [\n {\n \"idiom\" : \"universal\",\n \"c"
},
{
"path": "Games/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Games/Base.lproj/LaunchScreen.storyboard",
"chars": 1664,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Games/Base.lproj/Main.storyboard",
"chars": 11772,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/BoardViewController.swift",
"chars": 4902,
"preview": "//\n// ViewController.swift\n// Games\n//\n// Created by Jo Albright on 2/3/16.\n// Copyright © 2016 Jo Albright. All rig"
},
{
"path": "Games/BoardController/BoardViews/BackgammonBoardView.swift",
"chars": 1162,
"preview": "//\n// BackgammonBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. A"
},
{
"path": "Games/BoardController/BoardViews/BombsweeperBoardView.swift",
"chars": 1880,
"preview": "//\n// BombsweeperBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. "
},
{
"path": "Games/BoardController/BoardViews/CheckersBoardView.swift",
"chars": 1609,
"preview": "//\n// CheckersBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All"
},
{
"path": "Games/BoardController/BoardViews/ChessBoardView.swift",
"chars": 1221,
"preview": "//\n// ChessBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All ri"
},
{
"path": "Games/BoardController/BoardViews/DotsBoardView.swift",
"chars": 874,
"preview": "//\n// DotsBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rig"
},
{
"path": "Games/BoardController/BoardViews/DoublesBoardView.swift",
"chars": 3985,
"preview": "//\n// DoublesBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/27/18.\n// Copyright © 2018 Jo Albright. All "
},
{
"path": "Games/BoardController/BoardViews/FourBoardView.swift",
"chars": 2994,
"preview": "//\n// FourBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All rig"
},
{
"path": "Games/BoardController/BoardViews/GoBoardView.swift",
"chars": 1897,
"preview": "//\n// GoBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All right"
},
{
"path": "Games/BoardController/BoardViews/MancalaBoardView.swift",
"chars": 1168,
"preview": "//\n// MancalaBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All "
},
{
"path": "Games/BoardController/BoardViews/MemoryBoardView.swift",
"chars": 2320,
"preview": "//\n// MemoryBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All r"
},
{
"path": "Games/BoardController/BoardViews/PegsBoardView.swift",
"chars": 1509,
"preview": "//\n// PegSolitaireBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright."
},
{
"path": "Games/BoardController/BoardViews/SudokuBoardView.swift",
"chars": 1204,
"preview": "//\n// SudokuBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. All r"
},
{
"path": "Games/BoardController/BoardViews/TicTacToeBoardView.swift",
"chars": 2351,
"preview": "//\n// TicTacToeBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/25/18.\n// Copyright © 2018 Jo Albright. Al"
},
{
"path": "Games/BoardController/BoardViews/WordsBoardView.swift",
"chars": 3395,
"preview": "//\n// WordsBoardView.swift\n// Games\n//\n// Created by Jo Albright on 4/23/18.\n// Copyright © 2018 Jo Albright. All ri"
},
{
"path": "Games/BoardController/Boards/Backgammon.storyboard",
"chars": 6963,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Bombsweeper.storyboard",
"chars": 9625,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Checkers.storyboard",
"chars": 8719,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Chess.storyboard",
"chars": 37465,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Dots.storyboard",
"chars": 5859,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Doubles.storyboard",
"chars": 7823,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Four.storyboard",
"chars": 7956,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Go.storyboard",
"chars": 12030,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Mancala.storyboard",
"chars": 6479,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Memory.storyboard",
"chars": 5953,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Pegs.storyboard",
"chars": 6811,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Sudoku.storyboard",
"chars": 9238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/TicTacToe.storyboard",
"chars": 7765,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/BoardController/Boards/Words.storyboard",
"chars": 14441,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Games/Info.plist",
"chars": 1406,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Games/MainViewController.swift",
"chars": 2705,
"preview": "//\n// MainViewController.swift\n// Games\n//\n// Created by Jo Albright on 4/20/18.\n// Copyright © 2018 Jo Albright. Al"
},
{
"path": "Games.xcodeproj/project.pbxproj",
"chars": 44532,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Games.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 150,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:Games.xcodeproj"
},
{
"path": "Games.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1196,
"preview": "# Gameboard\n\nGameboards built in a playground\n\n### Games\n\n*Links send you to the readme for each game.*\n\n- [x] [Checkers"
},
{
"path": "RM_Checkers.md",
"chars": 1401,
"preview": "# Checkers\n\n\n\n```swift\nvar checkers = GameBoard(.Checkers)\n\n// setup colors\n\n"
},
{
"path": "RM_Chess.md",
"chars": 1527,
"preview": "# Chess\n\n\n\n```swift\nvar chess = GameBoard(.Chess)\n\n// setup colors\n\nvar colors = Bo"
},
{
"path": "RM_Go.md",
"chars": 983,
"preview": "# Go\n\n\n\n```swift\nvar go = Gameboard(.Go)\n\n// setup colors\n\nvar colors = BoardColors()\n\nco"
},
{
"path": "RM_Minesweeper.md",
"chars": 1452,
"preview": "# Minesweeper\n\n\n\n```swift\nenum MoveType { case Guess, Mark }\n\nvar mines"
},
{
"path": "RM_Sudoku.md",
"chars": 1105,
"preview": "# Sudoku\n\n\n\n```swift\nvar sudoku = Gameboard(.Sudoku)\n\n// setup colors\n\nvar colors"
},
{
"path": "RM_TicTacToe.md",
"chars": 895,
"preview": "# TicTacToe\n\n\n\n```swift\nvar tictactoe = GameBoard(.TicTacToe)\n\n// setup col"
},
{
"path": "icon.ai",
"chars": 116939,
"preview": "%PDF-1.5\r%\r\n1 0 obj\r<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Ty"
}
]
About this extraction
This page contains the full source code of the joalbright/Gameboard GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 99 files (478.1 KB), approximately 178.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.