195 lines
5.7 KiB
Swift
195 lines
5.7 KiB
Swift
//
|
|
// Shape.swift
|
|
// Privyet
|
|
//
|
|
// Created by Amy Bowersox on 5/24/20.
|
|
// Copyright © 2020 Erbosoft Metaverse Design Solutions. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SpriteKit
|
|
|
|
let NumOrientations: UInt32 = 4
|
|
|
|
enum Orientation: Int, CustomStringConvertible {
|
|
case Zero = 0, Ninety, OneEighty, TwoSeventy
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .Zero:
|
|
return "0"
|
|
case .Ninety:
|
|
return "90"
|
|
case .OneEighty:
|
|
return "180"
|
|
case .TwoSeventy:
|
|
return "270"
|
|
}
|
|
}
|
|
|
|
static func random() -> Orientation {
|
|
return Orientation(rawValue:Int(arc4random_uniform(NumOrientations)))!
|
|
}
|
|
|
|
static func rotate(orientation: Orientation, clockwise: Bool) -> Orientation {
|
|
var rotated = orientation.rawValue + (clockwise ? 1 : -1)
|
|
if rotated > Orientation.TwoSeventy.rawValue {
|
|
rotated = Orientation.Zero.rawValue
|
|
} else if rotated < 0 {
|
|
rotated = Orientation.TwoSeventy.rawValue
|
|
}
|
|
return Orientation(rawValue:rotated)!
|
|
}
|
|
}
|
|
|
|
// The number of total shape varieties
|
|
let NumShapeTypes: UInt32 = 7
|
|
|
|
// Shape indexes
|
|
let FirstBlockIdx: Int = 0
|
|
let SecondBlockIdx: Int = 1
|
|
let ThirdBlockIdx: Int = 2
|
|
let FourthBlockIdx: Int = 3
|
|
|
|
class Shape: Hashable, CustomStringConvertible {
|
|
// The color of the shape
|
|
let color: BlockColor
|
|
|
|
// The blocks comprising the shape
|
|
var blocks = Array<Block>()
|
|
// The current orientation of the shape
|
|
var orientation: Orientation
|
|
// The column and row representing the shape's anchor point
|
|
var column, row: Int
|
|
|
|
// Required overrides
|
|
|
|
// Subclasses must override this property
|
|
var blockRowColumnPositions: [Orientation: Array<(columnDiff: Int, rowDiff: Int)>] {
|
|
return [:]
|
|
}
|
|
|
|
// Subclasses must override this property
|
|
var bottomBlocksForOrientations: [Orientation: Array<Block>] {
|
|
return [:]
|
|
}
|
|
|
|
var bottomBlocks: Array<Block> {
|
|
guard let bottomBlocks = bottomBlocksForOrientations[orientation] else {
|
|
return []
|
|
}
|
|
return bottomBlocks
|
|
}
|
|
|
|
// Equatable
|
|
static func == (lhs: Shape, rhs: Shape) -> Bool {
|
|
return lhs.row == rhs.row && lhs.column == rhs.column
|
|
}
|
|
|
|
// Hashable
|
|
func hash(into hasher: inout Hasher) {
|
|
blocks.forEach {b in
|
|
hasher.combine(b.hashValue)
|
|
}
|
|
}
|
|
|
|
// CustomStringConvertible
|
|
var description: String {
|
|
return "\(color) block facing \(orientation): \(blocks[FirstBlockIdx]), \(blocks[SecondBlockIdx]), \(blocks[ThirdBlockIdx]), \(blocks[FourthBlockIdx])"
|
|
}
|
|
|
|
init(column: Int, row: Int, color: BlockColor, orientation: Orientation) {
|
|
self.color = color
|
|
self.column = column
|
|
self.row = row
|
|
self.orientation = orientation
|
|
initializeBlocks()
|
|
}
|
|
|
|
convenience init(column: Int, row: Int) {
|
|
self.init(column: column, row: row, color: BlockColor.random(), orientation: Orientation.random())
|
|
}
|
|
|
|
final func initializeBlocks() {
|
|
guard let blockRowColumnTranslations = blockRowColumnPositions[orientation] else {
|
|
return
|
|
}
|
|
|
|
blocks = blockRowColumnTranslations.map { (diff) -> Block in
|
|
return Block(column: column + diff.columnDiff, row: row + diff.rowDiff, color: color)
|
|
}
|
|
}
|
|
|
|
final func rotateBlocks(orientation: Orientation) {
|
|
guard let blockRowColumnTranslation: Array<(columnDiff: Int, rowDiff: Int)> = blockRowColumnPositions[orientation] else {
|
|
return
|
|
}
|
|
for (idx, diff) in blockRowColumnTranslation.enumerated() {
|
|
blocks[idx].column = column + diff.columnDiff
|
|
blocks[idx].row = row + diff.rowDiff
|
|
}
|
|
}
|
|
|
|
final func rotateClockwise() {
|
|
let newOrientation = Orientation.rotate(orientation: orientation, clockwise: true)
|
|
rotateBlocks(orientation: newOrientation)
|
|
orientation = newOrientation
|
|
}
|
|
|
|
final func rotateCounterClockwise() {
|
|
let newOrientation = Orientation.rotate(orientation: orientation, clockwise: false)
|
|
rotateBlocks(orientation: newOrientation)
|
|
orientation = newOrientation
|
|
}
|
|
|
|
final func lowerShapeByOneRow() {
|
|
shiftBy(columns: 0, rows: 1)
|
|
}
|
|
|
|
final func raiseShapeByOneRow() {
|
|
shiftBy(columns: 0, rows: -1)
|
|
}
|
|
|
|
final func shiftRightByOneColumn() {
|
|
shiftBy(columns: 1, rows: 0)
|
|
}
|
|
|
|
final func shiftLeftByOneColumn() {
|
|
shiftBy(columns: -1, rows: 0)
|
|
}
|
|
|
|
final func shiftBy(columns: Int, rows: Int) {
|
|
self.column += columns
|
|
self.row += rows
|
|
for block in blocks {
|
|
block.column += columns
|
|
block.row += rows
|
|
}
|
|
}
|
|
|
|
final func moveTo(column: Int, row: Int) {
|
|
self.column = column
|
|
self.row = row
|
|
rotateBlocks(orientation: orientation)
|
|
}
|
|
|
|
final class func random(startingColumn: Int, startingRow: Int) -> Shape {
|
|
switch Int(arc4random_uniform(NumShapeTypes)) {
|
|
case 0:
|
|
return SquareShape(column: startingColumn, row: startingRow)
|
|
case 1:
|
|
return LineShape(column: startingColumn, row: startingRow)
|
|
case 2:
|
|
return TShape(column: startingColumn, row: startingRow)
|
|
case 3:
|
|
return LShape(column: startingColumn, row: startingRow)
|
|
case 4:
|
|
return JShape(column: startingColumn, row: startingRow)
|
|
case 5:
|
|
return SShape(column: startingColumn, row: startingRow)
|
|
default:
|
|
return ZShape(column: startingColumn, row: startingRow)
|
|
}
|
|
}
|
|
}
|