Skip to content

Commit

Permalink
Day 23 | Part 1 - Refactored IntCodeComputer onNextBoot Functionality…
Browse files Browse the repository at this point in the history
… (Accepts NetworkAddress)
  • Loading branch information
TomPlum committed Jul 9, 2020
1 parent 0cfd89c commit b08b3dd
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 55 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.aoc.intcode.computer

import com.aoc.intcode.computer.boot.BootMode
import com.aoc.intcode.computer.exceptions.HaltProgram
import com.aoc.intcode.computer.exceptions.SignalInterrupt
import com.aoc.intcode.computer.instructions.InstructionStrategy
Expand All @@ -10,8 +11,8 @@ import com.aoc.intcode.computer.instructions.strategies.Input
* This class is the heart of Advent of Code 2019.
* Every other day utilises the [IntCodeComputer]. It is completed by Day 9.
*
* The computer can be started with a [BootMode] which will start the next boot with a value
* in the [Memory] [SystemInput]. The [BootMode.systemInputCode] will modify the [Program] behaviour.
* The computer can be started with a [TestBootMode] which will start the next boot with a value
* in the [Memory] [SystemInput]. The [TestBootMode.systemInputCode] will modify the [Program] behaviour.
*/
class IntCodeComputer constructor(instructions: String) {
val program = Program(instructions)
Expand Down Expand Up @@ -59,7 +60,7 @@ class IntCodeComputer constructor(instructions: String) {
* Starts the computer in an alternate mode so the Thermal Environment Supervision Terminal (TEST)
* can run a diagnostic program.
*/
fun onNextBoot(mode: BootMode) = program.memory.input.add(mode.systemInputCode)
fun onNextBoot(mode: BootMode) = program.memory.input.add(mode.getCode())

/**
* When running TEST programs, the [IntCodeComputer] will often output a diagnostic code
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.aoc.intcode.computer.boot

interface BootMode {
fun getCode(): Long
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.aoc.intcode.computer.boot

import com.aoc.intcode.computer.IntCodeComputer

/**
* The Thermal Environment Supervision Terminal (TEST) is capable of running diagnostic tests on an [IntCodeComputer].
* @see IntCodeComputer.onNextBoot
*/
enum class TestBootMode : BootMode {
AIR_CONDITIONER_DIAGNOSTIC_TEST {
override fun getCode() = 1L
},
THERMAL_RADIATOR_CONTROLLER_DIAGNOSTIC_TEST {
override fun getCode() = 5L
},
BOOST_TEST {
override fun getCode() = 1L
},
SENSOR_BOOST {
override fun getCode() = 2L
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ class IntCodeComputerMesh(private val software: String) {
repeat(50) { computers[NetworkAddress(it.toLong())] = IntCodeComputer(software) }

computers.forEach { (address, computer) ->
computer.program.memory.input.add(address.value)
computer.onNextBoot(address)
}

}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
package com.aoc.intcode.network

data class NetworkAddress(val value: Long)
import com.aoc.intcode.computer.boot.BootMode

data class NetworkAddress(val value: Long) : BootMode {
override fun getCode() = value
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import assertk.assertions.isFalse
import assertk.assertions.isTrue
import com.aoc.input.InputReader
import com.aoc.input.Day
import com.aoc.intcode.computer.boot.TestBootMode
import com.aoc.intcode.network.NetworkAddress
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -86,6 +88,16 @@ class IntCodeComputerTest {

@Nested
inner class DayFive {
@Test
@DisplayName("Given a Input OpCode (3) and NO system input, when running, then it should suspend execution and" +
"wait for further input. The instruction pointer should remain where it is")
fun inputShouldSetComputerToWaitingWhenNoSystemInput() {
val computer = IntCodeComputer("1,0,0,0,3,0,99")
computer.run()
assertThat(computer.waiting).isTrue()
assertThat(computer.program.memory.instructionPointer).isEqualTo(4)
}

@Test
@DisplayName("Given a JUMP_IF_TRUE OpCode(5) in IMMEDIATE_MODE, when the first parameter is non-zero, then it should set the instruction pointer to the value from the second parameter")
fun jumpIfTrue() {
Expand Down Expand Up @@ -274,7 +286,7 @@ class IntCodeComputerTest {
fun dayFivePartTwoSolution() {
val puzzleInput = InputReader().readInputAsSingleString(Day.from(5))
val computer = IntCodeComputer(puzzleInput)
computer.onNextBoot(BootMode.THERMAL_RADIATOR_CONTROLLER_DIAGNOSTIC_TEST)
computer.onNextBoot(TestBootMode.THERMAL_RADIATOR_CONTROLLER_DIAGNOSTIC_TEST)
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(7408802)
}
Expand All @@ -284,7 +296,7 @@ class IntCodeComputerTest {
fun dayFivePartOneSolution() {
val puzzleInput = InputReader().readInputAsSingleString(Day.from(5))
val computer = IntCodeComputer(puzzleInput)
computer.onNextBoot(BootMode.AIR_CONDITIONER_DIAGNOSTIC_TEST)
computer.onNextBoot(TestBootMode.AIR_CONDITIONER_DIAGNOSTIC_TEST)
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(5044655)
}
Expand Down Expand Up @@ -321,7 +333,7 @@ class IntCodeComputerTest {
fun dayNinePartOneSolution() {
val puzzleInput = InputReader().readInputAsSingleString(Day.from(9))
val computer = IntCodeComputer(puzzleInput)
computer.onNextBoot(BootMode.BOOST_TEST)
computer.onNextBoot(TestBootMode.BOOST_TEST)
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(3100786347L)
}
Expand All @@ -331,7 +343,7 @@ class IntCodeComputerTest {
fun dayNinePartTwoSolution() {
val puzzleInput = InputReader().readInputAsSingleString(Day.from(9))
val computer = IntCodeComputer(puzzleInput)
computer.onNextBoot(BootMode.SENSOR_BOOST)
computer.onNextBoot(TestBootMode.SENSOR_BOOST)
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(87023)
}
Expand All @@ -342,20 +354,48 @@ class IntCodeComputerTest {

}

@Test
@DisplayName("Given the output has at least one code, when getting the diagnostic code, then it should return the final code from the output")
fun getDiagnosticCode() {
val computer = IntCodeComputer("4,3,99,250")
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(250)
@Nested
inner class DiagnosticCode {
@Test
@DisplayName("Given the output has at least one code, when getting the diagnostic code, then it should return the final code from the output")
fun getDiagnosticCode() {
val computer = IntCodeComputer("4,3,99,250")
computer.run()
assertThat(computer.getDiagnosticCode()).isEqualTo(250)
}

@Test
@DisplayName("Given the output is empty, when getting the diagnostic code, then it should throw an exception")
fun getDiagnosticCodeWhenEmptyOutput() {
val computer = IntCodeComputer("1,0,0,0,99")
computer.run()
assertThrows<IllegalStateException> { computer.getDiagnosticCode() }
}
}

@Test
@DisplayName("Given the output is empty, when getting the diagnostic code, then it should throw an exception")
fun getDiagnosticCodeWhenEmptyOutput() {
val computer = IntCodeComputer("1,0,0,0,99")
computer.run()
assertThrows<IllegalStateException> { computer.getDiagnosticCode() }
@Nested
inner class OnNextBoot {
@ParameterizedTest
@EnumSource(value = TestBootMode::class)
@DisplayName("Given a custom boot mode for the IntCodeComputer, when setting the mode for the next boot," +
"then it should set the associated code in the computers' system input")
fun onNextBootTEST(bootMode: TestBootMode) {
val computer = IntCodeComputer("99")
computer.onNextBoot(bootMode)
assertThat(getFirstSystemInputValue(computer)).isEqualTo(bootMode.getCode())
}

@Test
@DisplayName("Given a Network Address, when booting, then it should add the address value in the System Input")
fun onNextBootNetworkAddress() {
val computer = IntCodeComputer("99")
computer.onNextBoot(NetworkAddress(45))
assertThat(getFirstSystemInputValue(computer)).isEqualTo(45)
}

private fun getFirstSystemInputValue(computer: IntCodeComputer): Long {
return computer.program.memory.input.values[0]
}
}

@Test
Expand All @@ -366,26 +406,6 @@ class IntCodeComputerTest {
assertThat(e.message).isEqualTo("Operation unknown for instruction 1220")
}

@Test
@DisplayName("Given a Input OpCode (3) and NO system input, when running, then it should suspend execution and" +
"wait for further input. The instruction pointer should remain where it is")
fun inputShouldSetComputerToWaitingWhenNoSystemInput() {
val computer = IntCodeComputer("1,0,0,0,3,0,99")
computer.run()
assertThat(computer.waiting).isTrue()
assertThat(computer.program.memory.instructionPointer).isEqualTo(4)
}

@ParameterizedTest
@EnumSource(value = BootMode::class)
@DisplayName("Given a custom boot mode for the IntCodeComputer, when setting the mode for the next boot, then it should" +
"set the associated code in the computers' system input")
fun onNextBoot(bootMode: BootMode) {
val computer = IntCodeComputer("99")
computer.onNextBoot(bootMode)
assertThat(computer.program.memory.input.values[0]).isEqualTo(bootMode.systemInputCode)
}

@Test
fun reset() {
val computer = IntCodeComputer("7,1,2,0,99")
Expand Down
6 changes: 3 additions & 3 deletions solutions/src/main/kotlin/com/aoc/solutions/Day5.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.aoc.solutions

import com.aoc.input.Day
import com.aoc.input.InputReader
import com.aoc.intcode.computer.BootMode
import com.aoc.intcode.computer.boot.TestBootMode
import com.aoc.intcode.computer.IntCodeComputer

fun main() {
Expand All @@ -14,14 +14,14 @@ fun main() {

private fun partTwo(memoryAddresses: String) {
val computer = IntCodeComputer(memoryAddresses)
computer.onNextBoot(BootMode.THERMAL_RADIATOR_CONTROLLER_DIAGNOSTIC_TEST)
computer.onNextBoot(TestBootMode.THERMAL_RADIATOR_CONTROLLER_DIAGNOSTIC_TEST)
val finalProgramState = computer.run()
println("Final Program State $finalProgramState")
}

private fun partOne(memoryAddresses: String) {
val computer = IntCodeComputer(memoryAddresses)
computer.onNextBoot(BootMode.AIR_CONDITIONER_DIAGNOSTIC_TEST)
computer.onNextBoot(TestBootMode.AIR_CONDITIONER_DIAGNOSTIC_TEST)
val finalProgramState = computer.run()
println("Final Program State $finalProgramState")
}
6 changes: 3 additions & 3 deletions solutions/src/main/kotlin/com/aoc/solutions/Day9.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.aoc.solutions

import com.aoc.input.Day
import com.aoc.input.InputReader
import com.aoc.intcode.computer.BootMode
import com.aoc.intcode.computer.boot.TestBootMode
import com.aoc.intcode.computer.IntCodeComputer

fun main() {
Expand All @@ -13,14 +13,14 @@ fun main() {

private fun partOne(input: String) {
val computer = IntCodeComputer(input)
computer.onNextBoot(BootMode.BOOST_TEST)
computer.onNextBoot(TestBootMode.BOOST_TEST)
computer.run()
print("Part 1 Solution: ${computer.getDiagnosticCode()}")
}

private fun partTwo(input: String) {
val computer = IntCodeComputer(input)
computer.onNextBoot(BootMode.SENSOR_BOOST)
computer.onNextBoot(TestBootMode.SENSOR_BOOST)
computer.run()
print("Part 2 Solution: ${computer.getDiagnosticCode()}")
}

0 comments on commit b08b3dd

Please sign in to comment.