privyet/Privyet/Shape.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)
}
}
}