diff --git a/Sources/AtCoderSupport/Array2D.swift b/Sources/AtCoderSupport/Array2D.swift index 195ccb7..313ce29 100644 --- a/Sources/AtCoderSupport/Array2D.swift +++ b/Sources/AtCoderSupport/Array2D.swift @@ -1,40 +1,76 @@ struct Array2D: Sequence, CustomStringConvertible { - let width: Int - let height: Int + typealias Coord = (row: Int, col: Int) + let quadDirectionUnitVec = [(0, 1), (-1, 0), (0, -1), (1, 0)] + let octaDirectionUnitVec = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)] + + private(set) var originWidth: Int + private(set) var originHeight: Int + var width: Int { + rotation.isMultiple(of: 2) ? originWidth : originHeight + } + var height: Int { + rotation.isMultiple(of: 2) ? originHeight : originWidth + } private(set) var elements: [Element] + private(set) var rotation: Int = 0 let outside: Element? - init(width: Int, height: Int, elements: [Element], outside: Element? = nil) { + init(height: Int, width: Int, elements: [Element], outside: Element? = nil) { precondition(elements.count == width * height) - self.width = width - self.height = height + self.originWidth = width + self.originHeight = height self.elements = elements self.outside = outside } - init(width: Int, height: Int, element: Element, outside: Element? = nil) { - self.init(width: width, height: height, elements: [Element](repeating: element, count: width * height), outside: outside) + init(height: Int, width: Int, element: Element, outside: Element? = nil) { + self.init(height: height, width: width, elements: [Element](repeating: element, count: width * height), outside: outside) } var count: Int { elements.count } - var xRange: Range { 0 ..< width } - var yRange: Range { 0 ..< height } - private func indexAt(x: Int, y: Int) -> Int? { - guard xRange.contains(x) else { return nil } - guard yRange.contains(y) else { return nil } - return y * width + x - } - subscript(x: Int, y: Int) -> Element { + var originRowRange: Range { 0 ..< originHeight } + var originColRange: Range { 0 ..< originWidth } + private func boardContains(coord: Coord) -> Bool { originRowRange.contains(coord.row) && originColRange.contains(coord.col) } + private func boardNotContains(coord: Coord) -> Bool { !boardContains(coord: coord) } + private func indexOriginAt(r: Int, c: Int) -> Int? { + guard originRowRange.contains(r) else { return nil } + guard originColRange.contains(c) else { return nil } + return r * originWidth + c + } + private func indexAt(r: Int, c: Int) -> Int? { + switch rotation { + case 0: + return indexOriginAt(r: r, c: c) + case 1: + guard originColRange.contains(r) else { return nil } + guard originRowRange.contains(c) else { return nil } + return indexOriginAt(r: originHeight - 1 - c, c: r) + case 2: + return indexOriginAt(r: originHeight - 1 - r, c: originWidth - 1 - c) + case 3: + guard originColRange.contains(r) else { return nil } + guard originRowRange.contains(c) else { return nil } + return indexOriginAt(r: c, c: originWidth - 1 - r) + default: + fatalError("illegal rotation value: \(rotation)") + } + } + subscript(r: Int, c: Int) -> Element { get { - guard let i = indexAt(x: x, y: y) else { return outside! } + guard let i = indexAt(r: r, c: c) else { + guard let os = outside else { + fatalError("(r, c)=(\(r),\(c)) is outside and the outside value of Array2D is not defined.") + } + return os + } return elements[i] } set { - guard let i = indexAt(x: x, y: y) else { + guard let i = indexAt(r: r, c: c) else { precondition(outside != nil) return } elements[i] = newValue } } - subscript(position: (Int, Int)) -> Element { + subscript(position: Coord) -> Element { get { self[position.0, position.1] } set { self[position.0, position.1] = newValue } } @@ -42,34 +78,137 @@ struct Array2D: Sequence, CustomStringConvertible { elements.makeIterator() } func map(_ transform: (Element) throws -> T) rethrows -> Array2D { - try Array2D(width: width, height: height, elements: elements.map(transform)) + try Array2D(height: originHeight, width: originWidth, elements: elements.map(transform)) + } + func neighbours(around now: Coord, ignoreOutside: Bool = true) -> [Coord] { + var res = [Coord]() + for i in 0..<4 { + let nr = now.row + quadDirectionUnitVec[i].0 + let nc = now.col + quadDirectionUnitVec[i].1 + if ignoreOutside && boardNotContains(coord: (row: nr, col: nc)) { + continue + } + res.append((nr, nc)) + } + return res + } + func surroundings(around now: Coord, ignoreOutside: Bool = true) -> [Coord] { + var res = [Coord]() + for i in 0..<8 { + let nr = now.row + octaDirectionUnitVec[i].0 + let nc = now.col + octaDirectionUnitVec[i].1 + if ignoreOutside { + if indexAt(r: nr, c: nc) == nil { + continue + } + } + res.append((nr, nc)) + } + return res + } + func locationList(condition: (Element) -> Bool) -> [Coord] { + var res = [Coord]() + for (i, e) in elements.enumerated() { + guard condition(e) else { continue } + res.append((row: i / originWidth, i % originWidth)) + } + return res + } + mutating func rotate(count: Int = 1) { + rotation += count + rotation = rotation % 4 + } + mutating func resetAndRotate(count: Int) { + rotation = count % 4 } var description: String { var result: String = "" - for y in yRange { - for x in xRange { - if x > 0 { + for r in originRowRange { + for c in originColRange { + if c > 0 { result.append(" ") } - result.append("\(self[x, y])") + result.append("\(self[r, c])") } result.append("\n") } return result } } +extension Array2D where Element: Equatable { + func trimmed(removing e: Element) -> Array2D { + let tb = trimmedBoard(removing: e) + return Array2D(height: tb.height, width: tb.width, elements: tb.elements) + } + mutating func trim(removing e: Element) { + let tb = trimmedBoard(removing: e) + self.elements = tb.elements + self.originWidth = tb.width + self.originHeight = tb.height + } + private func trimmedBoard(removing e: Element) -> (elements: [Element], width: Int, height: Int) { + var left = width - 1, right = 0, top = height - 1, bottom = 0 + // Swift.min と Collection.min が衝突してて Linux 環境上での世話がめんどいので車輪を再発明 + func vmin(_ a: Int, _ b: Int) -> Int { a < b ? a : b } + func vmax(_ a: Int, _ b: Int) -> Int { a > b ? a : b } + for r in 0.. 0 { + for r in originRowRange { + for c in originColRange { + if c > 0 { result.append(" ") } - result.append(self[x, y].description) + result.append(self[r, c].description) } result.append("\n") } return result } } +extension Array2D where Element == Character { + init(height: Int, width: Int, stringArray: [String], outside: Element? = nil) { + let array = stringArray.map { s in Array(s) }.flatMap { $0 } + self.init(height: height, width: width, elements: array, outside: outside) + } + func seek(word: String) -> [Coord]? { + let wcs = Array(word) + for row in 0..= 0 { self.n = m } else { self.n = m + mod } } + init(integerLiteral value: IntegerLiteralType) { n = value } + var description: String { String(n) } + static var zero = Zn(0) + static var one = Zn(1) + static prefix func - (value: Self) -> Self { Zn(value.n == 0 ? 0 : mod - value.n) } + static func + (lhs: Self, rhs: Self) -> Self { let n = lhs.n + rhs.n; return Zn(n < mod ? n : n - mod) } + static func + (lhs: Self, rhs: Int) -> Self { lhs + Zn(rhs) } + static func + (lhs: Int, rhs: Self) -> Self { Zn(lhs) + rhs } + static func - (lhs: Self, rhs: Self) -> Self { let n = lhs.n - rhs.n; return Zn(n >= 0 ? n : n + mod) } + static func - (lhs: Self, rhs: Int) -> Self { lhs - Zn(rhs) } + static func - (lhs: Int, rhs: Self) -> Self { Zn(lhs) - rhs } + static func * (lhs: Self, rhs: Self) -> Self { Zn((lhs.n * rhs.n) % mod) } + static func * (lhs: Self, rhs: Int) -> Self { lhs * Zn(rhs) } + static func * (lhs: Int, rhs: Self) -> Self { Zn(lhs) * rhs } + static func / (lhs: Self, rhs: Self) -> Self { lhs * rhs.inverse } + static func / (lhs: Int, rhs: Self) -> Self { Zn(lhs) * rhs.inverse } + static func / (lhs: Self, rhs: Int) -> Self { lhs * Zn(rhs).inverse } + static func += (lhs: inout Self, rhs: Self) { lhs = lhs + rhs } + static func += (lhs: inout Self, rhs: Int) { lhs = lhs + Zn(rhs) } + static func -= (lhs: inout Self, rhs: Self) { lhs = lhs - rhs } + static func -= (lhs: inout Self, rhs: Int) { lhs = lhs - Zn(rhs) } + static func *= (lhs: inout Self, rhs: Self) { lhs = lhs * rhs } + static func *= (lhs: inout Self, rhs: Int) { lhs = lhs * Zn(rhs) } + static func /= (lhs: inout Self, rhs: Self) { lhs = lhs / rhs } + static func /= (lhs: inout Self, rhs: Int) { lhs = lhs / Zn(rhs) } + static func ** (lhs: Self, rhs: Int) -> Self { lhs.pow(rhs) } + + func pow(_ n: Int) -> Self { + if n < 0 { return inverse.pow(-n) } + var result: Zn = 1 + var x: Zn = self + var n = n + while n > 0 { + if n & 1 == 1 { result *= x } + x *= x + n >>= 1 + } + return result + } + var inverse: Self { pow(mod - 2) } +} diff --git a/Tests/AtCoderSupportTests/Array2DTests.swift b/Tests/AtCoderSupportTests/Array2DTests.swift index aee0216..d1471e3 100644 --- a/Tests/AtCoderSupportTests/Array2DTests.swift +++ b/Tests/AtCoderSupportTests/Array2DTests.swift @@ -4,21 +4,21 @@ import XCTest final class Array2DTests: XCTestCase { func testInit() { do { - let a: Array2D = .init(width: 3, height: 2, element: 42) + let a: Array2D = .init(height: 2, width: 3, element: 42) XCTAssertEqual(a[0, 0], 42) - XCTAssertEqual(a[1, 0], 42) - XCTAssertEqual(a[2, 0], 42) - XCTAssertEqual(a[0, 1], 42) + XCTAssertEqual(a[0, 2], 42) + + XCTAssertEqual(a[1, 0], 42) XCTAssertEqual(a[1, 1], 42) - XCTAssertEqual(a[2, 1], 42) + XCTAssertEqual(a[1, 2], 42) } } func testCount() { do { - let a: Array2D = .init(width: 4, height: 3, element: 42) + let a: Array2D = .init(height: 3, width: 4, element: 42) let r = a.count XCTAssertEqual(r, 12) } @@ -26,118 +26,508 @@ final class Array2DTests: XCTestCase { func testSubscriptGet() { do { - let a: Array2D = .init(width: 4, height: 3, elements: [ + let a: Array2D = .init(height: 3, width: 4, elements: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ]) XCTAssertEqual(a[0, 0], 1) - XCTAssertEqual(a[1, 0], 2) - XCTAssertEqual(a[2, 0], 3) - XCTAssertEqual(a[3, 0], 4) + XCTAssertEqual(a[0, 1], 2) + XCTAssertEqual(a[0, 2], 3) + XCTAssertEqual(a[0, 3], 4) - XCTAssertEqual(a[0, 1], 5) + XCTAssertEqual(a[1, 0], 5) XCTAssertEqual(a[1, 1], 6) - XCTAssertEqual(a[2, 1], 7) - XCTAssertEqual(a[3, 1], 8) + XCTAssertEqual(a[1, 2], 7) + XCTAssertEqual(a[1, 3], 8) - XCTAssertEqual(a[0, 2], 9) - XCTAssertEqual(a[1, 2], 10) + XCTAssertEqual(a[2, 0], 9) + XCTAssertEqual(a[2, 1], 10) XCTAssertEqual(a[2, 2], 11) - XCTAssertEqual(a[3, 2], 12) + XCTAssertEqual(a[2, 3], 12) } do { - let a: Array2D = .init(width: 4, height: 3, elements: [ + let a: Array2D = .init(height: 3, width: 4, elements: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ], outside: -1) XCTAssertEqual(a[0, 0], 1) - XCTAssertEqual(a[1, 0], 2) - XCTAssertEqual(a[2, 0], 3) - XCTAssertEqual(a[3, 0], 4) + XCTAssertEqual(a[0, 1], 2) + XCTAssertEqual(a[0, 2], 3) + XCTAssertEqual(a[0, 3], 4) - XCTAssertEqual(a[0, 1], 5) + XCTAssertEqual(a[1, 0], 5) XCTAssertEqual(a[1, 1], 6) - XCTAssertEqual(a[2, 1], 7) - XCTAssertEqual(a[3, 1], 8) + XCTAssertEqual(a[1, 2], 7) + XCTAssertEqual(a[1, 3], 8) - XCTAssertEqual(a[0, 2], 9) - XCTAssertEqual(a[1, 2], 10) + XCTAssertEqual(a[2, 0], 9) + XCTAssertEqual(a[2, 1], 10) XCTAssertEqual(a[2, 2], 11) - XCTAssertEqual(a[3, 2], 12) + XCTAssertEqual(a[2, 3], 12) XCTAssertEqual(a[-1, -1], -1) - XCTAssertEqual(a[4, -1], -1) - XCTAssertEqual(a[-1, 3], -1) - XCTAssertEqual(a[4, 3], -1) + XCTAssertEqual(a[-1, 4], -1) + XCTAssertEqual(a[3, -1], -1) + XCTAssertEqual(a[3, 4], -1) - XCTAssertEqual(a[-1, 0], -1) XCTAssertEqual(a[0, -1], -1) - XCTAssertEqual(a[4, 0], -1) - XCTAssertEqual(a[0, 3], -1) + XCTAssertEqual(a[-1, 0], -1) + XCTAssertEqual(a[0, 4], -1) + XCTAssertEqual(a[3, 0], -1) } } func testSubscriptSet() { do { - var a: Array2D = .init(width: 4, height: 3, elements: [ + var a: Array2D = .init(height: 3, width: 4, elements: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ], outside: -1) a[0, 0] = 100 - a[1, 0] = 200 - a[2, 0] = 300 - a[3, 0] = 400 + a[0, 1] = 200 + a[0, 2] = 300 + a[0, 3] = 400 - a[0, 1] = 500 + a[1, 0] = 500 a[1, 1] = 600 - a[2, 1] = 700 - a[3, 1] = 800 + a[1, 2] = 700 + a[1, 3] = 800 - a[0, 2] = 900 - a[1, 2] = 1000 + a[2, 0] = 900 + a[2, 1] = 1000 a[2, 2] = 1100 - a[3, 2] = 1200 + a[2, 3] = 1200 a[-1, -1] = -100 - a[4, -1] = -100 - a[-1, 3] = -100 - a[4, 3] = -100 + a[-1, 4] = -100 + a[3, -1] = -100 + a[3, 4] = -100 - a[-1, 0] = -100 - a[0, -1] = -100 - a[4, 0] = -100 - a[0, 3] = -100 + a[0, -1] = -123 + a[-1, 0] = -234 + a[0, 4] = -345 + a[3, 0] = -456 XCTAssertEqual(a[0, 0], 100) - XCTAssertEqual(a[1, 0], 200) - XCTAssertEqual(a[2, 0], 300) - XCTAssertEqual(a[3, 0], 400) + XCTAssertEqual(a[0, 1], 200) + XCTAssertEqual(a[0, 2], 300) + XCTAssertEqual(a[0, 3], 400) - XCTAssertEqual(a[0, 1], 500) + XCTAssertEqual(a[1, 0], 500) XCTAssertEqual(a[1, 1], 600) - XCTAssertEqual(a[2, 1], 700) - XCTAssertEqual(a[3, 1], 800) + XCTAssertEqual(a[1, 2], 700) + XCTAssertEqual(a[1, 3], 800) - XCTAssertEqual(a[0, 2], 900) - XCTAssertEqual(a[1, 2], 1000) + XCTAssertEqual(a[2, 0], 900) + XCTAssertEqual(a[2, 1], 1000) XCTAssertEqual(a[2, 2], 1100) - XCTAssertEqual(a[3, 2], 1200) + XCTAssertEqual(a[2, 3], 1200) XCTAssertEqual(a[-1, -1], -1) - XCTAssertEqual(a[4, -1], -1) - XCTAssertEqual(a[-1, 3], -1) - XCTAssertEqual(a[4, 3], -1) + XCTAssertEqual(a[-1, 4], -1) + XCTAssertEqual(a[3, -1], -1) + XCTAssertEqual(a[3, 4], -1) - XCTAssertEqual(a[-1, 0], -1) XCTAssertEqual(a[0, -1], -1) - XCTAssertEqual(a[4, 0], -1) - XCTAssertEqual(a[0, 3], -1) + XCTAssertEqual(a[-1, 0], -1) + XCTAssertEqual(a[0, 4], -1) + XCTAssertEqual(a[3, 0], -1) + } + } + + func testNeighbourCoord() { + let target = [ + "0*0", "0*1", "0*2", "0*3", + "1*0", "1*1", "1*2", "1*3", + "2*0", "2*1", "2*2", "2*3", + "3*0", "3*1", "3*2", "3*3", + "4*0", "4*1", "4*2", "4*3" + ] + let a: Array2D = .init(height: 5, width: 4, elements: target) + do { + let neighbourList = a.neighbours(around: (1, 1)) + let expectedList = [(1, 2), (0, 1), (1, 0), (2, 1)] + for (i, (r, c)) in neighbourList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let neighbourList = a.neighbours(around: (0, 1)) + let expectedList = [(0, 2), (0, 0), (1, 1)] + for (i, (r, c)) in neighbourList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let neighbourList = a.neighbours(around: (0, 0)) + let expectedList = [(0, 1), (1, 0)] + for (i, (r, c)) in neighbourList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let neighbourList = a.neighbours(around: (0, 0), ignoreOutside: false) + let expectedList = [(0, 1), (-1, 0), (0, -1), (1, 0)] + for (i, (r, c)) in neighbourList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + } + + func testSurroundimgsCoord() { + let target = [ + "0*0", "0*1", "0*2", "0*3", + "1*0", "1*1", "1*2", "1*3", + "2*0", "2*1", "2*2", "2*3", + "3*0", "3*1", "3*2", "3*3", + "4*0", "4*1", "4*2", "4*3" + ] + let a: Array2D = .init(height: 5, width: 4, elements: target) + do { + let surroundList = a.surroundings(around: (1, 1)) + let expectedList = [(1, 2), (0, 2), (0, 1), (0, 0), (1, 0), (2, 0), (2, 1), (2, 2)] + for (i, (r, c)) in surroundList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let surroundList = a.surroundings(around: (0, 1)) + let expectedList = [(0, 2), (0, 0), (1, 0), (1, 1), (1, 2)] + for (i, (r, c)) in surroundList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let surroundList = a.surroundings(around: (0, 0)) + let expectedList = [(0, 1), (1, 0), (1, 1)] + for (i, (r, c)) in surroundList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + do { + let surroundList = a.surroundings(around: (0, 0), ignoreOutside: false) + let expectedList = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)] + for (i, (r, c)) in surroundList.enumerated() { + XCTAssertEqual(r, expectedList[i].0) + XCTAssertEqual(c, expectedList[i].1) + } + } + } + + func testLocationList() { + let strs = [ + "........", + "..*.....", + "........", + ".*......", + ".....*..", + "........" + ] + let a: Array2D = .init(height: strs.count, width: strs[0].count, stringArray: strs) + do { + let list = a.locationList(condition: { $0 == "*" }) + XCTAssertTrue(list.contains { row, col in row == 1 && col == 2 }) + XCTAssertTrue(list.contains { row, col in row == 3 && col == 1 }) + XCTAssertTrue(list.contains { row, col in row == 4 && col == 5 }) + } + do { + let list = a.locationList(condition: { $0 == "X" }) + XCTAssertTrue(list.isEmpty) + } + } + + func testRotatedSize() { + let target = [Bool](repeating: false, count: 28) + var a: Array2D = .init(height: 7, width: 4, elements: target) + XCTAssertEqual(a.width, 4) + a.rotate() + XCTAssertEqual(a.width, 7) + a.rotate() + XCTAssertEqual(a.width, 4) + } + + func testRotateOnce() { + let target = [ + "0_0", "0_1", "0_2", "0_3", + "1_0", "1_1", "1_2", "1_3", + "2_0", "2_1", "2_2", "2_3", + "3_0", "3_1", "3_2", "3_3", + "4_0", "4_1", "4_2", "4_3", + "5_0", "5_1", "5_2", "5_3", + "6_0", "6_1", "6_2", "6_3" + ] + var a: Array2D = .init(height: 7, width: 4, elements: target) + a.rotate() + + XCTAssertEqual(a[0, 0], "6_0") + XCTAssertEqual(a[0, 1], "5_0") + XCTAssertEqual(a[0, 2], "4_0") + XCTAssertEqual(a[0, 3], "3_0") + XCTAssertEqual(a[0, 4], "2_0") + XCTAssertEqual(a[0, 5], "1_0") + XCTAssertEqual(a[0, 6], "0_0") + + XCTAssertEqual(a[1, 0], "6_1") + XCTAssertEqual(a[1, 1], "5_1") + XCTAssertEqual(a[1, 2], "4_1") + XCTAssertEqual(a[1, 3], "3_1") + XCTAssertEqual(a[1, 4], "2_1") + XCTAssertEqual(a[1, 5], "1_1") + XCTAssertEqual(a[1, 6], "0_1") + + XCTAssertEqual(a[2, 0], "6_2") + XCTAssertEqual(a[2, 1], "5_2") + XCTAssertEqual(a[2, 2], "4_2") + XCTAssertEqual(a[2, 3], "3_2") + XCTAssertEqual(a[2, 4], "2_2") + XCTAssertEqual(a[2, 5], "1_2") + XCTAssertEqual(a[2, 6], "0_2") + + XCTAssertEqual(a[3, 0], "6_3") + XCTAssertEqual(a[3, 1], "5_3") + XCTAssertEqual(a[3, 2], "4_3") + XCTAssertEqual(a[3, 3], "3_3") + XCTAssertEqual(a[3, 4], "2_3") + XCTAssertEqual(a[3, 5], "1_3") + XCTAssertEqual(a[3, 6], "0_3") + } + + func testRotateTwice() { + let target = [ + "0_0", "0_1", "0_2", "0_3", + "1_0", "1_1", "1_2", "1_3", + "2_0", "2_1", "2_2", "2_3", + "3_0", "3_1", "3_2", "3_3", + "4_0", "4_1", "4_2", "4_3", + "5_0", "5_1", "5_2", "5_3", + "6_0", "6_1", "6_2", "6_3" + ] + var a: Array2D = .init(height: 7, width: 4, elements: target) + a.rotate(count: 2) + + XCTAssertEqual(a[0, 0], "6_3") + XCTAssertEqual(a[0, 1], "6_2") + XCTAssertEqual(a[0, 2], "6_1") + XCTAssertEqual(a[0, 3], "6_0") + + XCTAssertEqual(a[1, 0], "5_3") + XCTAssertEqual(a[1, 1], "5_2") + XCTAssertEqual(a[1, 2], "5_1") + XCTAssertEqual(a[1, 3], "5_0") + + XCTAssertEqual(a[2, 0], "4_3") + XCTAssertEqual(a[2, 1], "4_2") + XCTAssertEqual(a[2, 2], "4_1") + XCTAssertEqual(a[2, 3], "4_0") + + XCTAssertEqual(a[3, 0], "3_3") + XCTAssertEqual(a[3, 1], "3_2") + XCTAssertEqual(a[3, 2], "3_1") + XCTAssertEqual(a[3, 3], "3_0") + + XCTAssertEqual(a[4, 0], "2_3") + XCTAssertEqual(a[4, 1], "2_2") + XCTAssertEqual(a[4, 2], "2_1") + XCTAssertEqual(a[4, 3], "2_0") + + XCTAssertEqual(a[5, 0], "1_3") + XCTAssertEqual(a[5, 1], "1_2") + XCTAssertEqual(a[5, 2], "1_1") + XCTAssertEqual(a[5, 3], "1_0") + + XCTAssertEqual(a[6, 0], "0_3") + XCTAssertEqual(a[6, 1], "0_2") + XCTAssertEqual(a[6, 2], "0_1") + XCTAssertEqual(a[6, 3], "0_0") + } + + func testRotateThreeTimes() { + let target = [ + "0_0", "0_1", "0_2", "0_3", + "1_0", "1_1", "1_2", "1_3", + "2_0", "2_1", "2_2", "2_3", + "3_0", "3_1", "3_2", "3_3", + "4_0", "4_1", "4_2", "4_3", + "5_0", "5_1", "5_2", "5_3", + "6_0", "6_1", "6_2", "6_3" + ] + var a: Array2D = .init(height: 7, width: 4, elements: target) + a.rotate(count: 3) + + XCTAssertEqual(a[0, 0], "0_3") + XCTAssertEqual(a[0, 1], "1_3") + XCTAssertEqual(a[0, 2], "2_3") + XCTAssertEqual(a[0, 3], "3_3") + XCTAssertEqual(a[0, 4], "4_3") + XCTAssertEqual(a[0, 5], "5_3") + XCTAssertEqual(a[0, 6], "6_3") + + XCTAssertEqual(a[1, 0], "0_2") + XCTAssertEqual(a[1, 1], "1_2") + XCTAssertEqual(a[1, 2], "2_2") + XCTAssertEqual(a[1, 3], "3_2") + XCTAssertEqual(a[1, 4], "4_2") + XCTAssertEqual(a[1, 5], "5_2") + XCTAssertEqual(a[1, 6], "6_2") + + XCTAssertEqual(a[2, 0], "0_1") + XCTAssertEqual(a[2, 1], "1_1") + XCTAssertEqual(a[2, 2], "2_1") + XCTAssertEqual(a[2, 3], "3_1") + XCTAssertEqual(a[2, 4], "4_1") + XCTAssertEqual(a[2, 5], "5_1") + XCTAssertEqual(a[2, 6], "6_1") + + XCTAssertEqual(a[3, 0], "0_0") + XCTAssertEqual(a[3, 1], "1_0") + XCTAssertEqual(a[3, 2], "2_0") + XCTAssertEqual(a[3, 3], "3_0") + XCTAssertEqual(a[3, 4], "4_0") + XCTAssertEqual(a[3, 5], "5_0") + XCTAssertEqual(a[3, 6], "6_0") + } + + func testRotateFourTimes() { + let target = [ + "0_0", "0_1", "0_2", "0_3", + "1_0", "1_1", "1_2", "1_3", + "2_0", "2_1", "2_2", "2_3", + "3_0", "3_1", "3_2", "3_3", + "4_0", "4_1", "4_2", "4_3", + "5_0", "5_1", "5_2", "5_3", + "6_0", "6_1", "6_2", "6_3" + ] + var a: Array2D = .init(height: 7, width: 4, elements: target) + a.rotate(count: 4) + for r in 0..<7 { + for c in 0..<4 { + XCTAssertEqual(a[r, c], "\(r)_\(c)") + } + } + } + + func testResetAndRotate() { + let target = [ + "0_0", "0_1", "0_2", "0_3", + "1_0", "1_1", "1_2", "1_3", + "2_0", "2_1", "2_2", "2_3", + "3_0", "3_1", "3_2", "3_3", + "4_0", "4_1", "4_2", "4_3", + "5_0", "5_1", "5_2", "5_3", + "6_0", "6_1", "6_2", "6_3" + ] + var a: Array2D = .init(height: 7, width: 4, elements: target) + a.rotate(count: 2) + a.resetAndRotate(count: 1) + + XCTAssertEqual(a[0, 0], "6_0") + XCTAssertEqual(a[0, 1], "5_0") + XCTAssertEqual(a[0, 2], "4_0") + XCTAssertEqual(a[0, 3], "3_0") + XCTAssertEqual(a[0, 4], "2_0") + XCTAssertEqual(a[0, 5], "1_0") + XCTAssertEqual(a[0, 6], "0_0") + + XCTAssertEqual(a[1, 0], "6_1") + XCTAssertEqual(a[1, 1], "5_1") + XCTAssertEqual(a[1, 2], "4_1") + XCTAssertEqual(a[1, 3], "3_1") + XCTAssertEqual(a[1, 4], "2_1") + XCTAssertEqual(a[1, 5], "1_1") + XCTAssertEqual(a[1, 6], "0_1") + + XCTAssertEqual(a[2, 0], "6_2") + XCTAssertEqual(a[2, 1], "5_2") + XCTAssertEqual(a[2, 2], "4_2") + XCTAssertEqual(a[2, 3], "3_2") + XCTAssertEqual(a[2, 4], "2_2") + XCTAssertEqual(a[2, 5], "1_2") + XCTAssertEqual(a[2, 6], "0_2") + + XCTAssertEqual(a[3, 0], "6_3") + XCTAssertEqual(a[3, 1], "5_3") + XCTAssertEqual(a[3, 2], "4_3") + XCTAssertEqual(a[3, 3], "3_3") + XCTAssertEqual(a[3, 4], "2_3") + XCTAssertEqual(a[3, 5], "1_3") + XCTAssertEqual(a[3, 6], "0_3") + } + + func testTrim() { + let board = [ + "........", + ".#####..", + "....#...", + "..###...", + "..#.....", + "........" + ] + let compact = [ + "#####", + "...#.", + ".###.", + ".#...", + ] + var a: Array2D = .init(height: board.count, width: board[0].count, stringArray: board) + a.trim(removing: ".") + var b: Array2D = .init(height: compact.count, width: compact[0].count, stringArray: compact) + + XCTAssertEqual(a.description, b.description) + + } + + func testTrimed() { + let board = [ + "........", + ".#####..", + "....#...", + "..###...", + "..#.....", + "........" + ] + let compact = [ + "#####", + "...#.", + ".###.", + ".#...", + ] + var a: Array2D = .init(height: board.count, width: board[0].count, stringArray: board) + var b: Array2D = .init(height: compact.count, width: compact[0].count, stringArray: compact) + + XCTAssertEqual(a.trimmed(removing: ".").description, b.description) + + } + + func testSeekWords() { + let strs = [ + "asdfghjk", + "zxcvbnez", + "qwerykio", + "asdfuyui", + "qwenhjkl", + "qwscvbfu", + "nbvcytfr" + ] + let a: Array2D = .init(height: strs.count, width: strs[0].count, stringArray: strs) + let result = a.seek(word: "snuke") + XCTAssertNotNil(result) + let expected = [(5, 2), (4, 3), (3, 4), (2, 5), (1, 6)] + for (i, (r, c)) in result!.enumerated() { + XCTAssertEqual(r, expected[i].0) + XCTAssertEqual(c, expected[i].1) } } } diff --git a/Tests/AtCoderSupportTests/ZnTests.swift b/Tests/AtCoderSupportTests/ZnTests.swift new file mode 100644 index 0000000..ebf5952 --- /dev/null +++ b/Tests/AtCoderSupportTests/ZnTests.swift @@ -0,0 +1,78 @@ +import XCTest +@testable import AtCoderSupport + +final class ZnTests: XCTestCase { + func testNegation() { + assert(-Zn(safe: 5) == Zn(safe: -5)) + assert(-Zn(safe: 0) == 0) + } + + func testAddition() { + assert((Zn(safe: 3) + Zn(safe: 5)).n == Zn(safe: 8).n) + assert((Zn(safe: 5) + Zn(safe: -4)).n == Zn(safe: 1).n) + } + + func testSubtraction() { + assert(Zn(safe: 5) - Zn(safe: 3) == Zn(safe: 2)) + assert(Zn(safe: 3) - Zn(safe: 5) == Zn(safe: -2)) + assert(Zn(safe: 3) - Zn(safe: 3) == Zn(safe: 0)) + } + + func testMultiplication() { + assert(Zn(safe: 3) * Zn(safe: 4) == Zn(safe: 12)) + assert(Zn(safe: 3) * Zn(safe: -4) == Zn(safe: -12)) + assert(Zn(safe: -3) * Zn(safe: 4) == Zn(safe: -12)) + assert(Zn(safe: -3) * Zn(safe: -4) == Zn(safe: 12)) + assert(Zn(safe: 3) * Zn(safe: 0) == Zn(safe: 0)) + assert(Zn(safe: 0) * Zn(safe: 3) == Zn(safe: 0)) + assert(Zn(safe: 0) * Zn(safe: 0) == Zn(safe: 0)) + } + + func testDivision() { + assert(Zn(safe: 3) / Zn(safe: 2) * Zn(safe: 2) == Zn(safe: 3)) + assert(Zn(safe: 3) / Zn(safe: -2) * Zn(safe: -2) == Zn(safe: 3)) + assert(Zn(safe: 3) / Zn(safe: 1) * Zn(safe: 1) == Zn(safe: 3)) + assert(Zn(safe: 3) / Zn(safe: -1) * Zn(safe: -1) == Zn(safe: 3)) + assert(Zn(safe: 0) / Zn(safe: 3) * Zn(safe: 3) == Zn(safe: 0)) + } + + func testPower() { + assert(Zn(safe: 2).pow(0) == Zn(safe: 1)) + assert(Zn(safe: 2).pow(1) == Zn(safe: 2)) + assert(Zn(safe: 2).pow(2) == Zn(safe: 2 * 2)) + assert(Zn(safe: 2).pow(3) == Zn(safe: 2 * 2 * 2)) + assert(Zn(safe: 2).pow(4) == Zn(safe: 2 * 2 * 2 * 2)) + assert(Zn(safe: 2).pow(5) == Zn(safe: 2 * 2 * 2 * 2 * 2)) + assert(Zn(safe: 2).pow(6) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2)) + assert(Zn(safe: 2).pow(7) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2 * 2)) + assert(Zn(safe: 2).pow(8) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2)) + assert(Zn(safe: 2).pow(-1) == Zn(safe: 2).inverse) + assert(Zn(safe: 2).pow(-2) == Zn(safe: 2 * 2).inverse) + assert(Zn(safe: 2).pow(-3) == Zn(safe: 2 * 2 * 2).inverse) + assert(Zn(safe: 2).pow(-4) == Zn(safe: 2 * 2 * 2 * 2).inverse) + assert(Zn(safe: 2).pow(-5) == Zn(safe: 2 * 2 * 2 * 2 * 2).inverse) + assert(Zn(safe: 2).pow(-6) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2).inverse) + assert(Zn(safe: 2).pow(-7) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2 * 2).inverse) + assert(Zn(safe: 2).pow(-8) == Zn(safe: 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2).inverse) + assert(Zn(safe: 3).pow(0) == Zn(safe: 1)) + assert(Zn(safe: 3).pow(1) == Zn(safe: 3)) + assert(Zn(safe: 3).pow(2) == Zn(safe: 3 * 3)) + assert(Zn(safe: 3).pow(3) == Zn(safe: 3 * 3 * 3)) + assert(Zn(safe: 3).pow(4) == Zn(safe: 3 * 3 * 3 * 3)) + assert(Zn(safe: 3).pow(5) == Zn(safe: 3 * 3 * 3 * 3 * 3)) + assert(Zn(safe: 3).pow(6) == Zn(safe: 3 * 3 * 3 * 3 * 3 * 3)) + assert(Zn(safe: 3).pow(7) == Zn(safe: 3 * 3 * 3 * 3 * 3 * 3 * 3)) + assert(Zn(safe: 3).pow(8) == Zn(safe: 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3)) + } + + func testInverse() { + assert(Zn(safe: 1).inverse * Zn(safe: 1) == Zn(safe: 1)) + assert(Zn(safe: 2).inverse * Zn(safe: 2) == Zn(safe: 1)) + assert(Zn(safe: 3).inverse * Zn(safe: 3) == Zn(safe: 1)) + assert(Zn(safe: 4).inverse * Zn(safe: 4) == Zn(safe: 1)) + assert(Zn(safe: 5).inverse * Zn(safe: 5) == Zn(safe: 1)) + assert(Zn(safe: 6).inverse * Zn(safe: 6) == Zn(safe: 1)) + assert(Zn(safe: 7).inverse * Zn(safe: 7) == Zn(safe: 1)) + assert(Zn(safe: 8).inverse * Zn(safe: 8) == Zn(safe: 1)) + } +} \ No newline at end of file