package Ġio . github . z eb alu . ad vent 2 0 2 0 Ċ Ċ class ĠTile ( lines : ĠList < String >) Ġ: ĠClone able Ġ{ ĊĊ ĉ private Ġval Ġid Ġ= Ġlines [ 0 ]. split (" Ġ" )[ 1 ]. let Ġ{ Ġit . substring ( 0 , Ġit . length Ġ- Ġ 1 ). to Long () Ġ} Ċ ĉ private Ġvar Ġarea Ġ= Ċĉ ĉ lines . drop ( 1 ). map Indexed Ġ{ Ġy , Ġline Ġ-> Ġline . map Indexed Ġ{ Ġx , Ġc Ġ-> ĠPair ( x , Ġy ) Ġto Ġc Ġ} Ġ}. flatten (). toMap () Ċ ĉ private Ġval Ġall Pos ible Edges Ġ= Ġcollect All Possible Edges () ĊĊ ĉ fun Ġmax X (): ĠInt Ġ= Ġarea . keys . map Ġ{ Ġit . first Ġ}. max OrNull () !! Ċ ĉ fun Ġmax Y (): ĠInt Ġ= Ġarea . keys . map Ġ{ Ġit . second Ġ}. max OrNull () !! ĊĊ ĉ fun Ġget Line ( lineNum : ĠInt ) Ġ= Ġ( 0 .. max X ()). map Ġ{ Ġx Ġ-> Ġarea . getValue ( Pair ( x , Ġline Num )) Ġ} Ċ ĉ fun Ġget Column ( col Num : ĠInt ) Ġ= Ġ( 0 .. max Y ()). map Ġ{ Ġy Ġ-> Ġarea . getValue ( Pair ( col Num , Ġy )) Ġ} Ċ ĉ fun Ġget Top Edge () Ġ= Ġget Line ( 0 ) Ċ ĉ fun Ġget Bottom Edge () Ġ= Ġget Line ( max Y ()) Ċ ĉ fun Ġget Left Edge () Ġ= Ġget Column ( 0 ) Ċ ĉ fun Ġget Right Edge () Ġ= Ġget Column ( max X ()) Ċ ĉ fun ĠgetId () Ġ= Ġid ĊĊ ĉ fun Ġrotate Left () Ġ{ Ċĉ ĉ val Ġmax X Ġ= Ġmax X () Ċĉ ĉ val Ġmax Y Ġ= Ġmax Y () Ċĉ ĉ area Ġ= Ġ( 0 .. max X ). map Ġ{ Ġx Ġ-> Ċĉĉ ĉ ( 0 .. max Y ). map Ġ{ Ġy Ġ-> Ċĉĉĉ ĉ Pair ( y , Ġmax X Ġ- Ġx ) Ġto Ġarea . getValue ( Pair ( x , Ġy )) Ċĉĉ ĉ } Ċĉ ĉ }. flatten (). toMap () Ċ ĉ } ĊĊ ĉ fun Ġrotate Right () Ġ{ Ċĉ ĉ val Ġmax X Ġ= Ġmax X () Ċĉ ĉ val Ġmax Y Ġ= Ġmax Y () Ċĉ ĉ area Ġ= Ġ( 0 .. max X ). map Ġ{ Ġx Ġ-> Ċĉĉ ĉ ( 0 .. max Y ). map Ġ{ Ġy Ġ-> Ċĉĉĉ ĉ Pair ( max Y Ġ- Ġy , Ġx ) Ġto Ġarea . getValue ( Pair ( x , Ġy )) Ċĉĉ ĉ } Ċĉ ĉ }. flatten (). toMap () Ċ ĉ } ĊĊ ĉ fun Ġrotate 1 8 0 () Ġ{ Ċĉ ĉ rotate Left () Ċĉ ĉ rotate Left () Ċ ĉ } ĊĊ ĉ fun Ġhorizontal Flip () Ġ{ Ċĉ ĉ val Ġmax X Ġ= Ġmax X () Ċĉ ĉ val Ġmax Y Ġ= Ġmax Y () Ċĉ ĉ area Ġ= Ġ( 0 .. max X ). map Ġ{ Ġx Ġ-> Ċĉĉ ĉ ( 0 .. max Y ). map Ġ{ Ġy Ġ-> Ċĉĉĉ ĉ Pair ( x , Ġmax Y Ġ- Ġy ) Ġto Ġarea . getValue ( Pair ( x , Ġy )) Ċĉĉ ĉ } Ċĉ ĉ }. flatten (). toMap () Ċ ĉ } ĊĊ ĉ fun Ġvertical Flip () Ġ{ Ċĉ ĉ val Ġmax X Ġ= Ġmax X () Ċĉ ĉ val Ġmax Y Ġ= Ġmax Y () Ċĉ ĉ area Ġ= Ġ( 0 .. max X ). map Ġ{ Ġx Ġ-> Ċĉĉ ĉ ( 0 .. max Y ). map Ġ{ Ġy Ġ-> Ċĉĉĉ ĉ Pair ( max X Ġ- Ġx , Ġy ) Ġto Ġarea . getValue ( Pair ( x , Ġy )) Ċĉĉ ĉ } Ċĉ ĉ }. flatten (). toMap () Ċ ĉ } ĊĊ ĉ private Ġfun Ġidentical () Ġ{ ĊĊ ĉ } ĊĊ ĉ fun Ġcan Be Connected ( other : ĠTile ) Ġ= Ġ! (( all Pos ible Edges . intersect ( other . all Pos ible Edges )). isEmpty ()) ĊĊ ĉ fun Ġfits On Top ( other : ĠTile ) Ġ= Ġget Bottom Edge (). equals ( other . get Top Edge ()) ĊĊ ĉ fun Ġfits On Bottom ( other : ĠTile ) Ġ= Ġother . fits On Top ( this ) ĊĊ ĉ fun Ġfits On Left ( other : ĠTile ) Ġ= Ġget Right Edge (). equals ( other . get Left Edge ()) ĊĊ ĉ fun Ġfits On Right ( other : ĠTile ) Ġ= Ġother . fits On Left ( this ) ĊĊ ĉ fun Ġcan Be Above ( other : ĠTile ) Ġ= Ġall Pos ible Edges . contains ( other . get Top Edge ()) ĊĊ ĉ fun Ġcan Be B ellow ( other : ĠTile ) Ġ= Ġother . can Be Above ( this ) ĊĊ ĉ fun Ġcan Be Left From ( other : ĠTile ) Ġ= Ġall Pos ible Edges . contains ( other . get Left Edge ()) ĊĊ ĉ fun Ġcan Be Right From ( other : ĠTile ) Ġ= Ġother . can Be Left From ( this ) ĊĊ ĉ fun ĠgetAll Possible Edges () Ġ= Ġall Pos ible Edges ĊĊ ĉ fun Ġcollect All Possible Edges () Ġ= Ċĉ ĉ listOf ( get Left Edge (), Ġget Right Edge (), Ġget Top Edge (), Ġget Bottom Edge ()). map Ġ{ ĠlistOf ( it , Ġit . reversed ()) Ġ}. flatten () Ċĉĉ ĉ . toSet () ĊĊ ĉ fun Ġall Pat ches ( width : ĠInt , Ġheight : ĠInt ) Ġ= Ċĉ ĉ ( 0 .. max X () Ġ- Ġwidth ). map Ġ{ Ġx Ġ-> Ċĉĉ ĉ ( 0 .. max Y () Ġ- Ġheight ). map Ġ{ Ġy Ġ-> Ċĉĉĉ ĉ ( 0 .. width ). map Ġ{ Ġdx Ġ-> Ċĉĉĉĉ ĉ ( 0 .. height ). map Ġ{ Ġdy Ġ-> Ċĉĉĉĉĉ ĉ Pair ( dx , Ġdy ) Ġto Ġarea [ Pair ( x Ġ+ Ġdx , Ġy Ġ+ Ġdy )] !! Ċĉĉĉĉ ĉ } Ċĉĉĉ ĉ }. flatten (). toMap () Ċĉĉ ĉ } Ċĉ ĉ }. flatten () ĊĊ ĉ fun Ġcount R ough () Ġ= Ġarea . keys . filter Ġ{ Ġarea [ it ] Ġ== Ġ'#' Ġ}. count () ĊĊ ĉ private Ġfun Ġmatch All W ays ( Ċĉ ĉ other : ĠTile , Ċĉ ĉ this Edge : ĠList < Char >, Ċĉ ĉ other Edge : Ġ( Tile ) Ġ-> ĠList < Char >, Ċĉ ĉ transform ations : ĠList <( Tile ) Ġ-> ĠUnit > Ċ ĉ ): ĠBoolean Ġ{ Ċĉ ĉ val Ġclone Ġ= Ġother . clone () Ċĉ ĉ transform ations . forEach Ġ{ Ġt Ġ-> Ċĉĉ ĉ t ( clone ) Ċĉĉ ĉ if Ġ( match By Rotate ( clone , Ġthis Edge , Ġother Edge )) Ġ{ Ċĉĉĉ ĉ return Ġtrue Ċĉĉ ĉ } Ċĉ ĉ } Ċĉ ĉ return Ġfalse Ċ ĉ } ĊĊ ĉ private Ġfun Ġmatch By Rotate ( other : ĠTile , Ġthis Edge : ĠList < Char >, Ġother Edge : Ġ( Tile ) Ġ-> ĠList < Char >): ĠBoolean Ġ{ Ċĉ ĉ repeat ( 4 ) Ġ{ Ċĉĉ ĉ if Ġ( this Edge . equals ( other Edge ( other ))) Ġ{ Ċĉĉĉ ĉ return Ġtrue Ċĉĉ ĉ } Ċĉĉ ĉ other . rotate Left () Ċĉ ĉ } Ċĉ ĉ return Ġfalse Ċ ĉ } ĊĊ ĉ fun Ġtransformations () Ġ= Ċĉ ĉ listOf ( Tile :: identical , ĠTile :: horizontal Flip , ĠTile :: vertical Flip , ĠTile :: horizontal Flip , ĠTile :: vertical Flip ) ĊĊ ĉ fun Ġtran 2 () Ġ= ĠlistOf ( Ċĉ ĉ Tile :: identical , ĠTile :: horizontal Flip , ĠTile :: vertical Flip , ĠTile :: rotate Left , ĠTile :: rotate Right , Ċĉ ĉ Tile :: rotate 1 8 0 , Ġ{ Ġt : ĠTile Ġ-> Ġt . rotate Left (); Ġt . vertical Flip () Ġ}, Ċĉ ĉ { Ġt : ĠTile Ġ-> Ġt . rotate Right (); Ġt . vertical Flip () Ġ}, Ċĉ ĉ { Ġt : ĠTile Ġ-> Ġt . rotate 1 8 0 (); Ġt . vertical Flip () Ġ}, Ċĉ ĉ { Ġt : ĠTile Ġ-> Ġt . rotate Left (); Ġt . horizontal Flip () Ġ}, Ċĉ ĉ { Ġt : ĠTile Ġ-> Ġt . rotate Right (); Ġt . horizontal Flip () Ġ}, Ċĉ ĉ { Ġt : ĠTile Ġ-> Ġt . rotate 1 8 0 (); Ġt . horizontal Flip () Ġ} Ċ ĉ ) ĊĊĊ ĉ override Ġfun ĠhashCode (): ĠInt Ġ= Ġid . toInt () Ġ* Ġ 1 1 9 Ċ ĉ override Ġfun Ġequals ( other : ĠAny ?): ĠBoolean Ġ= Ġif Ġ( other Ġis ĠTile ) Ġother . id Ġ== Ġid Ġelse Ġfalse Ċ ĉ override Ġfun ĠtoString (): ĠString Ġ{ Ċĉ ĉ var Ġresult Ġ= Ġ"" Ċĉ ĉ for Ġ( y Ġin Ġ 0 .. max Y ()) Ġ{ Ċĉĉ ĉ for Ġ( x Ġin Ġ 0 .. max X ()) Ġ{ Ċĉĉĉ ĉ result Ġ+= Ġarea . getValue ( Pair ( x , Ġy )) Ċĉĉ ĉ } Ċĉĉ ĉ result Ġ+= Ġ'\ n ' Ċĉ ĉ } Ċĉ ĉ return Ġresult . substring ( 0 , Ġresult . length Ġ- Ġ 1 ) Ċ ĉ } ĊĊ ĉ override Ġpublic Ġfun Ġclone (): ĠTile Ġ= Ġsuper . clone () Ġas ĠTile ĊĊ ĉ comp anion Ġobject Ġ{ Ċĉ ĉ fun ĠtoString Side By Side ( tiles : ĠList < Tile >, Ġseparator : ĠString Ġ= Ġ"\ t "): ĠString Ġ{ Ċĉĉ ĉ var Ġresult Ġ= Ġ"" Ċĉĉ ĉ for Ġ( y Ġin Ġ 0 .. tiles [ 0 ]. max Y ()) Ġ{ Ċĉĉĉ ĉ for Ġ( tile Ġin Ġtiles ) Ġ{ Ċĉĉĉĉ ĉ for Ġ( x Ġin Ġ 0 .. tiles [ 0 ]. max X ()) Ġ{ Ċĉĉĉĉĉ ĉ result Ġ+= Ġtile . area . getValue ( Pair ( x , Ġy )) Ċĉĉĉĉ ĉ } Ċĉĉĉĉ ĉ result Ġ+= Ġseparator Ċĉĉĉ ĉ } Ċĉĉĉ ĉ result Ġ+= Ġ'\ n ' Ċĉĉ ĉ } Ċĉĉ ĉ return Ġresult Ċĉ ĉ } ĊĊĉ ĉ fun ĠtoString Side By Side Without Edges ( tiles : ĠList < Tile >): ĠString Ġ{ Ċĉĉ ĉ var Ġresult Ġ= Ġ"" Ċĉĉ ĉ for Ġ( y Ġin Ġ 1 .. tiles [ 0 ]. max Y () Ġ- Ġ 1 ) Ġ{ Ċĉĉĉ ĉ for Ġ( tile Ġin Ġtiles ) Ġ{ Ċĉĉĉĉ ĉ for Ġ( x Ġin Ġ 1 .. tiles [ 0 ]. max X () Ġ- Ġ 1 ) Ġ{ Ċĉĉĉĉĉ ĉ result Ġ+= Ġtile . area . getValue ( Pair ( x , Ġy )) Ċĉĉĉĉ ĉ } Ċĉĉĉ ĉ } Ċĉĉĉ ĉ result Ġ+= Ġ'\ n ' Ċĉĉ ĉ } Ċĉĉ ĉ return Ġresult Ċĉ ĉ } ĊĊ ĉ } Ċ Ċ }