隨記
1. 五子棋游戲
(1). RenjuBoard.swift
mport UIKit
/**
棋盤交叉點的狀態
- Space: 空格
- Black: 黑棋
- White: 白棋
*/
enum PointState {
case Space, Black, White
}
/// 棋盤
class RenjuBoard {
var board: [[PointState]]
var isBlackTurn = true
var isGameOver = false
init() {
board = [[PointState]](count: 15, repeatedValue: [PointState](count: 15, repeatedValue: .Space))
}
// 索引器語法 - 可以直接對棋盤對象做下標運算來放置棋子
subscript(row: Int, col: Int) -> Bool {
get { return board[row][col] == .Space }
set(isBlack) {
if board[row][col] == .Space {
board[row][col] = isBlack ? .Black : .White
isBlackTurn = !isBlackTurn
}
}
}
func reset() {
isGameOver = false
isBlackTurn = true
for i in 0..<board.count {
for j in 0..<board[i].count {
board[i][j] = .Space
}
}
}
func judge(row: Int, _ col: Int) -> Bool {
return _judgeH(row, col) || _judgeV(row, col) || _judgeX1(row, col) || _judgeX2(row, col)
}
private func _judgeH(row: Int, _ col: Int) -> Bool {
var counter = 1
var currentCol = col - 1
while currentCol >= 0 {
if board[row][currentCol] == board[row][col] {
counter += 1
currentCol -= 1
}
else {
break
}
}
currentCol = col + 1
while currentCol < board.count {
if board[row][currentCol] == board[row][col] {
counter += 1
currentCol += 1
}
else {
break
}
}
return counter >= 5
}
private func _judgeV(row: Int, _ col: Int) -> Bool {
var counter = 1
var currentRow = row - 1
while currentRow >= 0 {
if board[currentRow][col] == board[row][col] {
counter += 1
currentRow -= 1
}
else {
break
}
}
currentRow = row + 1
while currentRow < board.count {
if board[currentRow][col] == board[row][col] {
counter += 1
currentRow += 1
}
else {
break
}
}
return counter >= 5
}
private func _judgeX1(row: Int, _ col: Int) -> Bool {
var counter = 1
var currentRow = row - 1
var currentCol = col - 1
while currentRow >= 0 && currentCol > 0 {
if board[currentRow][currentCol] == board[row][col] {
counter += 1
currentRow -= 1
currentCol -= 1
}
else {
break
}
}
currentRow = row + 1
currentCol = col + 1
while currentRow < board.count && currentCol < board.count {
if board[currentRow][currentCol] == board[row][col] {
counter += 1
currentRow += 1
currentCol += 1
}
else {
break
}
}
return counter >= 5
}
private func _judgeX2(row: Int, _ col: Int) -> Bool {
var counter = 1
var currentRow = row - 1
var currentCol = col + 1
while currentRow >= 0 && currentCol < board.count {
if board[currentRow][currentCol] == board[row][col] {
counter += 1
currentRow -= 1
currentCol += 1
}
else {
break
}
}
currentRow = row + 1
currentCol = col - 1
while currentRow < board.count && currentCol >= 0 {
if board[currentRow][currentCol] == board[row][col] {
counter += 1
currentRow += 1
currentCol -= 1
}
else {
break
}
}
return counter >= 5
}
func draw() {
let lineBP = UIBezierPath()
// 繪制15條橫線和15條豎線來構造一個棋盤
for i in 0..<board.count {
lineBP.moveToPoint(CGPointMake(10, 10 + 50 * CGFloat(i)))
lineBP.addLineToPoint(CGPointMake(710, 10 + 50 * CGFloat(i)))
lineBP.moveToPoint(CGPointMake(10 + 50 * CGFloat(i), 10))
lineBP.addLineToPoint(CGPointMake(10 + 50 * CGFloat(i), 710))
}
lineBP.stroke()
// 繪制棋盤的邊框
let rectBP = UIBezierPath(rect: CGRectMake(3, 3, 714, 714))
rectBP.lineWidth = 6
rectBP.stroke()
// 繪制天元和星
let starsRectArray = [
CGRectMake(155, 155, 10, 10),
CGRectMake(555, 155, 10, 10),
CGRectMake(155, 555, 10, 10),
CGRectMake(555, 555, 10, 10),
CGRectMake(355, 355, 10, 10)
]
for starRect in starsRectArray {
let ovalBP = UIBezierPath(ovalInRect: starRect)
ovalBP.fill()
}
// 繪制棋盤上的棋子
for i in 0..<board.count {
for j in 0..<board[i].count {
if board[i][j] != .Space {
let ovalBP = UIBezierPath(ovalInRect: CGRectMake(-10 + CGFloat(j) * 50, -10 + CGFloat(i) * 50, 40, 40))
(board[i][j] == .Black ? UIColor.blackColor() : UIColor.whiteColor()).set()
ovalBP.fill()
}
}
}
}
}
(2). Canvas.swift
import UIKit
// 有的時候某個對象要做某件事情但其自身又沒有能力做這件事情
// 這個時候就可以使用委托回調的編程模式讓別的對象來做這件事情
// 實現委托回調的編程模式有以下幾個步驟:
// 1. 設計一個協議(被委托方必須要遵循協議才能給別的對象當委托)
protocol CanvasDelegate: class {
// 協議里面的方法就是要委托其他對象做的事情
func showMessage(canvas: Canvas, message: String)
}
class Canvas: UIView {
// 2. 委托方添加一個屬性其類型是遵循了協議的被委托方
weak var delegate: CanvasDelegate?
var renjuBoard = RenjuBoard()
var isAutoMode = false
func clearBoard() {
renjuBoard.reset()
setNeedsDisplay()
}
func randomMove() {
let row = Int(arc4random_uniform(15))
let col = Int(arc4random_uniform(15))
if renjuBoard[row, col] {
renjuBoard[row, col] = renjuBoard.isBlackTurn
setNeedsDisplay()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Swift 2中的guard大法, Swift 3中據說要廢掉
guard !isAutoMode else { return }
// guard !renjuBoard.isGameOver else { return }
if !renjuBoard.isGameOver {
if let touch = touches.first {
let point = touch.locationInView(self)
let row = lround(Double(point.y - 10) / 50)
let col = lround(Double(point.x - 10) / 50)
if renjuBoard[row, col] {
renjuBoard[row, col] = renjuBoard.isBlackTurn
setNeedsDisplay()
if renjuBoard.judge(row, col) {
renjuBoard.isGameOver = true
// 3. 自己做不了的事情委托給別的對象來做
delegate?.showMessage(self, message: renjuBoard.isBlackTurn ? "白棋勝" : "黑棋勝")
}
}
}
}
}
override func drawRect(rect: CGRect) {
renjuBoard.draw()
}
}
(3). ViewController.swift
// 4. 讓視圖控制器遵循協議成為被委托方(協議表能力)
class ViewController: UIViewController, CanvasDelegate {
var timer: NSTimer?
var canvas: Canvas!
override func viewDidLoad() {
super.viewDidLoad()
canvas = Canvas(frame: CGRectMake(0, 0, 720, 720))
// canvas.isAutoMode = true
// 6. 給畫布對象綁定委托(self就是視圖控制器對象它遵循了協議所以有充當委托的能力也就是說可以扮演被委托方的角色)
canvas.delegate = self
canvas.center = self.view.center
canvas.backgroundColor = UIColor(red: 254.0 / 255.0, green: 209.0 / 255.0, blue: 46.0 / 255.0, alpha: 1)
self.view.addSubview(canvas)
// timer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: canvas, selector: "randomMove", userInfo: nil, repeats: true)
}
// 5. 遵循協議就必須要實現協議中的方法(協議表約定)
func showMessage(canvas: Canvas, message: String) {
let alertController = UIAlertController(title: message, message: "", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "確定", style: .Default) { action in
// 此處通過尾隨閉包來定義點擊確定按鈕后要做什么
canvas.clearBoard()
}
alertController.addAction(okAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
// deinit在銷毀對象的時候調用
deinit {
// 銷毀計時器
timer?.invalidate()
}
}
結構體于類
import Foundation
class Student1 {
var name: String
var age: Int
var tel: String?
init(name: String, age: Int) {
self.name = name
self.age = age
}
func getOlder() {
age += 1
}
func study(courseName: String) {
print("\(name)正在學習.")
}
}
struct Student2 {
var name: String
var age: Int
func study(courseName: String) {
print("\(name)正在學習.")
}
// 區別3: 結構中的方法在默認情況下是不允許修改結構中的屬性除非加上mutating關鍵字
mutating func getOlder() {
age += 1
}
}
// 計算機的硬件由五大部件構成:
// 運算器、控制器、存儲器、輸入設備、輸出設備
// 運算器 + 控制器 => CPU (中央處理器)
// 存儲器 => 內存 (RAM - Random Access Memory)
// 程序員可以使用的內存大致分為五塊區域:
// 棧 (stack) - 我們定義的局部變量/臨時變量都是放在棧上
// - 特點: 小、快
// 堆 (heap) - 我們創建的對象都是放在堆上的
// - 特點: 大、慢
// 靜態區 (static area)
// - 數據段 - 全局量
// - 只讀數據段 - 常量
// - 代碼段 - 函數和方法
//var a: Int = 10
//var b = a
//b = 100
//print(a)
//
//var c: Double = 100
//var d = c
//d = 1.23456
//print(c)
//
//var e: String = "Hello"
//var f = e
//f = "Good"
//print(e)
//
//var g: Array<Int> = [1, 2, 3, 4, 5]
//var h = g
//h[0] = 1000
//print(g)
// 區別1: 結構的對象是值類型, 類的對象是引用類型
// 值類型在賦值的時候會在內存中進行對象的拷貝
// 引用類型在賦值的時候不會進行對象拷貝只是增加了一個引用
// 結論: 我們自定義新類型時優先考慮使用類而不是結構除非我們要定義的是一種底層的數據結構(保存其他數據的類型)
// 引用類型的類
//let stu1 = Student1(name: "阿郎", age: 35)
//var stu3 = stu1 // 此處內存中仍然只有一個學生對象
//stu3.name = "羅小號"
//stu3.age = 18
//print(stu1.name)
//print(stu1.age)
//
// 值類型的結構
// 區別2: 結構會自動生成初始化方法
//let stu2 = Student2(name: "阿郎", age: 35)
//var stu4 = stu2 // 此處內存中會復制一個新的學生對象
//stu4.name = "王大錘"
//stu4.age = 18
//print(stu2.name)
//print(stu2.age)
// 在Swift中同名函數只要參數列表不同是可以共存的 這個叫函數的重載
func changeName(inout name: String) {
name = "王大錘"
}
// 參數前面加var的做法在Swift 3中肯定是要廢掉的
func changeName(var stu: Student2) {
stu.name = "王大錘"
}
var name = "阿郎"
changeName(&name)
print(name)
var stu = Student2(name: "阿郎", age: 35)
changeName(stu)
print(stu.name)