1+ import { delay , Console } from "../../utility.mjs" ;
2+
3+ export default class {
4+ /**
5+ * @param {Console } solConsole Solution console.
6+ * @param {HTMLElement } visContainer Visualization container.
7+ */
8+ constructor ( solConsole , visContainer ) {
9+ this . isSolving = false ;
10+ this . isStopping = false ;
11+ this . solConsole = typeof solConsole !== "undefined" ? solConsole : new Console ( ) ;
12+ this . visContainer = visContainer ;
13+ }
14+
15+ /**
16+ * Parses the puzzle input.
17+ * @param {string } input Puzzle input.
18+ * @returns {number[] } Lengths.
19+ */
20+ parse ( input ) {
21+ let consoleLine = this . solConsole . addLine ( "Parsing..." ) ;
22+
23+ input = input . trim ( ) ;
24+ if ( ! / ^ [ \d , ] + $ / . test ( input ) )
25+ throw new Error ( "Invalid input data" ) ;
26+
27+ let lengths = input . split ( "," ) . map ( e => parseInt ( e ) ) ;
28+
29+ consoleLine . innerHTML += " done." ;
30+ return lengths ;
31+ }
32+
33+ /**
34+ * Finds the result of multiplying the first two numbers in the list after hash process (part 1) or the Knot Hash of the input (part 2).
35+ * @param {number } part Puzzle part.
36+ * @param {string } input Puzzle input.
37+ * @param {boolean } visualization Enable visualization.
38+ * @returns {number|string } Result of multiplying the first two numbers in the list after hash process (part 1) or the Knot Hash of the input (part 2).
39+ */
40+ async solve ( part , input , visualization ) {
41+ try {
42+ this . isSolving = true ;
43+
44+ let lengths = this . parse ( input ) ;
45+ let list = new Array ( lengths . length > 5 || part == 2 ? 256 : 5 ) . fill ( null ) . map ( ( e , i ) => i ) ;
46+ let numberOfRounds = part == 1 ? 1 : 64 ;
47+
48+ if ( part == 2 )
49+ lengths = [ ...lengths . join ( "," ) . split ( "" ) . map ( e => e . charCodeAt ( 0 ) ) , 17 , 31 , 73 , 47 , 23 ] ;
50+
51+ let visConsole = new Console ( ) ;
52+ let solConsoleLine ;
53+ if ( visualization ) {
54+ this . solConsole . addLine ( `Number of rounds: ${ numberOfRounds } .` ) ;
55+ solConsoleLine = this . solConsole . addLine ( ) ;
56+ this . visContainer . append ( visConsole . container ) ;
57+ list . forEach ( e => visConsole . addLine ( ) ) ;
58+ }
59+
60+ let currentPosition = 0 , skipSize = 0 ;
61+ for ( let round = 0 ; round < numberOfRounds ; round ++ ) {
62+ for ( let length of lengths ) {
63+ if ( this . isStopping )
64+ return ;
65+
66+ let newList = list . slice ( ) ;
67+ for ( let i = 0 ; i < length ; i ++ )
68+ newList [ ( currentPosition + i ) % list . length ] = list [ ( currentPosition + length - 1 - i ) % list . length ] ;
69+ list = newList ;
70+ currentPosition = ( currentPosition + length + ( skipSize ++ ) ) % list . length ;
71+
72+ if ( visualization ) {
73+ solConsoleLine . innerHTML = `Round: ${ round + 1 } .` ;
74+ list . forEach ( ( e , i ) => visConsole . lines [ i ] . innerHTML = e ) ;
75+ await delay ( 1 ) ;
76+ }
77+ }
78+ }
79+
80+ if ( part == 1 ) {
81+ if ( visualization ) {
82+ visConsole . lines [ 0 ] . classList . add ( "highlighted" ) ;
83+ visConsole . lines [ 1 ] . classList . add ( "highlighted" ) ;
84+ }
85+ return list [ 0 ] * list [ 1 ] ;
86+ }
87+
88+ let denseHash = "" ;
89+ for ( let i = 0 ; i < 16 ; i ++ )
90+ denseHash += list . slice ( i * 16 , ( i + 1 ) * 16 ) . reduce ( ( acc , e ) => acc ^ e , 0 ) . toString ( 16 ) . padStart ( 2 , "0" ) ;
91+
92+ return denseHash ;
93+ }
94+
95+ finally {
96+ this . isSolving = false ;
97+ }
98+ }
99+
100+ /**
101+ * Stops solving the puzzle.
102+ */
103+ async stopSolving ( ) {
104+ this . isStopping = true ;
105+ while ( this . isSolving )
106+ await ( delay ( 10 ) ) ;
107+ this . isStopping = false ;
108+ }
109+ }
0 commit comments