package Ġpl . sh ock ah . a oc . y 2 0 1 8 Ċ Ċ import Ġorg . junit . jupiter . api . Assertions Ċ import Ġorg . junit . jupiter . api . Test Ċ import Ġpl . sh ock ah . a oc . Ad vent Task Ċ import Ġpl . sh ock ah . a oc . parse 4 Ċ import Ġjava . util . regex . Pattern Ċ Ċ class ĠDay 1 6 : ĠAd vent Task < Day 1 6 . Input , ĠInt , ĠInt >( 2 0 1 8 , Ġ 1 6 ) Ġ{ Ċ ĉ private Ġval Ġexample Pattern Ġ= ĠPattern . compile (" .*? \\ [( \\ d + ), Ġ( \\ d + ), Ġ( \\ d + ), Ġ( \\ d + )] ") ĊĊ ĉ data Ġclass ĠInput ( Ċĉ ĉ val Ġexamples : ĠList < Example >, Ċĉ ĉ val Ġinstructions : ĠList < Instruction > Ċ ĉ ) ĊĊ ĉ data Ġclass ĠExample ( Ċĉ ĉ val Ġbefore : ĠInt Array , Ċĉ ĉ val Ġinstruction : ĠInstruction , Ċĉ ĉ val Ġafter : ĠInt Array Ċ ĉ ) Ġ{ Ċĉ ĉ override Ġfun Ġequals ( other : ĠAny ?): ĠBoolean Ġ{ Ċĉĉ ĉ if Ġ( this Ġ=== Ġother ) Ġreturn Ġtrue Ċĉĉ ĉ if Ġ( java Class Ġ!= Ġother ?. java Class ) Ġreturn Ġfalse ĊĊĉĉ ĉ other Ġas ĠExample ĊĊĉĉ ĉ if Ġ(! before . content Equals ( other . before )) Ġreturn Ġfalse Ċĉĉ ĉ if Ġ( instruction Ġ!= Ġother . instruction ) Ġreturn Ġfalse Ċĉĉ ĉ if Ġ(! after . content Equals ( other . after )) Ġreturn Ġfalse ĊĊĉĉ ĉ return Ġtrue Ċĉ ĉ } ĊĊĉ ĉ override Ġfun ĠhashCode (): ĠInt Ġ{ Ċĉĉ ĉ var Ġresult Ġ= Ġbefore . content HashCode () Ċĉĉ ĉ result Ġ= Ġ 3 1 Ġ* Ġresult Ġ+ Ġinstruction . hashCode () Ċĉĉ ĉ result Ġ= Ġ 3 1 Ġ* Ġresult Ġ+ Ġafter . content HashCode () Ċĉĉ ĉ return Ġresult Ċĉ ĉ } Ċ ĉ } ĊĊ ĉ data Ġclass ĠInstruction ( Ċĉ ĉ val Ġopcode : ĠInt , Ċĉ ĉ val Ġinput A : ĠInt , Ċĉ ĉ val Ġinput B : ĠInt , Ċĉ ĉ val Ġoutput : ĠInt Ċ ĉ ) ĊĊ ĉ @ Suppress (" Enum Entry Name ") Ċ ĉ enum Ġclass ĠOperation ( Ċĉ ĉ private Ġval Ġfunc : Ġ( a : ĠInt , Ġb : ĠInt , Ġout : ĠInt , Ġregisters : ĠInt Array ) Ġ-> ĠUnit Ċ ĉ ) Ġ{ Ċĉ ĉ addr ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġ+ Ġregisters [ b ] Ġ}), Ċĉ ĉ addi ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġ+ Ġb Ġ}), Ċĉ ĉ mul r ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġ* Ġregisters [ b ] Ġ}), Ċĉ ĉ mul i ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġ* Ġb Ġ}), Ċĉ ĉ ban r ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġand Ġregisters [ b ] Ġ}), Ċĉ ĉ ban i ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġand Ġb Ġ}), Ċĉ ĉ bor r ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġor Ġregisters [ b ] Ġ}), Ċĉ ĉ b ori ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġor Ġb Ġ}), Ċĉ ĉ se tr ({ Ġa , Ġ_, Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġregisters [ a ] Ġ}), Ċĉ ĉ set i ({ Ġa , Ġ_, Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġa Ġ}), Ċĉ ĉ gt ir ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( a Ġ> Ġregisters [ b ]) Ġ 1 Ġelse Ġ 0 Ġ}), Ċĉ ĉ gt ri ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( registers [ a ] Ġ> Ġb ) Ġ 1 Ġelse Ġ 0 Ġ}), Ċĉ ĉ g tr r ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( registers [ a ] Ġ> Ġregisters [ b ]) Ġ 1 Ġelse Ġ 0 Ġ}), Ċĉ ĉ eq ir ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( a Ġ== Ġregisters [ b ]) Ġ 1 Ġelse Ġ 0 Ġ}), Ċĉ ĉ eq ri ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( registers [ a ] Ġ== Ġb ) Ġ 1 Ġelse Ġ 0 Ġ}), Ċĉ ĉ eq rr ({ Ġa , Ġb , Ġout , Ġregisters Ġ-> Ġregisters [ out ] Ġ= Ġif Ġ( registers [ a ] Ġ== Ġregisters [ b ]) Ġ 1 Ġelse Ġ 0 Ġ}); ĊĊĉ ĉ operator Ġfun Ġinvoke ( a : ĠInt , Ġb : ĠInt , Ġout : ĠInt , Ġregisters : ĠInt Array ) Ġ{ Ċĉĉ ĉ func ( a , Ġb , Ġout , Ġregisters ) Ċĉ ĉ } ĊĊĉ ĉ operator Ġfun Ġinvoke ( instruction : ĠInstruction , Ġregisters : ĠInt Array ) Ġ{ Ċĉĉ ĉ func ( instruction . input A , Ġinstruction . input B , Ġinstruction . output , Ġregisters ) Ċĉ ĉ } Ċ ĉ } ĊĊ ĉ override Ġfun Ġparse Input ( raw Input : ĠString ): ĠInput Ġ{ Ċĉ ĉ val Ġlines Ġ= Ġraw Input . lines () Ċĉ ĉ var Ġindex Ġ= Ġ 0 Ċĉ ĉ val Ġexamples Ġ= Ġmutable ListOf < Example >() Ċĉ ĉ val Ġinstructions Ġ= Ġmutable ListOf < Instruction >() ĊĊĉ ĉ while Ġ( index Ġ< Ġlines . size ) Ġ{ Ċĉĉ ĉ try Ġ{ Ċĉĉĉ ĉ val Ġbefore Ġ= Ġparse Registers ( lines [ index ]) Ċĉĉĉ ĉ val Ġinstruction Ġ= Ġparse Instruction ( lines [ index Ġ+ Ġ 1 ]) Ċĉĉĉ ĉ val Ġafter Ġ= Ġparse Registers ( lines [ index Ġ+ Ġ 2 ]) Ċĉĉĉ ĉ examples Ġ+= ĠExample ( before , Ġinstruction , Ġafter ) Ċĉĉĉ ĉ index Ġ+= Ġ 4 Ċĉĉ ĉ } Ġcatch Ġ( ignored : ĠIllegalArgumentException ) Ġ{ Ċĉĉĉ ĉ index Ġ+= Ġ 2 Ċĉĉĉ ĉ break Ċĉĉ ĉ } Ċĉ ĉ } ĊĊĉ ĉ for Ġ( i Ġin Ġindex Ġuntil Ġlines . size ) Ġ{ Ċĉĉ ĉ instructions Ġ+= Ġparse Instruction ( lines [ i ]) Ċĉ ĉ } Ċĉ ĉ return ĠInput ( examples , Ġinstructions ) Ċ ĉ } ĊĊ ĉ private Ġfun Ġparse Registers ( line : ĠString ): ĠInt Array Ġ{ Ċĉ ĉ val Ġ( a , Ġb , Ġc , Ġd ) Ġ= Ġexample Pattern . parse 4 < Int , ĠInt , ĠInt , ĠInt >( line ) Ċĉ ĉ return Ġint ArrayOf ( a , Ġb , Ġc , Ġd ) Ċ ĉ } ĊĊ ĉ private Ġfun Ġparse Instruction ( line : ĠString ): ĠInstruction Ġ{ Ċĉ ĉ val Ġsplit Ġ= Ġline . split (" Ġ"). map Ġ{ Ġit . trim (). toInt () Ġ} Ċĉ ĉ return ĠInstruction ( split [ 0 ], Ġsplit [ 1 ], Ġsplit [ 2 ], Ġsplit [ 3 ]) Ċ ĉ } ĊĊ ĉ override Ġfun Ġpart 1 ( input : ĠInput ): ĠInt Ġ{ Ċĉ ĉ return Ġinput . examples . count Ġ{ Ġexample Ġ-> Ċĉĉ ĉ return @ count ĠOperation . values (). count Ġ{ Ċĉĉĉ ĉ val Ġregisters Ġ= Ġexample . before . copyOf () Ċĉĉĉ ĉ it ( example . instruction , Ġregisters ) Ċĉĉĉ ĉ registers . content Equals ( example . after ) Ċĉĉ ĉ } Ġ>= Ġ 3 Ċĉ ĉ } Ċ ĉ } ĊĊ ĉ override Ġfun Ġpart 2 ( input : ĠInput ): ĠInt Ġ{ Ċĉ ĉ val Ġoperations Ġ= Ġmutable Map Of < Int , ĠOperation >() Ċĉ ĉ val Ġpossible Operations Ġ= ĠOperation . values (). associate With Ġ{ Ġmutable Set Of < Int >() Ġ}. to Mutable Map () ĊĊĉ ĉ input . examples . forEach Ġ{ Ġexample Ġ-> Ċĉĉ ĉ Operation . values (). forEach Ġ{ Ċĉĉĉ ĉ val Ġregisters Ġ= Ġexample . before . copyOf () Ċĉĉĉ ĉ it ( example . instruction , Ġregisters ) Ċĉĉĉ ĉ if Ġ( registers . content Equals ( example . after )) Ċĉĉĉĉ ĉ possible Operations [ it ] !! Ġ+= Ġexample . instruction . opcode Ċĉĉ ĉ } Ċĉ ĉ } ĊĊĉ ĉ while Ġ( true ) Ġ{ Ċĉĉ ĉ val Ġold Size Ġ= Ġoperations . size ĊĊĉĉ ĉ l @ Ġfor Ġ(( operation , Ġop codes ) Ġin Ġpossible Operations ) Ġ{ Ċĉĉĉ ĉ when Ġ( op codes . size ) Ġ{ Ċĉĉĉĉĉ 0 Ġ-> Ġthrow ĠIllegalStateException (" No Ġop codes Ġfor Ġoperation Ġ${ operation . name }") Ċĉĉĉĉĉ 1 Ġ-> Ġ{ Ċĉĉĉĉĉ ĉ val Ġopcode Ġ= Ġop codes . first () Ċĉĉĉĉĉ ĉ operations [ opcode ] Ġ= Ġoperation Ċĉĉĉĉĉ ĉ possible Operations . remove ( operation ) Ċĉĉĉĉĉ ĉ possible Operations . values . forEach Ġ{ Ġit . remove ( opcode ) Ġ} Ċĉĉĉĉĉ ĉ break @ l Ċĉĉĉĉ ĉ } Ċĉĉĉĉ ĉ else Ġ-> Ġ{ Ġ} Ċĉĉĉ ĉ } Ċĉĉ ĉ } ĊĊĉĉ ĉ check ( operations . size Ġ!= Ġold Size ) Ġ{ Ġ" Cannot Ġfigure Ġout Ġop codes Ġfor Ġoperations Ġ${ ( Operation . values (). toList () Ġ- Ġoperations . values ). join ToString (", Ġ") Ġ{ Ġit . name Ġ}}" Ġ} Ċĉĉ ĉ if Ġ( possible Operations . isEmpty ()) Ċĉĉĉ ĉ break Ċĉ ĉ } ĊĊĉ ĉ println ("> ĠOperations :") Ċĉ ĉ println ( operations . to Sorted Map (). map Ġ{ Ġ"${ it . key }: Ġ${ it . value }" Ġ}. join ToString ("\ n ")) ĊĊĉ ĉ val Ġregisters Ġ= Ġint ArrayOf ( 0 , Ġ 0 , Ġ 0 , Ġ 0 ) Ċĉ ĉ input . instructions . forEach Ġ{ Ċĉĉ ĉ operations [ it . opcode ] !! ( it . input A , Ġit . input B , Ġit . output , Ġregisters ) Ċĉ ĉ } Ċĉ ĉ println ("> ĠFinal Ġregisters : Ġ${ registers . toList () }") Ċĉ ĉ return Ġregisters [ 0 ] Ċ ĉ } ĊĊ ĉ class ĠTests Ġ{ Ċĉ ĉ private Ġval Ġtask Ġ= ĠDay 1 6 () ĊĊĉ ĉ @ Test Ċĉ ĉ fun Ġpart 1 () Ġ{ Ċĉĉ ĉ val Ġinput Ġ= Ġtask . parse Input (""" Ċĉĉĉ ĉ Before : Ġ[ 3 , Ġ 2 , Ġ 1 , Ġ 1 ] Ċĉĉĉĉ 9 Ġ 2 Ġ 1 Ġ 2 Ċĉĉĉ ĉ After : Ġ Ġ[ 3 , Ġ 2 , Ġ 2 , Ġ 1 ] ĊĊĊ Ċĉĉĉĉ 9 Ġ 2 Ġ 1 Ġ 2 Ċĉĉ ĉ """. trim Indent ()) Ċĉĉ ĉ Assertions . assertEquals ( 1 , Ġtask . part 1 ( input )) Ċĉ ĉ } Ċ ĉ } Ċ }