Tetris/tetriscli/main.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()
}