132 lines
4.6 KiB
Swift
132 lines
4.6 KiB
Swift
//
|
|
// main.swift
|
|
// tetriscli
|
|
//
|
|
// Created by Shadowfacts on 10/13/19.
|
|
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
class TwoDimString: CustomStringConvertible {
|
|
var width: Int
|
|
var height: Int
|
|
var rows: [String]
|
|
|
|
var description: String {
|
|
return rows.joined(separator: "\n")
|
|
}
|
|
|
|
init(width: Int, height: Int) {
|
|
self.width = width
|
|
self.height = height
|
|
self.rows = []
|
|
|
|
let empty = String(repeating: " ", count: width)
|
|
for _ in 1...height {
|
|
rows.append(empty)
|
|
}
|
|
}
|
|
|
|
subscript(column: Int, row: Int) -> Character {
|
|
get {
|
|
guard column >= 0 && column < width,
|
|
row >= 0 && row < height else { fatalError("Out of bounds position \(column), \(row) for TwoDimString(width: \(width), height: \(height))") }
|
|
let rowStr = rows[row]
|
|
return rowStr[rowStr.index(rowStr.startIndex, offsetBy: column)]
|
|
}
|
|
set {
|
|
guard column >= 0 && column < width,
|
|
row >= 0 && row < height else { fatalError("Out of bounds position \(column), \(row) for TwoDimString(width: \(width), height: \(height))") }
|
|
let rowStr = rows[row]
|
|
|
|
rows[row] = String(rowStr.prefix(column)) + String(newValue) + String(rowStr.dropFirst(column + 1))
|
|
}
|
|
}
|
|
|
|
func setRow(_ row: Int, to str: String) {
|
|
guard row >= 0 && row < height else { fatalError("Can't set row \(row) for TwoDimString(width: \(width), height: \(height))") }
|
|
guard str.count == width else { fatalError("Can't set row with count \(str.count) for TwoDimString(width: \(width), height: \(height))") }
|
|
|
|
rows[row] = str
|
|
}
|
|
|
|
func setColumn(_ col: Int, to str: String) {
|
|
guard col >= 0 && col < width else { fatalError("Can't set column \(col) for TwoDimString(width: \(width), height: \(height))") }
|
|
guard str.count == height else { fatalError("Can't set row with count \(str.count) for TwoDimString(width: \(width), height: \(height))") }
|
|
|
|
for row in 0..<height {
|
|
self[col, row] = str[str.index(str.startIndex, offsetBy: row)]
|
|
}
|
|
}
|
|
|
|
func setSubString(at column: Int, row: Int, string: TwoDimString) {
|
|
guard column >= 0 && column + string.width <= width,
|
|
row >= 0 && row + string.height <= height else { fatalError("Can't set TwoDimString(width: \(string.width), height: \(string.height)) at (\(column), \(row))") }
|
|
|
|
for subCol in 0..<string.width {
|
|
for subRow in 0..<string.height {
|
|
self[subCol + column, subRow + row] = string[subCol, subRow]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TwoDimString {
|
|
convenience init(controller: GameController) {
|
|
self.init(width: controller.width + 2, height: controller.height + 2)
|
|
|
|
setRow(0, to: "+" + String(repeating: "-", count: controller.width) + "+")
|
|
setRow(controller.height + 1, to: "+" + String(repeating: "-", count: controller.width) + "+")
|
|
setColumn(0, to: "+" + String(repeating: "|", count: controller.height) + "+")
|
|
setColumn(controller.width + 1, to: "+" + String(repeating: "|", count: controller.height) + "+")
|
|
|
|
for y in 0..<controller.height {
|
|
for x in 0..<controller.width where controller.board.get(tile: (x, y)) {
|
|
self[x + 1, y + 1] = "X"
|
|
}
|
|
}
|
|
|
|
if let currentPiece = controller.currentPiece {
|
|
let (left, top) = currentPiece.topLeft
|
|
for y in 0..<currentPiece.tiles.count where y + top + 1 >= 0 && y + top + 1 < height {
|
|
for x in 0..<currentPiece.tiles.first!.count where x + left + 1 >= 0 && x + left + 1 < width {
|
|
self[x + left + 1, y + top + 1] = currentPiece.tiles[y][x] ? "X" : "-"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let controller = GameController()
|
|
controller.currentPiece = GamePiece(tetromino: .l)
|
|
|
|
func readMove() {
|
|
print(TwoDimString(controller: controller))
|
|
print("Move: ", terminator: "")
|
|
let input = readLine()!.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
switch input {
|
|
case "", "s", "step":
|
|
controller.step()
|
|
case "cw":
|
|
controller.rotate(direction: .clockwise)
|
|
case "ccw":
|
|
controller.rotate(direction: .counterClockwise)
|
|
case "l", "left":
|
|
controller.left()
|
|
case "r", "right":
|
|
controller.right()
|
|
case "drop":
|
|
controller.drop()
|
|
case "hold":
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
while true {
|
|
readMove()
|
|
}
|