Compare commits
5
Commits
3e711561fa
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8062f0a2be | ||
|
|
5531412a55 | ||
|
|
14c93b8482 | ||
|
|
d511a8cd65 | ||
|
|
944fad0f02 |
@@ -0,0 +1,150 @@
|
||||
/----------------------\ /--------------------------\
|
||||
| /+------------------------------------------------------------------------------+-------------\ |
|
||||
| /--++--------------------------------------------------------\ | | |
|
||||
| | /++--------------------------------------------------------+---------------------+-------\ | |
|
||||
| /----------------+-+++--------\ /---------------------------------------------+---------------------+\ | | |
|
||||
| | | ||| | | /+---------------------++------+-----+-----------\|
|
||||
/----+-+-\ | ||| | | /----------------------------++---------------------++---\ | | ||
|
||||
| | | |/-------------+-+++--------+-+---------------+--->------------------------++--\ /------------++---+--+-----+---------\ ||
|
||||
| | | || /-------+-+++--------+-+---------------+----------------------------++--+-----+-----\ || | | | | ||
|
||||
/+----+-+-++-----+-------+-+++--------+-+---------------+----------------------------++--+--\ | | || | | | | ||
|
||||
|| |/+-++-----+-------+-+++--------+-+---------------+----------------------------++--+--+--+-----+-\ || | | | | ||
|
||||
/-----++----+++\|| | | ||| | | | || | | | | | || | | /--+---------+-++----\
|
||||
| || |||||| | | ||| | | /--+----------------------------++--+--+--+-----+-+----++---+--+--+--+------\ | || |
|
||||
| || |||||| | | ||| | | /--------+\ | /---------------------++--+--+--+-----+-+----++---+--+--+--+------+--+-++---\|
|
||||
| || ||||||/----+-------+-+++--------+-+---+--------++-+------+---------------------++--+--+--+-----+-+----++---+\ | | | | | || ||
|
||||
| || |||||||/---+-------+-+++--------+-+---+--------++-+------+----------------\ || | | | | | || || | | | | | || ||
|
||||
| || |||||||| | | ||| | | | || | | | || | | | | | /-++---++-+--+--+------+--+-++-\ ||
|
||||
| /--++----++++++++---+-------+-+++--\ /-+-+---+--------++-+------+----------------+----++--+--+\ | | | | || || | | | | | || | ||
|
||||
/+--+--++----++++++++---+-------+-+++--+---+-+-+---+--------++-+------+----------------+-\ || | || | | | | || || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | | | ||/-+--++-+-----+-+--+-++\ || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | /--------+-+--+++-+--++\| | | | ||| || | | | | | || | ||
|
||||
|| | || |||||||| | | ||| | | | | | || | | | | | ||| | |||| | | | ||| || | | | | | || | ||
|
||||
|| | || |||||^|| \-------+-+++--+---+-+-+---+--------++-+------+-------+--------+-+--+++-+--++++-----/ | | ||| || | | | | | || | ||
|
||||
|| | \+-<--++++++++-----------+-+++--+---+-+-+---+--------++-+------+-------+--------+-+--+++-+--/||| | | ||| || | | | | | || | ||
|
||||
|| | | |||||||| /----+-+++--+---+-+-+---+--------++-+----\ | | | | ||| | |||/------+--+-+++--++-+--+--+------+--+\|| | ||
|
||||
|| | | |||||||| | | |||/-+---+-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-+--+--+------+-\|||| | ||
|
||||
|| | | |||||||| | | |||| | /+-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-+--+--+--\ | ||||| | ||
|
||||
|| | | |||||||| | | \+++-+--++-+-+---+--------++-+----+-+-------+--------+-+--+++-+---++++------+--+-+++--++-/ | | | | ||||| | ||
|
||||
|| | | |||||||| | | ||| |/-++-+-+---+--------++-+----+\| | | | ||| | |||| | | ||| || | | | | ||||| | ||
|
||||
|| |/--+----++++++++---->-+----+--+++-++-++-+-+---+--------++-+---\||| | | | ||| | |||| |/-+-+++--++----+--+\ | | ||||| | ||
|
||||
|| || | |||||||| /+----+--+++-++-++-+-+---+--------++-+---++++-------+--------+-+--+++-+---++++------++-+-+++--++---\| || | | ||||| | ||
|
||||
|| || | |||||||| || | /+++-++-++\| | | || ^ |||| | | | ||| | ||||/-----++-+-+++--++---++--++-+---+\||||| | ||
|
||||
|| || |/---++++++++-----++----+-++++-++-++++-+---+--------++-+---++++-------+--------+-+--+++-+\/-+++++-----++-+-+++--++---++\ || | ||||||| | ||
|
||||
|| || || |||||||| || | |||| || |||| | | || | |||| | | | ||| ||| ||||| || | ||| || ||| || | ||||||| | ||
|
||||
|| || || |||||||| || | |||| || ||||/+---+--------++-+---++++-------+--------+-+\ ||| ||| ||||| || | ||| || ||| || | ||||||| | ||
|
||||
|| || /++---++++++++-----++----+-++++-++-++++++---+--------++-+---++++-------+--------+-++-+++-+++-+++++\ || | ||| || ||| || | ||||||| | ||
|
||||
|| || ||| |||||||| || |/++++-++-++++++---+--------++\| |||| | |/++-+++-+++-++++++--\ || | ||| || ||| || | ||||||| | ||
|
||||
|| || ||| |||||||| || |||||| || |||||| | |||| |||| \--------++++-+++-+++-+/|||| | || | ||| || ||| || | ||||||| | ||
|
||||
|\--++-+++---+++/|||| || |||||| || |||||| | |||| |||| /--------------++++-+++-+++-+-++++--+-++-+-+++--++---+++-++-+\ ||||||| | ||
|
||||
| \+-+++---+++-++++-----++----++++++-/| |||||| | |||| |||| | |||| ||| ||| | |||| | || | ||| || ||| || || ||||||| | ||
|
||||
| | ||| ||| |||| || |||||| /+-++++++---+--------++++---++++-+--------------++++-+++-+++-+-++++--+\|| | ||| || ||| || || ||||||| | ||
|
||||
| | ||| |\+-++++-----++----++++++-++-++++++---+--------++++---++++-+--------------++++-+++-+++-+-++++--++/| | ||| || ||| || || ||||||| | ||
|
||||
| | ||| | | |||| ||/---++++++-++-++++++---+--------++++---++++-+------------\ |||| ||| ||| | ||\+--++-+-+-+++--++---+++-++-++--+/||||| | ||
|
||||
| | ||| | | |||| ||| |||||| || |||||| | /------++++---++++-+------------+-++++-+++-+++-+-++-+--++-+-+-+++--++--\||| || || | ||||| | ||
|
||||
/+----+-+++---+\| |||| ||| |||||| || |||||| | | |||| |||| | | |||| ||| ||| | |\-+--++-+-+-+++--++--++++-++-++--+-++/|| | ||
|
||||
|| | ||| ||| |||| ||| |||||| || |||||| \-+------+/|\---++++-+------------+-++++-+++-+++-+-+--+--++-+-+-+++--/| |||| || || | || || | ||
|
||||
|| /-+-+++---+++-++++-\ ||| |||||| |\-++++++-----+------+-+----++/| | /----+-++++-+++-+++-+-+--+--++-+-+\||| | |||| || || | || || | ||
|
||||
|| | | ||| ||| |||| | ||| |||||| | ||||\+-----+------+-+----++-+-+-------+----+-+++/ ||| ||| | |/-+--++-+-+++++--\| |||| || || | || || | ||
|
||||
|| | | ||| ||| |||| | ||| |||||| | |||| | | | | || | | | | ||| ||| ||| | || | || | ||||| || |||| || || | || || | ||
|
||||
|| |/+-+++---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-------+---\| ||| ||\-+++-+-++-+--++-+-++++/ || |||| || || | || || | ||
|
||||
|| ||| ||\---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-------+---++-+++--++--+/| | \+-+--++-+-++++---++--++++-++-++--+-+/ || | ||
|
||||
|| ||| ||/---+++-++++-+---+++---++++++-+--++++-+-----+------+-+----++-+-+-----<-+---++-+++--++-\| | | | | || | ||\+---++--++++-++-++--+-+--+/ | ||
|
||||
|| ||| ||| ||| |||| | ||| |||||| | |||| | | | | || | | | || ||| ||/++-+-+--+-+--++-+-++-+---++\ |||| || || | | | | ||
|
||||
|| ||| ||| \++-++++-+---+++---++++/| | ||||/+-<---+------+-+----++-+-+-------+---++-+++--+++++-+\| | | || | || | ||| |||| || || | | | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | /-++-+-+-------+---++-+++--+++++-+++--+-+-\|| | || | ||| |||| || || | | | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | || | | | || |\+--+++++-+++--+-+-+/|/+-++-+---+++-++++-++-++--+-+\ | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | || | | ^ || | | ||||| ||| | | | ||| || | ||| |||| || || | || | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| /--+------+-+--+-++-+-+-------+---++-+-+--+++++-+++--+-+-+-+++-++-+---+++-++++-++-++\ | || | | ||
|
||||
|| ||| ||| || |||| | ||| |||| | | |||||| | | | | | || | | \---++-+-+--+++++-+++--+-+-+-+++-+/ | ||| |||| || ||| | || | | ||
|
||||
|\--+++-+++----++-++++-+---+++---++++-+-+--++++++--+--+------+-+--+-++-+-+-----------++-+-/ ||||| ||| | | | ||| | | ||| |||| || ||| | || | | ||
|
||||
| ||| ||| || |||| | ||| |||| | | |||||| | /+------+\| | || | | || | ||||| ||| | | | ||| | | ||| |||| || ||| | || | | ||
|
||||
| ||| ||| || |||| | ||| |||| | | |||||| | || ||| | || | |/----------++-+----+++++-+++--+-+-+-+++-+--+---+++-++++-++\||| | || | | ||
|
||||
| ||\-+++----++-++++-+---+++---++++-+-+--++++++--+-++------+++--+-/| | || || | ||||| ||| | | | |||/+--+---+++-++++-++++++-+-++-+--+\||
|
||||
|/--++--+++----++-++++-+\ ||| |||| | |/-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+-+++++--+---+++-++++<++++++-+-++-+\ ||||
|
||||
|| || ||| /-++-++++-++--+++---++++-+-++-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+-+++++--+\ ||| |||| |||||| | || || ||||
|
||||
|| || ||| | || ||||/++--+++---++++-+-++-++++++--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+\||||| || ||| |||| |||||| | || || ||||
|
||||
||/-++--+++--+-++-+++++++--+++---++++-+\|| |||||\--+-++------+++--+--+-+-++----------++-+----+++++-+++--+-+-+++++++--/| ||| |||| |||||| | || || ||||
|
||||
||| || ||| | || ||||||| ||| |||| |||| ||||| /-+-++------+++--+--+-+-++--------\ || | ||||| ||| | | ||||||| /+--+++-++++-++++++-+-++-++\||||
|
||||
||| || ||| | || ||||||| ||| |||| |||| ||||| | | || ||| | | | || | || | ||||| ||| | | ||||||| || ||| |||| |||||| | || |||||||
|
||||
||| || ||| | || ||||||| |\+---++++-++++-+++++-+-+-++------+++--+--/ | || /---+-++-+----+++++-+++--+-+-+++++++--++--+++-++++\|||||| | || |||||||
|
||||
||| || ||| | || ||\++++--+-+---++++-++++-+++++-+-+-++------+++--+----+-++----+---+-++-+----+++++-+++--+-+-+++++++--++--+/| ||||||||||| | || |||||||
|
||||
||| || ||| | || || |||| | | |||| |||| \++++-+-+-++------+++--+----+-++----+---+-++-+----+++++-+++--+-+-+++++++--++--+-+-++++++++/|| | || |||||||
|
||||
||| || ||| | || || |v|| | | /++++-++++--++++-+-+-++------+++--+----+-++-\ | | || | ||||| ||| | | ||||||| || | | |||||||| || | || |||||||
|
||||
||v || /+++--+-++-++-++++--+-+--+++++-++++--++++-+-+-++------+++--+----+-++-+--+---+-++-+----+++++-+++--+-+\||||||| || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | ||||| |||| |||| | | || ||| |/---+-++-+-\| | || | ||||| ||| | ||||||||| || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | ||||| |||| |||| | | || ||| || | || | ||/--+-++-+----+++++-+++--+-+++++++++\ || | | |||||||| || | || |||||||
|
||||
||| || |||| | || || |||| | | |||\+-++++--+/|| | | || ||| || \-++-+-+++--+-++-+----+++++-+++--+-++++++++++-++--+-+-++++++++-++-+-++-+++++/|
|
||||
||| || |||| | || || |||| | | ||| | |||| | || | | || ||| || || | ||| | || | ||||| ||| | |||||||||| \+--+-+-++++++++-++-+-++-++/|| |
|
||||
||| || |||| \-++-++-++++--+-+--+++-+-++++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++--/ | | ||\+++++-++-+-++-++-++-/
|
||||
||| || |||| || || |||| | | ||| | \+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++-----+-+-++-+++++-++-+-/| || ||
|
||||
||| || |||| ||/++-++++--+-+--+++-+--+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++++-+++--+-++++++++++-----+-+\|| ||||| || | | || ||
|
||||
||| || |||\----+++++-++++--+-+--+++-+--+++--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++/| ||| | |||||||||| | |||| ||||| || | | || ||
|
||||
||| || ||| ||||| |||| | | ||| | ||| | || | | || ||| || || | ||| | || | ||| | ||| \-++++++++++-----/ |||| ||||| || | | || ||
|
||||
|\+-++-+++-----+++++-+++/ | | ||| | ||\--+-++-+-+-++------+++--++-----++-+-+++--+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-+--+-+/ ||
|
||||
| | || ||| ||||| ||| | | ||| | || | || | | || ||| || || | |||/-+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-+\ | | ||
|
||||
| | || ||| ||||| ||| /-+-+--+++-+--++\ | || | | || /----+++--++-----++-+-++++-+-++-+----+++-+-+++----++++++++++-------++++-+++++-++-++-+-+--++-\
|
||||
| | || ||| ||||| ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | \++-+-+++----++++++++++-------++++-+++++-++-++-+-/ || |
|
||||
| | || ||\-----+++/| ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | |\-+-+++----++++++++++-------/||| ||||| || || | || |
|
||||
| | || || /---+++-+-+++-+-+-+--+++-+--+++--+-++-+-+-++-+----+++--++-----++-+-++++-+-++-+-----+--+-+++----++++++++++--\ ||| ||||| || || | || |
|
||||
\-+-++-++--+---/|| | ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | | | \++----++++++++++--+-----+++-/|||| || || | || |
|
||||
| || || | || | ||| | | | ||| | ||| | || | | || | ||| || || | |||| | || | | | || |||||||||| | ||| |||| || || | || |
|
||||
| || || | \+-+-+++-+-+-+--+++-+--+++--+-/| | | || | ||| || || | |||| | || | | | ||/---++++++++++--+-----+++--++++-++-++-+\ || |
|
||||
| || || /+-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++-+----+++-\|| || | |||| | || | | | ||| |||||||||| | ||| ||^| || || || || |
|
||||
| || || || | | ||| | | | ||| | ||| | | | | || | ||| ||| || | |||| | || | | | ||| |||||||||| | ||| |||| || || || || |
|
||||
| || || || | | ||| | | | ||| | ||| | | | | || | ||| ||| || | ||||/+-++-+-----+--+-\||| |||||||||| | ||| |||| || || || || |
|
||||
/-+-++-++-++-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++\| ||| ||| || | |||\++-++-+-----+--+-++++---++++++++++--+-----+++--++++-++-+/ || || |
|
||||
| | ||/++-++-----+-+-+++-+-+-+--+++-+--+++--+--+-+-+-++++----+++-+++\ || | ||| || || | | | |||| |||||||||| | ||| |||| || | || || |
|
||||
| | ||||| || | | ||| | |/+--+++-+--+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----+--+-++++---++++++++++--+-----+++-\|||| || | || || |
|
||||
| | |||||/++-----+-+-+++\| ||| ||| \--+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----+--+-++++---++++++++++--+-----+++-++/|| || | || || |
|
||||
| | |||||||| | | ||||| ||| |\+----+++--+--+-+-+-++++----+++-++++----++-+-+++-++-++-+-----/ | |||| ||||||||\+--+-----+++-++-++-++-+--++---/| |
|
||||
| | |||||||| | | ||||| ||| | | ||| | | | | |||| ||| |||| || | ||| || || | | |||| |||||||| | | ||| || || || | || | |
|
||||
| | |||||||| | | ||||| ||| | | ||| | | | | |||| \++-++++--->++-+-+++-++-++-+--------+-++++---++++++++-+--+-----+++-++-++-++-/ || | |
|
||||
| | |||||||| | | ||||| ||| | | /-+++--+--+-+-+-++++-----++-++++\ || | ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| | | | ||| | | | | |||| || ||||| || | ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| \-+--+-+++--+--+-+-+-++++-----++-+++++>--++-/ ||| || || | | |||| |||||||| | | ||| || || || || | |
|
||||
| | |||||||| | | ||||| ||| /+--+-+++--+--+\| | |||| || ||||| || ||| || || | | |||\---++++++++-+--+-----+++-++-++-++----+/ | |
|
||||
| \-++++++++-----+-+-+++++-+++---++--+-/|| | ||| | |||| || ||||| /++---+++-++-++-+--------+\||| |||||||| | | ||| || || || | | |
|
||||
| |||||||| | | ||||| ||| || | || | \++-+-++++-----++-+++++--+++---+++-++-++-+--------+++/| |||||||| | | ||| || || || | | |
|
||||
| ||||||\+-----+-+-+++++-+++---++--+--++--+---++-+-++++-----++-/|||| ||| ||| || ||/+--------+++-+----++++++++-+--+-----+++-++-++-++----+\ | |
|
||||
| |||||| | | \-+++++-+++---++--+--++--+---++-+-++++-----++--++++--+++---+++-++-++++--------/|| | ||||||\+-+--+-----+++-++-/|/++----++\ | |
|
||||
| |||||| | | ||||| ||| || | \+--+---++-+-++++-----++--++++--+++---+++-++-++++---------++-+----++++/| | | | ||| || |||| ||| | |
|
||||
| |||||| | | ||||| ||| || | | | || | |||| || |||| |\+---+++-++-++++---------++-+----++++-+-+-+--+-----+++-++--++/| ||| | |
|
||||
| |||||| | /+---+++++-+++---++--+---+--+---++-+-++++-----++--++++--+-+---+++-++-++++---------++-+----++++-+-+-+--+\ ||| || || | ||| | |
|
||||
| |||||\-+----++---+++/| ||| || | | | || | |||| || |||| | | ||| || |||| || | |||| | | | || ||| || || | ||| | |
|
||||
| ||||| | /-++---+++-+-+++---++--+---+--+---++-+-++++-----++--++++-\| \---+++-++-++++---------++-+----++++-+-+-+--++----+++-++--/| | ||| | |
|
||||
| ||||| | | || ||| | ||\---++--+---+--+---++-+-++++-----++--++++-++-----+++-++-+/|| || | /-++++-+-+-+--++----+++-++---+-+----+++-\ | |
|
||||
| ||||| | | || ||| | || \+--+---+--+---/| | |||| || |||| || ||| || | || || | | |||| | | | || /+++-++---+-+----+++-+-+\|
|
||||
| ||||| | | || ||| | || | | | | | | |||| || |||| || ||| \+-+-++---------+/ | | |||| | | | || |||| || | | ||| | |||
|
||||
| ||||| | | || ||| | |\-----+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-++---------+--+--+-++++-+-+-+--++---++++-/| | | ||| | |||
|
||||
| ||||| | | || ||| | \------+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-++---------+--+--+-++++-+-+-+--++---+++/ | | | ||| | |||
|
||||
| ||||| | | || \++-+--------+--+---+--+----+-+-++++-----++--++++-++-----+++--+-+-+/ | | | |||| |/+-+--++---+++---+--\| | ||| | |||
|
||||
\---+++++--+--+-++----++-+--------+--+---+--+----+-+-++/| || |||| || ||| | | | | | | |||| ||| | || ||| | || | ||| | |||
|
||||
||||| | | || || \--------+--+---/ | | | || | || |||| || ||| | | \----------+--+--+-++++-+++-+--++---+++---+--++-+----+/| | |||
|
||||
||||| | | || /--++----------+--+--\ | | \-++-+-----++--++++-++-----+++--+-+------------+--+--+-++++-+++-+--++---+++---+--++-/ | | | |||
|
||||
||||| | | || | || | | | \----+---++-+-----++--++++-++-----+++--+-+------------+--/ | |||| ||| | || ||| | || | | | |||
|
||||
||||| | | || | || | | | | |\-+-----++--++++-++-----+++--+-+------------+-----+-++++-+++-+--++---++/ | || | | | |||
|
||||
||||| \--+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++--+-+------------+-----+-++++-+++-+--/| || | || | | | |||
|
||||
|\+++-----+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++--+-/ | | |||| ||| | | || | || | | | |||
|
||||
| ||| /--+-++-+--++----------+--+--+--------+---+--+-----++--++++-++-----+++\ | | | |||| ||| | | || | || | | | |||
|
||||
| ||| | | || | || | | | | | \-----++--++++-++-----++++-+--------------+-----+-++++-+++-+---+---++----+--++------+-+-+-++/
|
||||
| ||| | | || |/-++----------+--+--+--------+---+----\ || |||| || |||| | | | |||| ||| | | || v || | | | ||
|
||||
| ||| | | || || || | | | \---+----+---++--++++-++-----++++-/ | | |||| ||| | | || | || | | | ||
|
||||
/--+-+++--+-\| || || || | | | | | || |||| || |||| | | |||| ||| | | || | || | | | ||
|
||||
| | ||| | || || \+-++----------+->+--/ | | || |\++-++-----/||| | | |||| ||| | | || | || | | | ||
|
||||
| | ||| | || || | || | | | | || | || || ||| /+-----+-++++-+++-+---+---++----+--++------+-+-+-++\
|
||||
| | ||\--+-++-++--+-++--->------+--+---------------+----+---++--+-++-++------+++---------------++-----+-/||| ||| | | || | || | | | |||
|
||||
| | || | || || | || \--+---------------+----+---+/ | || || ||| || | ||| |\+-+---+---++----+--/| | | | |||
|
||||
| | || | || || | \+-------------+---------------+----+---+---+-++-++------+++---------------++-----+--++/ | | | | || | | | | | |||
|
||||
| | || | |\-++--+--+-------------+---------------+----+---+---+-++-/| |\+---------------++-----+--++--+-+-/ | || | \------+-/ | |||
|
||||
| | || | | || | | | | | | | || \------+-+---------------+/ | || | | | || | | | |||
|
||||
| \-++---+-+--++--+--/ \---------------+----+---+---+-+/ | | | \--++--+-+-----+---++----+----------+---/ |||
|
||||
| |\---+-+--++--+--------------------------------+----+---+---+-+----------+-+---------------+---------/| | \-----+---++----+----------+-----/||
|
||||
\----+----+-/ || | \----+---/ | | | | | | | | || | | ||
|
||||
| | || | | \-+----------+-+---------------+----------/ | | || | | ||
|
||||
| | \+--+-------------------------------------+---------+----------+-+---------------+-------------+-------/ \+----+----------+------/|
|
||||
| | \--+-------------------------------------+---------+----------+-+---------------+-------------+------------/ | | |
|
||||
| \--------+-------------------------------------+---------+----------+-/ | | | | |
|
||||
| \-------------------------------------/ | \-----------------+-------------+-----------------/ | |
|
||||
| | | \----------------------------/ |
|
||||
\-------------------------------------------------------------/ \--------------------------------------------------/
|
||||
@@ -0,0 +1,32 @@
|
||||
################################
|
||||
#########################.G.####
|
||||
#########################....###
|
||||
##################.G.........###
|
||||
##################.##.......####
|
||||
#################...#.........##
|
||||
################..............##
|
||||
######..########...G...#.#....##
|
||||
#####....######.G.GG..G..##.####
|
||||
#######.#####G............#.####
|
||||
#####.........G..G......#...####
|
||||
#####..G......G..........G....##
|
||||
######GG......#####........E.###
|
||||
#######......#######..........##
|
||||
######...G.G#########........###
|
||||
######......#########.....E..###
|
||||
#####.......#########........###
|
||||
#####....G..#########........###
|
||||
######.##.#.#########......#####
|
||||
#######......#######.......#####
|
||||
#######.......#####....E...#####
|
||||
##.G..#.##............##.....###
|
||||
#.....#........###..#.#.....####
|
||||
#.........E.E...#####.#.#....###
|
||||
######......#.....###...#.#.E###
|
||||
#####........##...###..####..###
|
||||
####...G#.##....E####E.####...##
|
||||
####.#########....###E.####....#
|
||||
###...#######.....###E.####....#
|
||||
####..#######.##.##########...##
|
||||
####..######################.###
|
||||
################################
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+234
-48
@@ -21,6 +21,7 @@ struct Cart: Equatable, Comparable {
|
||||
var loc = GridPoint(X: 0, Y: 0)
|
||||
var dir = Direction.up
|
||||
var intersection = Sequence.left
|
||||
var removed = false
|
||||
var dirValue: (Int, Int) {
|
||||
get {
|
||||
switch dir {
|
||||
@@ -39,12 +40,10 @@ struct Cart: Equatable, Comparable {
|
||||
|
||||
mutating func changeDirection(with map: Character) {
|
||||
func rotateRight() { dir = Direction(rawValue: dir.rawValue + 1) ?? Direction.up }
|
||||
func rotateLeft() { dir = Direction(rawValue: dir.rawValue - 1) ?? Direction.up }
|
||||
func rotateLeft() { dir = Direction(rawValue: dir.rawValue - 1) ?? Direction.left }
|
||||
func increaseSequence() { intersection = Sequence(rawValue: intersection.rawValue + 1) ?? Sequence.left }
|
||||
|
||||
// No change
|
||||
if map == "-" || map == "|" { return }
|
||||
// Execute intersection sequence
|
||||
if map == "+" {
|
||||
switch intersection {
|
||||
case .left : rotateLeft()
|
||||
@@ -54,7 +53,6 @@ struct Cart: Equatable, Comparable {
|
||||
increaseSequence()
|
||||
return
|
||||
}
|
||||
// Turn to follow curve
|
||||
switch dir {
|
||||
case .up, .down :
|
||||
if map == "/" { rotateRight() }
|
||||
@@ -86,21 +84,142 @@ struct Cart: Equatable, Comparable {
|
||||
// 1. '<' or '>' => '-'
|
||||
// 2. '^' or 'v' => '|'
|
||||
class Madness {
|
||||
var track: [[Character]] = []
|
||||
var width = 0
|
||||
var height = 0
|
||||
var carts: [Cart] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt'
|
||||
init(withFile filename: String) {
|
||||
let trackFile = Tools.readFile(fromPath: filename)
|
||||
var trackStrings = trackFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = trackStrings.last, lastStr.count == 0 else { return }
|
||||
trackStrings.removeLast() // empty string
|
||||
parseData(withStars: trackStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString trackFile: String) {
|
||||
let trackStrings = trackFile.components(separatedBy: "\n")
|
||||
parseData(withStars: trackStrings)
|
||||
}
|
||||
|
||||
func parseData(withStars trackArray: [String]) {
|
||||
guard trackArray.count > 0 else { print("Error Parsing"); return }
|
||||
width = trackArray[0].count
|
||||
height = trackArray.count
|
||||
for line in trackArray {
|
||||
track.append(Array(line))
|
||||
}
|
||||
|
||||
func newCart(at loc: (Int, Int), with direction: Direction) {
|
||||
carts.append(Cart(loc: GridPoint(X: loc.0, Y: loc.1), dir: direction, intersection: Sequence.left, removed: false))
|
||||
switch direction {
|
||||
case .up, .down : track[loc.1][loc.0] = "|"
|
||||
case .left, .right: track[loc.1][loc.0] = "-"
|
||||
}
|
||||
}
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch track[j][i] {
|
||||
case "^": newCart(at: (i, j), with: Direction.up)
|
||||
case "v": newCart(at: (i, j), with: Direction.down)
|
||||
case "<": newCart(at: (i, j), with: Direction.left)
|
||||
case ">": newCart(at: (i, j), with: Direction.right)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTrack(at loc: GridPoint) -> Character {
|
||||
guard loc.X >= 0 && loc.Y >= 0 && loc.X < width && loc.Y < height else { print("getTrack out of range"); return "#" }
|
||||
return track[loc.Y][loc.X]
|
||||
}
|
||||
|
||||
func collision(removeCrash: Bool) -> GridPoint? {
|
||||
var retVal: GridPoint? = nil
|
||||
var dupTest: [GridPoint : Int] = [:]
|
||||
for index in 0..<carts.count {
|
||||
if !carts[index].removed {
|
||||
if dupTest[carts[index].loc] != nil {
|
||||
if removeCrash {
|
||||
carts[index].removed = true
|
||||
carts[dupTest[carts[index].loc]!].removed = true
|
||||
} else {
|
||||
return carts[index].loc
|
||||
}
|
||||
} else {
|
||||
dupTest[carts[index].loc] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
let notRemoved = carts.filter { $0.removed == false }
|
||||
if notRemoved.count == 1 {
|
||||
retVal = notRemoved[0].loc
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Start of Tick:
|
||||
// 1. order carts by location
|
||||
// 2. move cart one step in it's direction
|
||||
// 3. Look to see where we landed
|
||||
// a. other cart => CRASH
|
||||
// b. '-' or '|' is a straight track => do nothing
|
||||
// c. '\' => rotate right
|
||||
// d. '/' => rotate left
|
||||
// e. '+' => [Left, Straight, Right] sequense for this cart
|
||||
func tick(andRemove remove: Bool) -> GridPoint? {
|
||||
var collided: GridPoint? = nil
|
||||
carts.sort()
|
||||
for index in 0..<carts.count {
|
||||
if !carts[index].removed {
|
||||
carts[index].move()
|
||||
collided = collision(removeCrash: remove)
|
||||
if collided != nil && !remove {
|
||||
break
|
||||
}
|
||||
let track = getTrack(at: carts[index].loc)
|
||||
carts[index].changeDirection(with: track)
|
||||
}
|
||||
}
|
||||
return collided
|
||||
}
|
||||
}
|
||||
|
||||
class Day13: AOCDay {
|
||||
lazy var tests: (() -> ()) = day13Tests
|
||||
lazy var final: (() -> ()) = day13Final
|
||||
|
||||
let testData =
|
||||
"/->-\\ \n" +
|
||||
"| | /----\\\n" +
|
||||
"| /-+--+-\\ |\n" +
|
||||
"| | | | v |\n" +
|
||||
"\\-+-/ \\-+--/\n" +
|
||||
" \\------/ "
|
||||
|
||||
let testData2 =
|
||||
"/>-<\\ \n" +
|
||||
"| | \n" +
|
||||
"| /<+-\\\n" +
|
||||
"| | | v\n" +
|
||||
"\\>+</ |\n" +
|
||||
" | ^\n" +
|
||||
" \\<->/"
|
||||
|
||||
func testCartMove() {
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left)
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car.move()
|
||||
XCTAssertEqual(test: "testCartMove", withExpression: (car.loc.X == 10 && car.loc.Y == 9))
|
||||
}
|
||||
|
||||
func testCartChangeDirection() {
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left)
|
||||
var car = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car.move()
|
||||
car.changeDirection(with: "-")
|
||||
car.move()
|
||||
@@ -128,67 +247,134 @@ class Day13: AOCDay {
|
||||
|
||||
func testCartSort() {
|
||||
var cars: [Cart] = []
|
||||
cars.append(Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left))
|
||||
cars.append(Cart(loc: GridPoint(X: 5, Y:22), dir: Direction.up, intersection: Sequence.left))
|
||||
cars.append(Cart(loc: GridPoint(X: 22, Y:5), dir: Direction.up, intersection: Sequence.left))
|
||||
cars.append(Cart(loc: GridPoint(X: 2, Y:10), dir: Direction.up, intersection: Sequence.left))
|
||||
// for car in cars { print("\(car)")}
|
||||
cars.append(Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 5, Y:22), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 22, Y:5), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.append(Cart(loc: GridPoint(X: 2, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false))
|
||||
cars.sort()
|
||||
// print("")
|
||||
// for car in cars { print("\(car)")}
|
||||
let lastCar = cars.last!
|
||||
XCTAssertEqual(test: "testCartSort last", withExpression: (lastCar.loc.X == 5 && lastCar.loc.Y == 22))
|
||||
}
|
||||
|
||||
func testCartEquatable() {
|
||||
var car1 = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left)
|
||||
var car1 = Cart(loc: GridPoint(X: 10, Y:10), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
car1.move()
|
||||
car1.changeDirection(with: "-")
|
||||
car1.move()
|
||||
// XCTAssertEqual(test: "testCartChangeDirection '-'", withExpression: (car1.loc.X == 10 && car1.loc.Y == 8))
|
||||
let car2 = Cart(loc: GridPoint(X: 10, Y:8), dir: Direction.up, intersection: Sequence.left)
|
||||
let car2 = Cart(loc: GridPoint(X: 10, Y:8), dir: Direction.up, intersection: Sequence.left, removed: false)
|
||||
XCTAssertEqual(test: "testCartEquatable", withExpression: (car1 == car2))
|
||||
}
|
||||
|
||||
func testMadnessInit() {
|
||||
let mad = Madness(withString: testData)
|
||||
printTrack(with: mad)
|
||||
XCTAssertEqual(test: "testMadnessInit string", withExpression: (mad.width == 13 && mad.height == 6))
|
||||
if mad.carts.count != 2 {
|
||||
XCTAssertEqual(test: "testMadnessInit carts count", withExpression: (false))
|
||||
} else {
|
||||
XCTAssertEqual(test: "testMadnessInit carts count", withExpression: (mad.carts.count == 2))
|
||||
XCTAssertEqual(test: "testMadnessInit cart X", withExpression: (mad.carts[0].loc.X == 2))
|
||||
XCTAssertEqual(test: "testMadnessInit cart Y", withExpression: (mad.carts[0].loc.Y == 0))
|
||||
XCTAssertEqual(test: "testMadnessInit cart direction", withExpression: (mad.carts[0].dir == Direction.right))
|
||||
}
|
||||
}
|
||||
|
||||
func testGetTrack() {
|
||||
let mad = Madness(withString: testData)
|
||||
var result = mad.getTrack(at: GridPoint(X: 4, Y: 2))
|
||||
XCTAssertEqual(test: "testGetTrack (5, 3)", withExpression: (result == "+"))
|
||||
result = mad.getTrack(at: GridPoint(X: 2, Y: 0))
|
||||
XCTAssertEqual(test: "testGetTrack (3, 1) convert cart to track", withExpression: (result == "-"))
|
||||
}
|
||||
|
||||
func testCollision() {
|
||||
let mad = Madness(withString: testData)
|
||||
mad.carts[1].loc = mad.carts[0].loc
|
||||
XCTAssertEqual(test: "testCollision", withExpression: (mad.collision(removeCrash: false) != nil))
|
||||
}
|
||||
|
||||
func testTick() {
|
||||
let mad = Madness(withString: testData)
|
||||
let oldcart = mad.carts[0]
|
||||
let collided = mad.tick(andRemove: false)
|
||||
let newcart = mad.carts[0]
|
||||
XCTAssertEqual(test: "testTick", withExpression: (oldcart != newcart))
|
||||
XCTAssertEqual(test: "testTick", withExpression: (collided == nil))
|
||||
}
|
||||
|
||||
func printTrack(with mad: Madness) {
|
||||
func cartLoc(at loc: GridPoint) -> (Bool, Character) {
|
||||
var retVal: (Bool, Character) = (false, " ")
|
||||
for cart in mad.carts {
|
||||
if cart.loc == loc && !cart.removed{
|
||||
switch cart.dir {
|
||||
case .up : retVal = (true, "^")
|
||||
case .down : retVal = (true, "v")
|
||||
case .left : retVal = (true, "<")
|
||||
case .right: retVal = (true, ">")
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
for j in 0..<mad.height {
|
||||
for i in 0..<mad.width {
|
||||
let cartIcon = cartLoc(at: GridPoint(X: i, Y: j))
|
||||
if cartIcon.0 {
|
||||
print("\(cartIcon.1)", terminator: " ")
|
||||
} else {
|
||||
print("\(mad.getTrack(at: GridPoint(X: i, Y: j)))", terminator: " ")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
func testRun() {
|
||||
var mad = Madness(withString: testData)
|
||||
printTrack(with: mad)
|
||||
var crash: GridPoint?
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: false)
|
||||
} while crash == nil
|
||||
// print("Collision location Part1: (\(crash!))")
|
||||
XCTAssertEqual(test: "testRun Part 1", withExpression: (crash! == GridPoint(X: 7, Y: 3)))
|
||||
|
||||
mad = Madness(withString: testData2)
|
||||
printTrack(with: mad)
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: true)
|
||||
} while crash == nil
|
||||
// print("Last Cart location Part2: (\(crash!))")
|
||||
XCTAssertEqual(test: "testRun Part 2", withExpression: (crash! == GridPoint(X: 6, Y: 4)))
|
||||
}
|
||||
|
||||
func day13Tests() {
|
||||
testCartMove()
|
||||
testCartChangeDirection()
|
||||
testCartSort()
|
||||
testCartEquatable()
|
||||
testMadnessInit()
|
||||
testGetTrack()
|
||||
testCollision()
|
||||
testTick()
|
||||
testRun()
|
||||
}
|
||||
|
||||
func day13Final() {
|
||||
let retVal = "None"
|
||||
print("Answer to part 1 is: \(retVal)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
var mad = Madness(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt")
|
||||
var crash: GridPoint?
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: false)
|
||||
} while crash == nil
|
||||
print("Answer to part 1 is: \(crash!)")
|
||||
|
||||
mad = Madness(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day13.txt")
|
||||
repeat {
|
||||
crash = mad.tick(andRemove: true)
|
||||
} while crash == nil
|
||||
print("Answer to part 2 is: \(crash!)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Start of Tick:
|
||||
// 1. order carts by location
|
||||
// 2. move cart one step in it's direction
|
||||
// 3. Look to see where we landed
|
||||
// a. other cart => CRASH
|
||||
// b. '-' or '|' is a straight track => do nothing
|
||||
// c. '\' => rotate right
|
||||
// d. '/' => rotate left
|
||||
// e. '+' => [Left, Straight, Right] sequense for this cart
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// We'll need to figure out the size of the grid
|
||||
// - scan and find the number of carts and their locations and direction
|
||||
// - convert the carts to "track"
|
||||
// - At intersections, each cart executes their own "sequense"
|
||||
// - Left, Straight, Right, repeat
|
||||
// - move carts in order of Top, Left to Bottom, Right
|
||||
// - order carts by (x,y) position, then execute moves
|
||||
// Watch for first crash and report crash location
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 14: Chocolate Charts"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Chocolate {
|
||||
var score: [Int] = [3, 7, 1, 0]
|
||||
var scoreStr = "3710"
|
||||
var elf: [Int] = [0, 1]
|
||||
var lf2 = 3
|
||||
|
||||
func moveForward() {
|
||||
for index in 0..<elf.count {
|
||||
let currentRecipe = elf[index]
|
||||
let moveCount = score[elf[index]] + 1
|
||||
elf[index] = moveCount + currentRecipe
|
||||
if elf[index] >= score.count {
|
||||
elf[index] -= score.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func nextRecipe() {
|
||||
var sum = 0
|
||||
for index in 0..<elf.count {
|
||||
sum += score[elf[index]]
|
||||
}
|
||||
let strsum = Array(String(sum))
|
||||
for i in 0..<strsum.count {
|
||||
let newScore = String(strsum[i])
|
||||
score.append(Int(newScore)!)
|
||||
scoreStr += newScore
|
||||
}
|
||||
}
|
||||
|
||||
func get10RecipeScore(after index: Int) -> String {
|
||||
var retVal = ""
|
||||
repeat {
|
||||
nextRecipe()
|
||||
moveForward()
|
||||
} while score.count < index+10
|
||||
for i in index..<index+10 {
|
||||
retVal += String(score[i])
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func getNumBefore(pattern: String) -> Int {
|
||||
var distance = 0
|
||||
let range = scoreStr.range(of: pattern)
|
||||
if let range = range {
|
||||
distance = scoreStr.distance(from: scoreStr.startIndex, to: range.lowerBound)
|
||||
}
|
||||
return distance
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Day14: AOCDay {
|
||||
lazy var tests: (() -> ()) = day14Tests
|
||||
lazy var final: (() -> ()) = day14Final
|
||||
|
||||
func testNextRecipe() {
|
||||
let cho = Chocolate()
|
||||
cho.nextRecipe()
|
||||
guard cho.score.count == 6 else {
|
||||
XCTAssertEqual(test: "testNextRecipe fail count", withExpression: (false))
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(test: "testNextRecipe", withExpression: (cho.score[4] == 1 && cho.score[5] == 0))
|
||||
}
|
||||
|
||||
func testMoveForward() {
|
||||
let cho = Chocolate()
|
||||
cho.nextRecipe()
|
||||
cho.moveForward()
|
||||
XCTAssertEqual(test: "testMoveForward", withExpression: (cho.elf[0] == 4 && cho.elf[1] == 3))
|
||||
}
|
||||
|
||||
func testGet10RecipeScore() {
|
||||
var cho = Chocolate()
|
||||
var answer = cho.get10RecipeScore(after: 9)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 9", withExpression: (answer == "5158916779"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 5)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 5", withExpression: (answer == "0124515891"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 18)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 18", withExpression: (answer == "9251071085"))
|
||||
cho = Chocolate()
|
||||
answer = cho.get10RecipeScore(after: 2018)
|
||||
XCTAssertEqual(test: "testGet10RecipeScore 2018", withExpression: (answer == "5941429882"))
|
||||
}
|
||||
|
||||
func testGetNumBefore() {
|
||||
let cho = Chocolate()
|
||||
_ = cho.get10RecipeScore(after: 2018)
|
||||
var answer = cho.getNumBefore(pattern: "51589")
|
||||
XCTAssertEqual(test: "testGetNumBefore 51589", withExpression: (answer == 9))
|
||||
answer = cho.getNumBefore(pattern: "01245")
|
||||
XCTAssertEqual(test: "testGetNumBefore 01245", withExpression: (answer == 5))
|
||||
answer = cho.getNumBefore(pattern: "92510")
|
||||
XCTAssertEqual(test: "testGetNumBefore 92510", withExpression: (answer == 18))
|
||||
answer = cho.getNumBefore(pattern: "59414")
|
||||
XCTAssertEqual(test: "testGetNumBefore 59414", withExpression: (answer == 2018))
|
||||
}
|
||||
|
||||
func day14Tests() {
|
||||
testNextRecipe()
|
||||
testMoveForward()
|
||||
testGet10RecipeScore()
|
||||
testGetNumBefore()
|
||||
}
|
||||
|
||||
func day14Final() {
|
||||
let cho = Chocolate()
|
||||
let answer = cho.get10RecipeScore(after: 580741)
|
||||
print("Answer to part 1 is: \(answer)")
|
||||
// let answer = cho.get10RecipeScore(after: 112580741)
|
||||
// let dist = cho.getNumBefore(pattern: "580741")
|
||||
// print("Answer to part 2 is: \(dist)")
|
||||
print("Brute forced part 2 - takes too long")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,789 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 15: Beverage Bandits"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum State: Int {
|
||||
case Unknown = -4
|
||||
case Wall = -3
|
||||
case Open = 0
|
||||
case Elf = 1
|
||||
case Goblin = 2
|
||||
}
|
||||
|
||||
struct Entity: Equatable, Comparable {
|
||||
var kind: State
|
||||
var loc: GridPoint
|
||||
var power: Int
|
||||
var hitPts: Int
|
||||
|
||||
init(kind: State, loc: GridPoint, power: Int = 3, hitPts: Int = 200) {
|
||||
self.kind = kind
|
||||
self.loc = loc
|
||||
self.power = power
|
||||
self.hitPts = hitPts
|
||||
}
|
||||
static func == (lhs: Entity, rhs: Entity) -> Bool {
|
||||
return (lhs.loc == rhs.loc) && (lhs.power == rhs.power) && (lhs.hitPts == rhs.hitPts)
|
||||
}
|
||||
|
||||
static func < (lhs: Entity, rhs: Entity) -> Bool {
|
||||
return lhs.loc < rhs.loc
|
||||
}
|
||||
}
|
||||
|
||||
class Beverage {
|
||||
var entities: [Entity] = []
|
||||
var maze: [[Character]] = []
|
||||
var nummaze: [[State]] = []
|
||||
var entityDict: [GridPoint : Int] = [:]
|
||||
var width = 0
|
||||
var height = 0
|
||||
var rounds = 0
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt'
|
||||
init(withFile filename: String) {
|
||||
let mazeFile = Tools.readFile(fromPath: filename)
|
||||
var mazeStrings = mazeFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = mazeStrings.last, lastStr.count == 0 else { return }
|
||||
mazeStrings.removeLast() // empty string
|
||||
parseData(intoGrid: mazeStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString mazeFile: String) {
|
||||
let mazeStrings = mazeFile.components(separatedBy: "\n")
|
||||
parseData(intoGrid: mazeStrings)
|
||||
}
|
||||
|
||||
func parseData(intoGrid mazeArray: [String]) {
|
||||
guard mazeArray.count > 0 else { print("Error Parsing"); return }
|
||||
width = mazeArray[0].count
|
||||
height = mazeArray.count
|
||||
for line in mazeArray {
|
||||
maze.append(Array(line))
|
||||
}
|
||||
|
||||
func newEntity(type kind: State, at loc: (Int, Int)) {
|
||||
var power = 3
|
||||
if kind == .Elf {
|
||||
power = 12
|
||||
}
|
||||
entities.append(Entity(kind: kind, loc: GridPoint(X: loc.0, Y: loc.1), power: power))
|
||||
}
|
||||
|
||||
for _ in 0..<height {
|
||||
nummaze.append(Array(repeating: .Wall, count: width))
|
||||
}
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch maze[j][i] {
|
||||
case "#": break // we initialized this grid to all "walls"
|
||||
case ".": nummaze[j][i] = .Open
|
||||
case "G": nummaze[j][i] = .Goblin
|
||||
newEntity(type: .Goblin,at: (i, j))
|
||||
case "E": nummaze[j][i] = .Elf
|
||||
newEntity(type: .Elf, at: (i, j))
|
||||
default: nummaze[j][i] = .Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
updateEntityDict()
|
||||
entities.sort()
|
||||
}
|
||||
|
||||
func updateEntityDict() {
|
||||
entityDict = [:]
|
||||
for index in 0..<entities.count {
|
||||
if entities[index].hitPts > 0 {
|
||||
entityDict[entities[index].loc] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the entities (reading order) and repopulate the nummaze map
|
||||
func updateMaze() {
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
if nummaze[j][i] == .Elf || nummaze[j][i] == .Goblin {
|
||||
nummaze[j][i] = .Open
|
||||
}
|
||||
}
|
||||
}
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 {
|
||||
switch entity.kind {
|
||||
case .Elf: nummaze[entity.loc.Y][entity.loc.X] = .Elf
|
||||
case .Goblin: nummaze[entity.loc.Y][entity.loc.X] = .Goblin
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func printMaze(with maze: [[Int]]) {
|
||||
let width = maze[0].count
|
||||
let height = maze.count
|
||||
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch maze[j][i] {
|
||||
case -4: print("?", terminator: "")
|
||||
case -3: print("#", terminator: "")
|
||||
case -2: print("G", terminator: "")
|
||||
case -1: print("E", terminator: "")
|
||||
case 0: print(".", terminator: "")
|
||||
default: print("\(maze[j][i])", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
// Return the distance and the preferred direction (direction only valid by reversing the request; i.e. swapping orig and dest)
|
||||
func distance(from origin: GridPoint, to dest: GridPoint) -> (dist: Int, dir: GridPoint) {
|
||||
var retVal = (dist: -1, dir: GridPoint(X:0, Y:0))
|
||||
var distMaze: [[Int]] = []
|
||||
for row in nummaze {
|
||||
distMaze.append(row.map { if $0.rawValue > 0 { return -$0.rawValue } else { return $0.rawValue } })
|
||||
}
|
||||
func testAndQueue(for point: GridPoint, on wave: Int, in queue: inout [GridPoint]) {
|
||||
if distMaze[point.Y][point.X] == 0 {
|
||||
distMaze[point.Y][point.X] = wave
|
||||
queue.append(point)
|
||||
}
|
||||
}
|
||||
|
||||
var wave = 1
|
||||
var done = false
|
||||
var queue: [GridPoint] = [origin]
|
||||
distMaze[dest.Y][dest.X] = 0
|
||||
while !done {
|
||||
var newQueue: [GridPoint] = []
|
||||
for point in queue {
|
||||
testAndQueue(for: point.up, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.down, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.left, on: wave, in: &newQueue)
|
||||
testAndQueue(for: point.right, on: wave, in: &newQueue)
|
||||
}
|
||||
queue = newQueue
|
||||
if queue.contains(dest) {
|
||||
done = true
|
||||
retVal.dist = distMaze[dest.Y][dest.X]
|
||||
if wave == 1 {
|
||||
retVal.dir = origin - dest
|
||||
}
|
||||
}
|
||||
done = done || (newQueue.count == 0)
|
||||
wave += 1
|
||||
}
|
||||
// printMaze(with: distMaze)
|
||||
|
||||
// Determin direction by locating the lowest distance count via reading-order
|
||||
if retVal.dir == GridDir.none {
|
||||
if distMaze[dest.up.Y][dest.up.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.up
|
||||
} else if distMaze[dest.left.Y][dest.left.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.left
|
||||
} else if distMaze[dest.right.Y][dest.right.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.right
|
||||
} else if distMaze[dest.down.Y][dest.down.X] == retVal.dist-1 {
|
||||
retVal.dir = GridDir.down
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func findNearestTarget(for attacker: Entity) -> GridPoint {
|
||||
var retVal = GridPoint(X: -1, Y: -1)
|
||||
var list: [GridPoint : Bool] = [:]
|
||||
func testAnAddToList(for point: GridPoint) {
|
||||
if nummaze[point.Y][point.X] == .Open {
|
||||
list[point] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Create a list of reachables
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 && entity.kind == enemy(of: attacker) {
|
||||
testAnAddToList(for: entity.loc.up)
|
||||
testAnAddToList(for: entity.loc.down)
|
||||
testAnAddToList(for: entity.loc.left)
|
||||
testAnAddToList(for: entity.loc.right)
|
||||
}
|
||||
}
|
||||
let inRange = Array(list.keys)
|
||||
var reachable: [GridPoint : Int] = [:]
|
||||
|
||||
// Create a sorted list of Nearest targets from reachables
|
||||
var minDist = width + height
|
||||
for target in inRange {
|
||||
let dist = distance(from: attacker.loc, to: target).dist
|
||||
if dist > 0 {
|
||||
minDist = min(dist, minDist)
|
||||
reachable[target] = dist
|
||||
}
|
||||
}
|
||||
var nearest = Array(reachable.filter { $0.value == minDist }.keys)
|
||||
nearest.sort()
|
||||
if nearest.count > 0 {
|
||||
retVal = nearest[0]
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func moveDirection(from entity: Entity, to dest: GridPoint) -> GridPoint {
|
||||
// use the reverse map in 'distance' to come up with a preferred direction
|
||||
var retVal = GridPoint(X:0,Y:0)
|
||||
if dest != GridPoint(X: -1, Y: -1) {
|
||||
let dist = distance(from: dest, to: entity.loc)
|
||||
if dist.dist > 0 {
|
||||
retVal = dist.dir
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func round() -> Bool {
|
||||
var done = false
|
||||
// Only sort once per round
|
||||
entities.sort()
|
||||
for index in 0..<entities.count {
|
||||
if entities[index].hitPts > 0 {
|
||||
done = takeTurn(with: index)
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !done {
|
||||
rounds += 1
|
||||
}
|
||||
return done
|
||||
}
|
||||
|
||||
func tabulateScore() -> Int {
|
||||
// sum remaining hitPts
|
||||
var sum = 0
|
||||
for entity in entities {
|
||||
if entity.hitPts > 0 {
|
||||
sum += entity.hitPts
|
||||
}
|
||||
}
|
||||
return sum * rounds
|
||||
}
|
||||
|
||||
let watchIndex = -1
|
||||
|
||||
|
||||
func takeTurn(with entityIndex: Int) -> Bool {
|
||||
//done test
|
||||
let viableEnemy = entities.filter { $0.kind == enemy(of: entities[entityIndex]) && $0.hitPts > 0 }
|
||||
guard viableEnemy.count > 0 else { return true }
|
||||
|
||||
// entityDict must be updated for every action (move or attack)
|
||||
updateEntityDict()
|
||||
// Adjacent to target?
|
||||
var indexOfAdjeacentTarget = adjacent(to: entityIndex)
|
||||
if indexOfAdjeacentTarget == -1 {
|
||||
// find nearest enemy
|
||||
let nearest = findNearestTarget(for: entities[entityIndex])
|
||||
// determine direction to go
|
||||
let direction = moveDirection(from: entities[entityIndex], to: nearest)
|
||||
// print("nearest \(nearest), direction = \(direction)")
|
||||
// move and update dict and map
|
||||
entities[entityIndex].loc = entities[entityIndex].loc + direction
|
||||
if entityIndex == watchIndex {
|
||||
print("\(entities[entityIndex])")
|
||||
print("nearest : \(nearest)")
|
||||
print("direction : \(direction)")
|
||||
}
|
||||
updateEntityDict()
|
||||
updateMaze()
|
||||
}
|
||||
// Check if we moved within range
|
||||
indexOfAdjeacentTarget = adjacent(to: entityIndex)
|
||||
if entityIndex == watchIndex && indexOfAdjeacentTarget > 0 {
|
||||
print("adjacent Target : \(entities[indexOfAdjeacentTarget])")
|
||||
}
|
||||
if indexOfAdjeacentTarget != -1 {
|
||||
attack(from: entities[entityIndex], to: indexOfAdjeacentTarget)
|
||||
updateEntityDict()
|
||||
updateMaze()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func enemy(of entity: Entity) -> State {
|
||||
var retVal = State.Goblin
|
||||
if entity.kind == .Goblin {
|
||||
retVal = .Elf
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Return the index number of the target to attack (or -1 if no target)
|
||||
func adjacent(to subjectIndex: Int) -> Int {
|
||||
var retVal = -1
|
||||
var enemyDict: [GridPoint:Int] = [:] // Loc : HitPts
|
||||
|
||||
func determineEnemyAndQueue(for loc: GridPoint) {
|
||||
if nummaze[loc.Y][loc.X] == enemy(of: entities[subjectIndex]) {
|
||||
updateEntityDict()
|
||||
if let index = entityDict[loc] {
|
||||
enemyDict[loc] = entities[index].hitPts
|
||||
}
|
||||
}
|
||||
}
|
||||
// create list of adjacent enemies
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.up)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.left)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.right)
|
||||
determineEnemyAndQueue(for: entities[subjectIndex].loc.down)
|
||||
|
||||
// sort list by HitPoints, fewest to most order
|
||||
if enemyDict.count > 0 {
|
||||
// find min hit point
|
||||
let minHP = enemyDict.min { a, b in a.value < b.value }?.value ?? -1
|
||||
// gather array of min-hitpoint enemies
|
||||
let minDict = enemyDict.filter {$0.value == minHP}
|
||||
// sort enemies by location in reading-order
|
||||
let enemy = minDict.sorted(by: <)
|
||||
// select the first one
|
||||
retVal = entityDict[enemy[0].key]!
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func attack(from attacker: Entity, to victimIndex: Int) {
|
||||
entities[victimIndex].hitPts = entities[victimIndex].hitPts - attacker.power
|
||||
// print("attacker power = \(attacker.power)")
|
||||
if entities[victimIndex].hitPts <= 0 && entities[victimIndex].kind == .Elf {
|
||||
print("Fail")
|
||||
while true {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class Day15: AOCDay {
|
||||
lazy var tests: (() -> ()) = day15Tests
|
||||
lazy var final: (() -> ()) = day15Final
|
||||
|
||||
let testData1 = """
|
||||
#######
|
||||
#E..G.#
|
||||
#...#.#
|
||||
#.G.#G#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData2 = """
|
||||
#######
|
||||
#.E...#
|
||||
#.....#
|
||||
#...G.#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData3 = """
|
||||
#########
|
||||
#G.....G#
|
||||
#...G...#
|
||||
#...E...#
|
||||
#G.....G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..G..G#
|
||||
#########
|
||||
"""
|
||||
|
||||
let testData4 = """
|
||||
#########
|
||||
#G..G..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..E..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..G..G#
|
||||
#########
|
||||
"""
|
||||
|
||||
let testData5 = """
|
||||
#######
|
||||
#...G.#
|
||||
#..G.G#
|
||||
#.#.#G#
|
||||
#...#E#
|
||||
#.....#
|
||||
#######
|
||||
"""
|
||||
|
||||
let testData6 = """
|
||||
#######
|
||||
#G....#
|
||||
#..G..#
|
||||
#..EG.#
|
||||
#..G..#
|
||||
#...G.#
|
||||
#######
|
||||
"""
|
||||
|
||||
|
||||
let testData7 = """
|
||||
#######
|
||||
#.G...#
|
||||
#...EG#
|
||||
#.#.#G#
|
||||
#..G#E#
|
||||
#.....#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 37 full rounds
|
||||
// Elves win with 982 total hit points left
|
||||
// Outcome: 37 * 982 = 36334
|
||||
let testData8 = """
|
||||
#######
|
||||
#G..#E#
|
||||
#E#E.E#
|
||||
#G.##.#
|
||||
#...#E#
|
||||
#...E.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 46 full rounds
|
||||
// Elves win with 859 total hit points left
|
||||
// Outcome: 46 * 859 = 39514
|
||||
let testData9 = """
|
||||
#######
|
||||
#E..EG#
|
||||
#.#G.E#
|
||||
#E.##E#
|
||||
#G..#.#
|
||||
#..E#.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 35 full rounds
|
||||
// Goblins win with 793 total hit points left
|
||||
// Outcome: 35 * 793 = 27755
|
||||
let testData10 = """
|
||||
#######
|
||||
#E.G#.#
|
||||
#.#G..#
|
||||
#G.#.G#
|
||||
#G..#.#
|
||||
#...E.#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 54 full rounds
|
||||
// Goblins win with 536 total hit points left
|
||||
// Outcome: 54 * 536 = 28944
|
||||
let testData11 = """
|
||||
#######
|
||||
#.E...#
|
||||
#.#..G#
|
||||
#.###.#
|
||||
#E#G#G#
|
||||
#...#G#
|
||||
#######
|
||||
"""
|
||||
|
||||
// Combat ends after 20 full rounds
|
||||
// Goblins win with 937 total hit points left
|
||||
// Outcome: 20 * 937 = 18740
|
||||
let testData12 = """
|
||||
#########
|
||||
#G......#
|
||||
#.E.#...#
|
||||
#..##..G#
|
||||
#...##..#
|
||||
#...#...#
|
||||
#.G...G.#
|
||||
#.....G.#
|
||||
#########
|
||||
"""
|
||||
|
||||
func testInitFile() {
|
||||
let bev = Beverage(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt")
|
||||
printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testInitString() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testEntities() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
var myentities = bev.entities
|
||||
func show(entities: [Entity]) {
|
||||
var id = 0
|
||||
for entity in entities {
|
||||
print("\(id) : \(entity)")
|
||||
id += 1
|
||||
}
|
||||
}
|
||||
// show(entities: myentities) // Demonstrated that sorting works when force-read in the entities in reversse order
|
||||
myentities.sort()
|
||||
// show(entities: myentities)
|
||||
}
|
||||
|
||||
func testFindNearestTarget() {
|
||||
var bev = Beverage(withString: testData1)
|
||||
var nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Elf)", withExpression: (nearest == GridPoint(X: 3, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[1])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 0)", withExpression: (nearest == GridPoint(X: 2, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[2])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 1)", withExpression: (nearest == GridPoint(X: 2, Y: 1)))
|
||||
nearest = bev.findNearestTarget(for: bev.entities[3])
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin 2)", withExpression: (nearest == GridPoint(X: -1, Y: -1)))
|
||||
|
||||
bev = Beverage(withString: testData5)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[3])
|
||||
XCTAssertEqual(test: "testFindNearestTarget is Goblin", withExpression: (bev.entities[3].kind == .Goblin))
|
||||
XCTAssertEqual(test: "testFindNearestTarget is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testFindNearestTarget (Goblin)", withExpression: (nearest == GridPoint(X: 3, Y: 3)))
|
||||
}
|
||||
|
||||
func testDistance() {
|
||||
let bev = Beverage(withString: testData1)
|
||||
var dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 2, Y: 2)).dist
|
||||
XCTAssertEqual(test: "testDistance (2, 2) = 2", withExpression: (dist == 2))
|
||||
dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 5, Y: 2)).dist
|
||||
XCTAssertEqual(test: "testDistance (5, 2) = -1", withExpression: (dist == -1))
|
||||
dist = bev.distance(from: bev.entities[0].loc, to: GridPoint(X: 2, Y: 1)).dist
|
||||
XCTAssertEqual(test: "testDistance (2, 1) = 0", withExpression: (dist == 1))
|
||||
dist = bev.distance(from: bev.entities[3].loc, to: GridPoint(X: 2, Y: 1)).dist
|
||||
XCTAssertEqual(test: "testDistance last Goblin to` Elf", withExpression: (dist == -1))
|
||||
}
|
||||
|
||||
func testMoveDirection() {
|
||||
var bev = Beverage(withString: testData1)
|
||||
var nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
var direction = bev.moveDirection(from: bev.entities[0], to: nearest)
|
||||
XCTAssertEqual(test: "testMoveDirection testData1", withExpression: (direction == GridDir.right))
|
||||
bev = Beverage(withString: testData2)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[0])
|
||||
direction = bev.moveDirection(from: bev.entities[0], to: nearest)
|
||||
XCTAssertEqual(test: "testMoveDirection testData2", withExpression: (direction == GridDir.right))
|
||||
|
||||
bev = Beverage(withString: testData5)
|
||||
nearest = bev.findNearestTarget(for: bev.entities[1])
|
||||
direction = bev.moveDirection(from: bev.entities[1], to: nearest)
|
||||
print("Nearest: \(nearest)")
|
||||
print("Direction: \(direction)")
|
||||
XCTAssertEqual(test: "testMoveDirection is Goblin", withExpression: (bev.entities[1].kind == .Goblin))
|
||||
XCTAssertEqual(test: "testMoveDirection is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testMoveDirection (nearest)", withExpression: (nearest == GridPoint(X: 5, Y: 5)))
|
||||
XCTAssertEqual(test: "testMoveDirection (dir)", withExpression: (direction == GridDir.down))
|
||||
}
|
||||
|
||||
func testAdjacent() {
|
||||
var bev = Beverage(withString: testData3)
|
||||
var adjacent = bev.adjacent(to: 3)
|
||||
XCTAssertEqual(test: "testAdjacent is Elf", withExpression: (bev.entities[3].kind == .Elf))
|
||||
XCTAssertEqual(test: "testAdjacent is adjacent", withExpression: (adjacent == 2))
|
||||
bev = Beverage(withString: testData4)
|
||||
adjacent = bev.adjacent(to: 4)
|
||||
XCTAssertEqual(test: "testAdjacent is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testAdjacent is not adjacent", withExpression: (adjacent == -1))
|
||||
}
|
||||
|
||||
func testTakeTurn() {
|
||||
var bev = Beverage(withString: testData3)
|
||||
XCTAssertEqual(test: "testTakeTurn is Elf", withExpression: (bev.entities[3].kind == .Elf))
|
||||
// printMaze(with: bev)
|
||||
_ = bev.takeTurn(with: 3)
|
||||
// printMaze(with: bev)
|
||||
bev = Beverage(withString: testData4)
|
||||
XCTAssertEqual(test: "testTakeTurn is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
// printMaze(with: bev)
|
||||
_ = bev.takeTurn(with: 4)
|
||||
// printMaze(with: bev)
|
||||
}
|
||||
|
||||
func testAttack() {
|
||||
let bev = Beverage(withString: testData6)
|
||||
// G.... 9 G.... 9
|
||||
// ..G.. 4 ..G.. 4
|
||||
// ..EG. 2 --> ..E..
|
||||
// ..G.. 2 ..G.. 2
|
||||
// ...G. 1 ...G. 1
|
||||
bev.entities[0].hitPts = 9
|
||||
bev.entities[1].hitPts = 4
|
||||
bev.entities[3].hitPts = 2
|
||||
bev.entities[4].hitPts = 2
|
||||
bev.entities[5].hitPts = 1
|
||||
printMaze(with: bev, withHP: true)
|
||||
let indexOfAdjeacentTarget = bev.adjacent(to: 2)
|
||||
if indexOfAdjeacentTarget != -1 {
|
||||
bev.attack(from: bev.entities[2], to: indexOfAdjeacentTarget)
|
||||
bev.updateEntityDict()
|
||||
bev.updateMaze()
|
||||
}
|
||||
printMaze(with: bev, withHP: true)
|
||||
}
|
||||
|
||||
func testRound() {
|
||||
let bev = Beverage(withString: testData4)
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
// printMaze(with: bev)
|
||||
_ = bev.round()
|
||||
printMaze(with: bev)
|
||||
let adjacent = bev.adjacent(to: 4)
|
||||
// print("adjacent=\(adjacent)")
|
||||
// print("entity = \(bev.entities[adjacent])")
|
||||
XCTAssertEqual(test: "testRound is Elf", withExpression: (bev.entities[4].kind == .Elf))
|
||||
XCTAssertEqual(test: "testRound attack entity 1", withExpression: (bev.entities[adjacent].loc == GridPoint(X: 4, Y: 2)))
|
||||
}
|
||||
|
||||
func testSampleGame() {
|
||||
var bev = Beverage(withString: testData7)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
var final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 7", withExpression: (final == 27730))
|
||||
|
||||
bev = Beverage(withString: testData8)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 8", withExpression: (final == 36334))
|
||||
|
||||
bev = Beverage(withString: testData9)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 9", withExpression: (final == 39514))
|
||||
|
||||
bev = Beverage(withString: testData10)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 10", withExpression: (final == 27755))
|
||||
|
||||
bev = Beverage(withString: testData11)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 11", withExpression: (final == 28944))
|
||||
|
||||
bev = Beverage(withString: testData12)
|
||||
// printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
final = bev.tabulateScore()
|
||||
// print("Final score = \(final)")
|
||||
XCTAssertEqual(test: "testSampleGame 12", withExpression: (final == 18740))
|
||||
|
||||
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// for _ in 2..<23 {
|
||||
// bev.round()
|
||||
// }
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// for _ in 28..<46 {
|
||||
// bev.round()
|
||||
// }
|
||||
// printMaze(with: bev, withHP: true)
|
||||
// bev.round()
|
||||
// printMaze(with: bev, withHP: true)
|
||||
}
|
||||
|
||||
func printMaze(with bev: Beverage, withHP: Bool = false) {
|
||||
let width = bev.nummaze[0].count
|
||||
let height = bev.nummaze.count
|
||||
func toEntityHP(i: Int, j: Int) -> Int {
|
||||
var retVal = 0
|
||||
if let index = bev.entityDict[GridPoint(X: i, Y: j)] {
|
||||
retVal = bev.entities[index].hitPts
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
print(" ROUND \(bev.rounds)")
|
||||
for j in 0..<height {
|
||||
for i in 0..<width {
|
||||
switch bev.nummaze[j][i] {
|
||||
case .Wall: print(" # ", terminator: "")
|
||||
case .Unknown: print(" ? ", terminator: "")
|
||||
case .Open: print(" . ", terminator: "")
|
||||
case .Goblin: withHP ? print("\u{001B}[0;31m\(String(format: "%03d", toEntityHP(i:i, j:j)))\u{001B}[0;37m", terminator: "") : print(" G ", terminator: "")
|
||||
case .Elf: withHP ? print("\u{001B}[0;32m\(String(format: "%03d", toEntityHP(i:i, j:j)))\u{001B}[0;37m", terminator: "") : print(" E ", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
}
|
||||
print("")
|
||||
}
|
||||
|
||||
|
||||
func day15Tests() {
|
||||
// testInitFile()
|
||||
// testInitString()
|
||||
// testEntities()
|
||||
// testDistance()
|
||||
// testMoveDirection()
|
||||
// testFindNearestTarget()
|
||||
// testAdjacent()
|
||||
// testTakeTurn()
|
||||
// testRound()
|
||||
// testAttack()
|
||||
// testSampleGame()
|
||||
}
|
||||
|
||||
func day15Final() {
|
||||
let retVal = "None"
|
||||
let bev = Beverage(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day15.txt")
|
||||
printMaze(with: bev, withHP: true)
|
||||
while !bev.round() {
|
||||
printMaze(with: bev, withHP: true)
|
||||
}
|
||||
// printMaze(with: bev, withHP: true)
|
||||
let final = bev.tabulateScore()
|
||||
|
||||
print("Answer to part 1 is: \(final)")
|
||||
print("Answer to part 2 is: \(retVal)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
//
|
||||
// Advent of Code 2018 "Day 16: Chronal Classification"
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
typealias Opfn = () -> Void
|
||||
|
||||
// Create an array of functions for the op codes such that we can make a dictionary to map them
|
||||
// 16 op-codes
|
||||
// 4 regisers
|
||||
class Z8 {
|
||||
var reg: [Int]
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
lazy var fn = [addr, addi, mulr, muli, banr, bani, borr, bori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr]
|
||||
|
||||
init(reg: [Int], op: Int, A: Int, B: Int, C: Int) {
|
||||
self.reg = reg
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
|
||||
// addr (add register) stores into register C the result of adding register A and register B. C = 7
|
||||
func addr() { reg[C] = reg[A] + reg[B] }
|
||||
// addi (add immediate) stores into register C the result of adding register A and value B.reg[C] = 5
|
||||
func addi() { reg[C] = reg[A] + B }
|
||||
// mulr (multiply register) stores into register C the result of multiplying register A and register B. reg[C] = 12
|
||||
func mulr() { reg[C] = reg[A] * reg[B] }
|
||||
// muli (multiply immediate) stores into register C the result of multiplying register A and value B. reg[C] = 6
|
||||
func muli() { reg[C] = reg[A] * B }
|
||||
// banr (bitwise AND register) stores into register C the result of the bitwise AND of register A and register B. reg[C] = 0
|
||||
func banr() { reg[C] = reg[A] & reg[B] }
|
||||
// bani (bitwise AND immediate) stores into register C the result of the bitwise AND of register A and value B. reg[C] = 2
|
||||
func bani() { reg[C] = reg[A] & B }
|
||||
// borr (bitwise OR register) stores into register C the result of the bitwise OR of register A and register B. reg[C] = 7
|
||||
func borr() { reg[C] = reg[A] | reg[B] }
|
||||
// bori (bitwise OR immediate) stores into register C the result of the bitwise OR of register A and value B. reg[C] = 3
|
||||
func bori() { reg[C] = reg[A] | B }
|
||||
// setr (set register) copies the contents of register A into register C. (Input B is ignored.) reg[C] = 3
|
||||
func setr() { reg[C] = reg[A] }
|
||||
// seti (set immediate) stores value A into register C. (Input B is ignored.) reg[C] = 1
|
||||
func seti() { reg[C] = A}
|
||||
// gtir (greater-than immediate/register) sets register C to 1 if value A is greater than register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func gtir() { reg[C] = A > reg[B] ? 1 : 0 }
|
||||
// gtri (greater-than register/immediate) sets register C to 1 if register A is greater than value B. Otherwise, register C is set to 0. reg[C] = 1
|
||||
func gtri() { reg[C] = reg[A] > B ? 1 : 0 }
|
||||
// gtrr (greater-than register/register) sets register C to 1 if register A is greater than register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func gtrr() { reg[C] = reg[A] > reg[B] ? 1 : 0 }
|
||||
// eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func eqir() { reg[C] = A == reg[B] ? 1 : 0 }
|
||||
// eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0. reg[C] = 0
|
||||
func eqri() { reg[C] = reg[A] == B ? 1 : 0 }
|
||||
// eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.reg[C] =0
|
||||
func eqrr() { reg[C] = reg[A] == reg[B] ? 1 : 0 }
|
||||
}
|
||||
|
||||
struct TestCase {
|
||||
var before: [Int]
|
||||
var after: [Int]
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
|
||||
init(before: [Int], after: [Int], op: Int, A: Int, B: Int, C: Int) {
|
||||
self.before = before
|
||||
self.after = after
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
|
||||
func validate(withIndex fnIndex: Int) -> Bool {
|
||||
let z8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
z8.fn[fnIndex]()
|
||||
return z8.reg == after
|
||||
}
|
||||
|
||||
func validate(withMapping map: [Int:Int]) -> Bool {
|
||||
let z8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
z8.fn[map[op]!]()
|
||||
return z8.reg == after
|
||||
}
|
||||
|
||||
func countOpsValid() -> Int {
|
||||
let tempz8 = Z8(reg: before, op: op, A: A, B: B, C: C)
|
||||
var count = 0
|
||||
for opIndex in 0..<tempz8.fn.count {
|
||||
count += validate(withIndex: opIndex) ? 1 : 0
|
||||
}
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
struct Code {
|
||||
var op: Int
|
||||
var A: Int
|
||||
var B: Int
|
||||
var C: Int
|
||||
|
||||
init(op: Int, A: Int, B: Int, C: Int) {
|
||||
self.op = op
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
}
|
||||
}
|
||||
|
||||
class Classification {
|
||||
var tests: [TestCase] = []
|
||||
var program: [Code] = []
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt'
|
||||
init(withFile filename: String) {
|
||||
let testFile = Tools.readFile(fromPath: filename)
|
||||
var testStrings = testFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = testStrings.last, lastStr.count == 0 else { return }
|
||||
testStrings.removeLast() // empty string
|
||||
parse(data: testStrings)
|
||||
}
|
||||
|
||||
// Supply test data in the form of a String
|
||||
init(withString testFile: String) {
|
||||
let testStrings = testFile.components(separatedBy: "\n")
|
||||
parse(data: testStrings)
|
||||
}
|
||||
|
||||
func parse(data testStrings: [String]) {
|
||||
guard testStrings.count > 0 else { print("Error Parsing"); return }
|
||||
|
||||
func parseArray(with line: String) -> [Int] {
|
||||
var retVal: [Int] = []
|
||||
let split = line.components(separatedBy: "[")
|
||||
guard split.count == 2 else { print("Error Array 1"); return retVal }
|
||||
let split2 = split[1].components(separatedBy: "]")
|
||||
guard split2.count == 2 else { print("Error Array 2"); return retVal }
|
||||
let dataString = split2[0].replacingOccurrences(of: " ", with: "")
|
||||
let data = dataString.components(separatedBy: ",")
|
||||
retVal = data.map { Int($0)!}
|
||||
return retVal
|
||||
}
|
||||
|
||||
var testIntermediate = TestCase(before: [], after: [], op: 0, A: 0, B: 0, C: 0)
|
||||
for line in testStrings {
|
||||
if line.hasPrefix("Before") {
|
||||
testIntermediate.before = parseArray(with: line)
|
||||
} else if line.hasPrefix("After") {
|
||||
testIntermediate.after = parseArray(with: line)
|
||||
tests.append(testIntermediate)
|
||||
} else if line.count > 4 {
|
||||
let split = line.components(separatedBy: " ")
|
||||
guard split.count == 4 else { print("Error code \(line)"); return }
|
||||
testIntermediate.op = Int(split[0])!
|
||||
testIntermediate.A = Int(split[1])!
|
||||
testIntermediate.B = Int(split[2])!
|
||||
testIntermediate.C = Int(split[3])!
|
||||
} else {
|
||||
testIntermediate = TestCase(before: [], after: [], op: 0, A: 0, B: 0, C: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Supply filename for input ex: '/home/peterr/AOC2018/Sources/AOC2018/data/day16Prog.txt'
|
||||
func loadProgram(withFile filename: String) {
|
||||
let progFile = Tools.readFile(fromPath: filename)
|
||||
var progStrings = progFile.components(separatedBy: "\n")
|
||||
// This gurd statement is just an excuse to use guard
|
||||
// I'm assuming the last string is an empty string, if not DON'T remove the last string
|
||||
guard let lastStr = progStrings.last, lastStr.count == 0 else { return }
|
||||
progStrings.removeLast() // empty string
|
||||
|
||||
var progIntermediate = Code(op: 0, A: 0, B: 0, C: 0)
|
||||
for line in progStrings {
|
||||
if line.count > 4 {
|
||||
let split = line.components(separatedBy: " ")
|
||||
guard split.count == 4 else { print("Error code 2 \(line)"); return }
|
||||
progIntermediate.op = Int(split[0])!
|
||||
progIntermediate.A = Int(split[1])!
|
||||
progIntermediate.B = Int(split[2])!
|
||||
progIntermediate.C = Int(split[3])!
|
||||
program.append(progIntermediate)
|
||||
progIntermediate = Code(op: 0, A: 0, B: 0, C: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runTests() -> Int {
|
||||
var validCount: [Int : Int] = [:]
|
||||
for testNum in 0..<tests.count {
|
||||
validCount[testNum] = tests[testNum].countOpsValid()
|
||||
}
|
||||
return validCount.filter {$0.value >= 3 }.count
|
||||
}
|
||||
|
||||
func validateMap(with map: [Int:Int]) -> Bool {
|
||||
for test in tests {
|
||||
if !test.validate(withMapping: map) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// returns the content of register zero
|
||||
func runProgram(with map: [Int:Int]) -> Int {
|
||||
let z8 = Z8(reg: [0, 0, 0, 0], op: 0, A: 0, B: 0, C: 0)
|
||||
|
||||
for lineIndex in 0..<program.count {
|
||||
z8.A = program[lineIndex].A
|
||||
z8.B = program[lineIndex].B
|
||||
z8.C = program[lineIndex].C
|
||||
z8.fn[map[program[lineIndex].op]!]()
|
||||
}
|
||||
return z8.reg[0]
|
||||
}
|
||||
|
||||
// Return a map of [SysOp : myOp]
|
||||
func determineOps() -> [Int:Int] {
|
||||
var possibleOpCodes: [Int : [Int]] = [:]
|
||||
for myOpCode in 0..<16 {
|
||||
var sysOp: [Int: Bool] = [:]
|
||||
for test in tests {
|
||||
if test.validate(withIndex: myOpCode) {
|
||||
sysOp[test.op] = true
|
||||
}
|
||||
}
|
||||
possibleOpCodes[myOpCode] = Array(sysOp.keys)
|
||||
}
|
||||
// We have 16 sets off opcodes, now reduce them
|
||||
func doneTest() -> Bool {
|
||||
for possible in possibleOpCodes {
|
||||
if possible.value.count > 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
while !doneTest() {
|
||||
for index in 0..<possibleOpCodes.count {
|
||||
if possibleOpCodes[index]!.count == 1 {
|
||||
for inner in 0..<possibleOpCodes.count {
|
||||
if inner != index {
|
||||
var possibleArray = possibleOpCodes[inner]!
|
||||
possibleArray.removeAll(where: { $0 == possibleOpCodes[index]![0] })
|
||||
possibleOpCodes[inner] = possibleArray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var retVal: [Int:Int] = [:]
|
||||
for myOpCode in 0..<16 {
|
||||
let sysOp = possibleOpCodes[myOpCode]![0]
|
||||
retVal[sysOp] = myOpCode
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Day16: AOCDay {
|
||||
lazy var tests: (() -> ()) = day16Tests
|
||||
lazy var final: (() -> ()) = day16Final
|
||||
|
||||
let testData1 = """
|
||||
Before: [3, 2, 1, 1]
|
||||
9 2 1 2
|
||||
After: [3, 2, 2, 1]
|
||||
|
||||
"""
|
||||
|
||||
func testZ8Instructions() {
|
||||
let z8 = Z8(reg: [0, 0, 0, 0], op: 0, A: 0, B: 0, C: 0)
|
||||
func initZ8() { z8.A = 1; z8.B = 2; z8.reg = [1, 3, 4, 2] }
|
||||
initZ8(); z8.addr()
|
||||
XCTAssertEqual(test: "testZ8Instructions addr", withExpression: (z8.reg[z8.C] == 7))
|
||||
initZ8(); z8.addi()
|
||||
XCTAssertEqual(test: "testZ8Instructions addi", withExpression: (z8.reg[z8.C] == 5))
|
||||
initZ8(); z8.mulr()
|
||||
XCTAssertEqual(test: "testZ8Instructions mulr", withExpression: (z8.reg[z8.C] == 12))
|
||||
initZ8(); z8.muli()
|
||||
XCTAssertEqual(test: "testZ8Instructions muli", withExpression: (z8.reg[z8.C] == 6))
|
||||
initZ8(); z8.banr()
|
||||
XCTAssertEqual(test: "testZ8Instructions banr", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.bani()
|
||||
XCTAssertEqual(test: "testZ8Instructions bani", withExpression: (z8.reg[z8.C] == 2))
|
||||
initZ8(); z8.borr()
|
||||
XCTAssertEqual(test: "testZ8Instructions borr", withExpression: (z8.reg[z8.C] == 7))
|
||||
initZ8(); z8.bori()
|
||||
XCTAssertEqual(test: "testZ8Instructions bori", withExpression: (z8.reg[z8.C] == 3))
|
||||
initZ8(); z8.setr()
|
||||
XCTAssertEqual(test: "testZ8Instructions setr", withExpression: (z8.reg[z8.C] == 3))
|
||||
initZ8(); z8.seti()
|
||||
XCTAssertEqual(test: "testZ8Instructions seti", withExpression: (z8.reg[z8.C] == 1))
|
||||
initZ8(); z8.gtir()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtir", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.gtri()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtri", withExpression: (z8.reg[z8.C] == 1))
|
||||
initZ8(); z8.gtrr()
|
||||
XCTAssertEqual(test: "testZ8Instructions gtrr", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqir()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqir", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqri()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqri", withExpression: (z8.reg[z8.C] == 0))
|
||||
initZ8(); z8.eqrr()
|
||||
XCTAssertEqual(test: "testZ8Instructions eqrr", withExpression: (z8.reg[z8.C] == 0))
|
||||
}
|
||||
|
||||
func testInitFile() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
XCTAssertEqual(test: "testInitFile count", withExpression: (cla.tests.count > 0))
|
||||
XCTAssertEqual(test: "testInitFile before", withExpression: (cla.tests.last!.before == [3, 1, 2, 2]))
|
||||
XCTAssertEqual(test: "testInitFile after", withExpression: (cla.tests.last!.after == [3, 1, 2, 0]))
|
||||
XCTAssertEqual(test: "testInitFile op", withExpression: (cla.tests.last!.op == 11))
|
||||
XCTAssertEqual(test: "testInitFile A", withExpression: (cla.tests.last!.A == 1))
|
||||
XCTAssertEqual(test: "testInitFile B", withExpression: (cla.tests.last!.B == 2))
|
||||
XCTAssertEqual(test: "testInitFile C", withExpression: (cla.tests.last!.C == 3))
|
||||
}
|
||||
|
||||
func testInitString() {
|
||||
let cla = Classification(withString: testData1)
|
||||
XCTAssertEqual(test: "testInitString count", withExpression: (cla.tests.count > 0))
|
||||
XCTAssertEqual(test: "testInitString before", withExpression: (cla.tests[0].before == [3, 2, 1, 1]))
|
||||
XCTAssertEqual(test: "testInitString after", withExpression: (cla.tests[0].after == [3, 2, 2, 1]))
|
||||
XCTAssertEqual(test: "testInitString op", withExpression: (cla.tests[0].op == 9))
|
||||
XCTAssertEqual(test: "testInitString A", withExpression: (cla.tests[0].A == 2))
|
||||
XCTAssertEqual(test: "testInitString B", withExpression: (cla.tests[0].B == 1))
|
||||
XCTAssertEqual(test: "testInitString C", withExpression: (cla.tests[0].C == 2))
|
||||
}
|
||||
|
||||
func testCountValidOps3orMore() {
|
||||
let cla = Classification(withString: testData1)
|
||||
let testCount = cla.runTests()
|
||||
XCTAssertEqual(test: "testCountValidOps3orMore count", withExpression: (testCount == 1))
|
||||
}
|
||||
|
||||
func testValidateWithMapping() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
let mapping = cla.determineOps()
|
||||
let works = cla.validateMap(with: mapping)
|
||||
XCTAssertEqual(test: "testValidateWithMapping", withExpression: (works == true))
|
||||
}
|
||||
|
||||
func day16Tests() {
|
||||
testZ8Instructions()
|
||||
testInitFile()
|
||||
testInitString()
|
||||
testCountValidOps3orMore()
|
||||
testValidateWithMapping()
|
||||
}
|
||||
|
||||
func day16Final() {
|
||||
let cla = Classification(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16.txt")
|
||||
let testCount = cla.runTests()
|
||||
|
||||
print("Answer to part 1 is: \(testCount)")
|
||||
|
||||
let mapping = cla.determineOps()
|
||||
cla.loadProgram(withFile: "/home/peterr/AOC2018/Sources/AOC2018/data/day16Prog.txt")
|
||||
let reg0 = cla.runProgram(with: mapping)
|
||||
|
||||
print("Answer to part 2 is: \(reg0)")
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
import Foundation
|
||||
|
||||
let showTests = true
|
||||
let onlyOneDay = 13
|
||||
let onlyOneDay = 16
|
||||
var allTests: [(() -> ())] = []
|
||||
var allFinal: [(() -> ())] = []
|
||||
|
||||
@@ -25,6 +25,9 @@ allTests.append(Day10().tests)
|
||||
allTests.append(Day11().tests)
|
||||
allTests.append(Day12().tests)
|
||||
allTests.append(Day13().tests)
|
||||
allTests.append(Day14().tests)
|
||||
allTests.append(Day15().tests)
|
||||
allTests.append(Day16().tests)
|
||||
|
||||
// Compile list of Answers
|
||||
allFinal.append(Day01().final)
|
||||
@@ -40,6 +43,9 @@ allFinal.append(Day10().final)
|
||||
allFinal.append(Day11().final)
|
||||
allFinal.append(Day12().final)
|
||||
allFinal.append(Day13().final)
|
||||
allFinal.append(Day14().final)
|
||||
allFinal.append(Day15().final)
|
||||
allFinal.append(Day16().final)
|
||||
|
||||
if onlyOneDay > 0 {
|
||||
print("\nDay \(onlyOneDay)")
|
||||
|
||||
@@ -19,9 +19,23 @@ func == <T:Equatable> (tuple1:(T,T),tuple2:(T,T)) -> Bool
|
||||
return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
|
||||
}
|
||||
|
||||
struct GridPoint: Equatable, Comparable {
|
||||
struct GridDir {
|
||||
static let none = GridPoint(X: 0, Y: 0)
|
||||
static let up = GridPoint(X: 0, Y: -1)
|
||||
static let down = GridPoint(X: 0, Y: 1)
|
||||
static let left = GridPoint(X: -1, Y: 0)
|
||||
static let right = GridPoint(X: 1, Y: 0)
|
||||
}
|
||||
|
||||
struct GridPoint: Equatable, Comparable, Hashable {
|
||||
var X = 0
|
||||
var Y = 0
|
||||
var up: GridPoint { return GridPoint(X: self.X, Y: self.Y-1) }
|
||||
var down: GridPoint { return GridPoint(X: self.X, Y: self.Y+1) }
|
||||
var left: GridPoint { return GridPoint(X: self.X-1, Y: self.Y) }
|
||||
var right: GridPoint {return GridPoint(X: self.X+1, Y: self.Y) }
|
||||
|
||||
var hashValue: Int { return X.hashValue ^ Y.hashValue }
|
||||
|
||||
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return (lhs.X == rhs.X) && (lhs.Y == rhs.Y)
|
||||
@@ -30,6 +44,14 @@ struct GridPoint: Equatable, Comparable {
|
||||
static func < (lhs: GridPoint, rhs: GridPoint) -> Bool {
|
||||
return lhs.Y == rhs.Y ? lhs.X < rhs.X : lhs.Y < rhs.Y
|
||||
}
|
||||
|
||||
static func + (lhs: GridPoint, rhs: GridPoint) -> GridPoint {
|
||||
return GridPoint(X: lhs.X + rhs.X, Y: lhs.Y + rhs.Y)
|
||||
}
|
||||
|
||||
static func - (lhs: GridPoint, rhs: GridPoint) -> GridPoint {
|
||||
return GridPoint(X: lhs.X - rhs.X, Y: lhs.Y - rhs.Y)
|
||||
}
|
||||
}
|
||||
|
||||
struct Tools {
|
||||
|
||||
Reference in New Issue
Block a user