parent
96d9683eb2
commit
cb807de984
@ -0,0 +1,187 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 9: Marble Mania"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct List {
|
||||
var val = 0
|
||||
var ptrNext = -1
|
||||
var ptrPrev = -1
|
||||
}
|
||||
|
||||
class Marble {
|
||||
var player: [Int] = []
|
||||
var lastMarble = 0
|
||||
var circle: [List] = []
|
||||
var circleCount = 1
|
||||
var currentMarble = 0
|
||||
var currentPlayer = 0
|
||||
var PC = 0
|
||||
|
||||
init(numPlayers: Int, lastMarble last: Int) {
|
||||
circle = Array(repeating: List(), count: last+1)
|
||||
circleCount = 1
|
||||
currentMarble = 0
|
||||
currentPlayer = 0
|
||||
PC = 0
|
||||
circle[0].ptrNext = 0
|
||||
circle[0].ptrPrev = 0
|
||||
|
||||
player = Array(repeating: 0, count: numPlayers)
|
||||
for num in 0...last { circle[num].val = num }
|
||||
lastMarble = last
|
||||
}
|
||||
|
||||
func insert() {
|
||||
circle[currentMarble].ptrNext = circle[PC].val
|
||||
circle[currentMarble].ptrPrev = circle[PC].ptrPrev
|
||||
circle[circle[PC].ptrPrev].ptrNext = circle[currentMarble].val
|
||||
circle[PC].ptrPrev = circle[currentMarble].val
|
||||
PC = currentMarble
|
||||
circleCount += 1
|
||||
}
|
||||
|
||||
func remove() {
|
||||
circle[circle[PC].ptrPrev].ptrNext = circle[PC].ptrNext
|
||||
circle[circle[PC].ptrNext].ptrPrev = circle[PC].ptrPrev
|
||||
PC = circle[circle[PC].ptrPrev].ptrNext
|
||||
circleCount -= 1
|
||||
}
|
||||
|
||||
func incrPC() {
|
||||
PC = circle[PC].ptrNext
|
||||
}
|
||||
|
||||
func incrPC(by n: Int) {
|
||||
for _ in 0..<n { incrPC() }
|
||||
}
|
||||
|
||||
func decrPC() {
|
||||
PC = circle[PC].ptrPrev
|
||||
}
|
||||
|
||||
func decrPC(by n: Int) {
|
||||
for _ in 0..<n { decrPC() }
|
||||
}
|
||||
|
||||
func incrPlayer() {
|
||||
currentPlayer += 1
|
||||
if currentPlayer == player.count { currentPlayer = 0 }
|
||||
}
|
||||
|
||||
func placeNextMarble() {
|
||||
currentMarble += 1
|
||||
if currentMarble % 23 == 0 {
|
||||
player[currentPlayer] += currentMarble
|
||||
decrPC(by: 7)
|
||||
player[currentPlayer] += circle[PC].val
|
||||
remove()
|
||||
} else {
|
||||
incrPC(by: 2)
|
||||
insert()
|
||||
}
|
||||
incrPlayer()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day09: AOCDay {
|
||||
lazy var tests: (() -> ()) = day09Tests
|
||||
lazy var final: (() -> ()) = day09Final
|
||||
|
||||
let testData: [(Int, Int, Int)] = [
|
||||
(9, 25, 32),
|
||||
(13, 7999, 146373),
|
||||
(17, 1104, 2764),
|
||||
(21, 6111, 54718),
|
||||
(30, 5807, 37305)
|
||||
]
|
||||
|
||||
let finalData = (477, 70851)
|
||||
|
||||
func printCircle(circle: [List], withCount circleCount: Int) -> String {
|
||||
var retVal = ""
|
||||
var marble = circle[0]
|
||||
for _ in 0..<circleCount {
|
||||
retVal += "\(marble.val), "
|
||||
marble = circle[marble.ptrNext]
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func testMarbleInit() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testMarbleInit num", withExpression: (marb.player.count == 9))
|
||||
XCTAssertEqual(test: "testMarbleInit last", withExpression: (marb.lastMarble == 15))
|
||||
XCTAssertEqual(test: "testMarbleInit result", withExpression: (result == "0, "))
|
||||
}
|
||||
|
||||
func testInsert() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
for _ in 0...3 {
|
||||
marb.currentMarble += 1
|
||||
marb.insert()
|
||||
marb.incrPC(by:2)
|
||||
}
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testInsert result", withExpression: (result == "0, 4, 2, 1, 3, "))
|
||||
}
|
||||
|
||||
func testRemove() {
|
||||
let marb = Marble(numPlayers: 9, lastMarble: 15)
|
||||
for _ in 0...3 {
|
||||
marb.currentMarble += 1
|
||||
marb.insert()
|
||||
marb.incrPC(by:2)
|
||||
}
|
||||
marb.decrPC(by: 2)
|
||||
marb.remove()
|
||||
let result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
XCTAssertEqual(test: "testRemove result", withExpression: (result == "0, 2, 1, 3, "))
|
||||
}
|
||||
|
||||
func testPlaceNextMarble() {
|
||||
var result = ""
|
||||
for data in testData {
|
||||
let marb = Marble(numPlayers: data.0, lastMarble: data.1)
|
||||
for _ in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
if data == (9, 25, 32) {
|
||||
result = printCircle(circle: marb.circle, withCount: marb.circleCount)
|
||||
}
|
||||
}
|
||||
let max = marb.player.max() ?? 0
|
||||
if data == (9, 25, 32) {
|
||||
XCTAssertEqual(test: "testPlaceMarble result", withExpression: (result == "0, 16, 8, 17, 4, 18, 19, 2, 24, 20, 25, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15, "))
|
||||
}
|
||||
XCTAssertEqual(test: "testPlaceMarble \(data)", withExpression: (max == data.2))
|
||||
}
|
||||
}
|
||||
|
||||
func day09Tests() {
|
||||
testMarbleInit()
|
||||
testInsert()
|
||||
testRemove()
|
||||
testPlaceNextMarble()
|
||||
}
|
||||
|
||||
func day09Final() {
|
||||
var marb = Marble(numPlayers: 477, lastMarble: 70851)
|
||||
for _ in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
}
|
||||
var max = marb.player.max() ?? 0
|
||||
print("Answer to part 1 is: \(max)")
|
||||
marb = Marble(numPlayers: 477, lastMarble: 7085100)
|
||||
for i in 0..<marb.lastMarble {
|
||||
marb.placeNextMarble()
|
||||
if i % 1000000 == 0 { print("\(i)")}
|
||||
}
|
||||
max = marb.player.max() ?? 0
|
||||
print("Answer to part 2 is: \(max)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue