随记
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)