Skip to content

Commit

Permalink
Flip black pieces when human
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Sep 23, 2024
1 parent 513bedc commit 15d7cd0
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 44 deletions.
15 changes: 13 additions & 2 deletions Chess/BoardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class BoardView: UIView {
private(set) var squares: [UIView] = []
private(set) var pieces: [String: UIImageView] = [:]
private(set) var moveIndicators: [UIView] = []

var flipBlackPieces: Bool = false {
didSet { updatePieces() }
}

var theme: Theme = .init(rawValue: Storage.shared.boardTheme ?? "") ?? .classic {
didSet { updateTheme() }
}
Expand Down Expand Up @@ -119,7 +124,10 @@ class BoardView: UIView {
usedIDs.insert(piece.id)
view.image = UIImage(named: piece.imageName)
view.frame = frame(x: j, y: i, size: size)
view.layer.transform = CATransform3DMakeScale(0.8, 0.8, 0)
var transform = CATransform3DMakeScale(0.8, 0.8, 0)
let rotate = flipBlackPieces && piece.color == .black
transform = CATransform3DRotate(transform, rotate ? .pi : 0, 0, 0, 1)
view.layer.transform = transform
}
}
for (id, view) in pieces where !usedIDs.contains(id) {
Expand Down Expand Up @@ -198,13 +206,16 @@ private extension UIImageView {
) {
let pulseView = UIImageView(frame: frame)
pulseView.image = image
pulseView.layer.transform = layer.transform
superview?.addSubview(pulseView)
UIView.animate(
withDuration: duration,
delay: 0,
options: .curveEaseOut,
animations: {
pulseView.transform = .init(scaleX: scale, y: scale)
var transform = pulseView.layer.transform
transform = CATransform3DScale(transform, scale, scale, 1)
pulseView.layer.transform = transform
pulseView.alpha = 0
}, completion: { _ in
pulseView.removeFromSuperview()
Expand Down
89 changes: 59 additions & 30 deletions Chess/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,9 @@ import UIKit

class SettingsViewController: UIViewController {
let tableView = UITableView(frame: .zero, style: .insetGrouped)
var selectedTheme: Theme {
didSet {
Storage.shared.boardTheme = selectedTheme.rawValue
tableView.reloadData()
}
}

var onThemeSelect: ((Theme) -> Void)?

init(selectedTheme: Theme?) {
self.selectedTheme = selectedTheme ?? .classic
super.init(nibName: nil, bundle: nil)
}

deinit {
print("SettingsViewController deinit")
}

@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var onFlipBlackWhenHuman: ((Bool) -> Void)?

override func viewDidLoad() {
super.viewDidLoad()
Expand All @@ -54,28 +35,76 @@ class SettingsViewController: UIViewController {
}

extension SettingsViewController: UITableViewDataSource, UITableViewDelegate {
enum Section: Int, CaseIterable {
case settings
case themes
}

func numberOfSections(in _: UITableView) -> Int {
1
Section.allCases.count
}

func tableView(_: UITableView, titleForHeaderInSection _: Int) -> String? {
"Board Themes"
func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
switch Section(rawValue: section) {
case .settings:
return nil
case .themes:
return "Board Themes"
case nil:
return nil
}
}

func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
Theme.allCases.count
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
switch Section(rawValue: section) {
case .settings:
return 1
case .themes:
return Theme.allCases.count
case nil:
return 0
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let theme = Theme.allCases[indexPath.row]
cell.textLabel?.text = theme.rawValue
cell.accessoryType = selectedTheme == theme ? .checkmark : .none
switch Section(rawValue: indexPath.section) {
case .settings:
cell.textLabel?.text = "Flip black pieces when human"
let toggle = UISwitch()
toggle.isOn = Storage.shared.flipBlackWhenHuman
toggle.addTarget(self, action: #selector(toggleFlipBlack), for: .valueChanged)
cell.accessoryView = toggle
case .themes:
let theme = Theme.allCases[indexPath.row]
cell.textLabel?.text = theme.rawValue
let selected = Storage.shared.boardTheme == theme.rawValue
cell.accessoryType = selected ? .checkmark : .none
cell.accessoryView = nil
case nil:
break
}
return cell
}

@objc private func toggleFlipBlack() {
let cell = tableView.cellForRow(at: IndexPath(item: 0, section: Section.settings.rawValue))
let selected = (cell?.accessoryView as? UISwitch)?.isOn ?? false
Storage.shared.flipBlackWhenHuman = selected
onFlipBlackWhenHuman?(selected)
}

func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedTheme = Theme.allCases[indexPath.row]
onThemeSelect?(selectedTheme)
switch Section(rawValue: indexPath.section) {
case .settings:
break
case .themes:
let selectedTheme = Theme.allCases[indexPath.row]
Storage.shared.boardTheme = selectedTheme.rawValue
tableView.reloadSections([Section.themes.rawValue], with: .none)
onThemeSelect?(selectedTheme)
case nil:
break
}
}
}
21 changes: 10 additions & 11 deletions Chess/Storage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,15 @@

import Foundation

@propertyWrapper public struct UserDefaultWrapper<Value> {
public let key: String
public let storage: UserDefaults = .standard
@propertyWrapper struct UserDefaultWrapper<Value> {
let key: String
let `default`: Value
let storage: UserDefaults = .standard

public init(key: String) {
self.key = key
}

public var wrappedValue: Value? {
var wrappedValue: Value {
get {
storage.value(forKey: key) as? Value
storage.value(forKey: key) as? Value ?? `default`
}

set {
storage.setValue(newValue, forKey: key)
storage.synchronize()
Expand All @@ -31,6 +27,9 @@ import Foundation
class Storage {
static let shared = Storage()

@UserDefaultWrapper(key: "boardTheme")
@UserDefaultWrapper(key: "boardTheme", default: nil)
var boardTheme: String?

@UserDefaultWrapper(key: "flipBlackWhenHuman", default: false)
var flipBlackWhenHuman: Bool
}
6 changes: 5 additions & 1 deletion Chess/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ class ViewController: UIViewController {
}

@IBAction private func settings() {
let vc = SettingsViewController(selectedTheme: boardView?.theme ?? .classic)
let vc = SettingsViewController()
vc.onThemeSelect = { self.boardView?.theme = $0 }
vc.onFlipBlackWhenHuman = {
self.boardView?.flipBlackPieces = $0 && self.game.blackIsHuman
}
present(vc, animated: true)
}
}
Expand Down Expand Up @@ -149,6 +152,7 @@ private extension ViewController {
func updateUI() {
setControl(undoButton, enabled: canUndo)
setControl(resetButton, enabled: game.inProgress)
boardView?.flipBlackPieces = game.blackIsHuman && Storage.shared.flipBlackWhenHuman
}

func setControl(_ control: UIControl?, enabled: Bool) {
Expand Down

0 comments on commit 15d7cd0

Please sign in to comment.