@ -44,67 +44,128 @@ fn StackList(comptime T: type, comptime capacity_type: type, comptime capacity:
} ;
}
const Direction = enum ( u2 ) {
Up ,
Down ,
Left ,
Right ,
fn RingQueue ( comptime T : type , comptime capacity_type : type , comptime capacity : capacity_type ) type {
return struct {
const Self = @This ( ) ;
mem : [ capacity ] T ,
first : capacity_type ,
next : capacity_type ,
fn add ( self : * Self , value : T ) void {
std . debug . assert ( self . next - self . first < capacity ) ;
self . mem [ self . next % capacity ] = value ;
self . next + = 1 ;
}
fn take ( self : * Self ) T {
const result = self . mem [ self . first % capacity ] ;
self . first + = 1 ;
return result ;
}
fn isEmpty ( self : * const Self ) bool {
return self . next = = self . first ;
}
fn init ( ) Self {
return Self {
. mem = undefined ,
. first = 0 ,
. next = 0 ,
} ;
}
} ;
}
const Direction = enum ( u8 ) {
Horizontal ,
Vertical ,
} ;
const ResultsByDirection = std . EnumArray ( Direction , u32 ) ;
const Results = [ 150 ] [ 150 ] ResultsByDirection ;
const NextCellCoordinates = StackList ( [ 2 ] usize , usize , 3 ) ;
const Task = packed struct ( u48 ) {
current_heat : u16 ,
x : u8 ,
y : u8 ,
entry_direction : Direction ,
_ : u8 = 0 ,
} ;
const NextTasks = StackList ( Task , usize , 6 ) ;
fn getNextTasks ( board : [ ] const [ ] const u8 , task : Task ) NextTasks {
var result = NextTasks . init ( ) ;
const previous_direction : Direction = switch ( task . entry_direction ) {
. Vertical = > . Horizontal ,
. Horizontal = > . Vertical ,
} ;
fn fillResults ( board : [ ] const [ ] const u8 , results : * Results , x : usize , y : usize , entry_direction : Direction , depth : usize ) void {
/ / std . debug . print ( " Solving for {d},{d}, {any}, depth: {d}, total: {d} \n " , . { x , y , entry_direction , depth , results . * [ x ] [ y ] . get ( entry_direction ) } ) ;
var previous_cells_list = StackList ( [ 2 ] usize , usize , 3 ) . init ( ) ;
switch ( entry_direction ) {
. Up = > {
for ( 1 . . 4 ) | delta | {
if ( x + delta < board . len ) {
previous_cells_list . add ( . { x + delta , y } ) ;
{
var previous_cells_list = StackList ( [ 2 ] u8 , usize , 3 ) . init ( ) ;
switch ( task . entry_direction ) {
. Vertical = > {
inline for ( 1 . . 4 ) | delta | {
i f ( task . x + delta < board . len ) {
previous_cells_list . add ( . { task . x + @as ( u8 , delta ) , task . y } ) ;
}
}
}
} ,
. Down = > {
for ( 1 . . 4 ) | delta | {
if ( x > = delta ) {
previous_cells_list . add ( . { x - delta , y } ) ;
} ,
. Horizontal = > {
inline for ( 1 . . 4 ) | delta | {
i f ( task . y + delta < board [ task . x ] . len ) {
previous_cells_list . add ( . { task . x , task . y + @as ( u8 , delta ) } ) ;
}
}
}
} ,
. Left = > {
for ( 1 . . 4 ) | delta | {
if ( y + delta < board [ x ] . len ) {
previous_cells_list . add ( . { x , y + delta } ) ;
} ,
}
var current_heat = task . current_heat ;
for ( previous_cells_list . getSlice ( ) ) | previous_cell | {
current_heat + = board [ previous_cell [ 0 ] ] [ previous_cell [ 1 ] ] ;
result . add ( . {
. current_heat = current_heat ,
. x = previous_cell [ 0 ] ,
. y = previous_cell [ 1 ] ,
. entry_direction = previous_direction ,
} ) ;
}
}
{
var previous_cells_list = StackList ( [ 2 ] u8 , usize , 3 ) . init ( ) ;
switch ( task . entry_direction ) {
. Vertical = > {
inline for ( 1 . . 4 ) | delta | {
if ( task . x > = delta ) {
previous_cells_list . add ( . { task . x - @as ( u8 , delta ) , task . y } ) ;
}
}
}
} ,
. Right = > {
for ( 1 . . 4 ) | delta | {
if ( y > = delta ) {
previous_cells_list . add ( . { x , y - delta } ) ;
} ,
. Horizontal = > {
inline for ( 1 . . 4 ) | delta | {
i f ( task . y > = delta ) {
previous_cells_list . add ( . { task . x , task . y - @as ( u8 , delta ) } ) ;
}
}
}
} ,
} ,
}
var current_heat = task . current_heat ;
for ( previous_cells_list . getSlice ( ) ) | previous_cell | {
current_heat + = board [ previous_cell [ 0 ] ] [ previous_cell [ 1 ] ] ;
result . add ( . {
. current_heat = current_heat ,
. x = previous_cell [ 0 ] ,
. y = previous_cell [ 1 ] ,
. entry_direction = previous_direction ,
} ) ;
}
}
const previous_directions : [ 2 ] Direction = switch ( entry_direction ) {
. Up , . Down = > . { . Left , . Right } ,
. Left , . Right = > . { . Up , . Down } ,
} ;
/ / std . debug . print ( " Next tasks for {any}: {any} \n " , . { task , result . getSlice ( ) } ) ;
var current_heat = results . * [ x ] [ y ] . get ( entry_direction ) ;
for ( previous_cells_list . getSlice ( ) ) | previous_cell | {
current_heat + = board [ previous_cell [ 0 ] ] [ previous_cell [ 1 ] ] ;
for ( previous_directions ) | direction | {
if ( results . * [ previous_cell [ 0 ] ] [ previous_cell [ 1 ] ] . get ( direction ) > current_heat ) {
results . * [ previous_cell [ 0 ] ] [ previous_cell [ 1 ] ] . set ( direction , current_heat ) ;
fillResults ( board , results , previous_cell [ 0 ] , previous_cell [ 1 ] , direction , depth + 1 ) ;
}
}
}
return result ;
}
fn solveLines ( lines : [ ] [ ] u8 ) usize {
@ -116,26 +177,47 @@ fn solveLines(lines: [][]u8) usize {
}
}
const x_max = lines . len - 1 ;
const y_max = lines [ x_max ] . len - 1 ;
const x_max = @as ( u8 , @intCast ( lines . len - 1 ) ) ;
const y_max = @as ( u8 , @intCast ( lines [ x_max ] . len - 1 ) ) ;
var results : Results = [ _ ] [ 150 ] ResultsByDirection { [ _ ] ResultsByDirection { ResultsByDirection . initFill ( total_max ) } * * 150 } * * 150 ;
results [ x_max ] [ y_max ] . set ( . Down , lines [ x_max ] [ y_max ] ) ;
results [ x_max ] [ y_max ] . set ( . Right , lines [ x_max ] [ y_max ] ) ;
var tasks = RingQueue ( Task , usize , 1_024_576 ) . init ( ) ;
tasks . add ( . {
. current_heat = lines [ x_max ] [ y_max ] ,
. x = x_max ,
. y = y_max ,
. entry_direction = . Horizontal ,
} ) ;
tasks . add ( . {
. current_heat = lines [ x_max ] [ y_max ] ,
. x = x_max ,
. y = y_max ,
. entry_direction = . Vertical ,
} ) ;
fillResults ( lines , & results , x_max , y_max , . Down , 0 ) ;
fillResults ( lines , & results , x_max , y_max , . Right , 0 ) ;
var i : usize = 0 ;
while ( ! tasks . isEmpty ( ) ) : ( i + = 1 ) {
/ / std . debug . print ( " Handling task {d} \n " , . { i } ) ;
var current_task = tasks . take ( ) ;
if ( results [ current_task . x ] [ current_task . y ] . get ( current_task . entry_direction ) > current_task . current_heat ) {
results [ current_task . x ] [ current_task . y ] . set ( current_task . entry_direction , current_task . current_heat ) ;
for ( getNextTasks ( lines , current_task ) . getSlice ( ) ) | next_task | {
tasks . add ( next_task ) ;
}
}
}
if ( false ) {
std . debug . print ( " Total tasks done: {d} \n " , . { i } ) ;
for ( 0 . . lines . len ) | x | {
for ( 0 . . lines [ x ] . len ) | y | {
std . debug . print ( " {d} " , . { @min ( @min ( results [ x ] [ y ] . get ( . Up ) , results [ x ] [ y ] . get ( . Down ) ) , @min ( results [ x ] [ y ] . get ( . Left ) , results [ x ] [ y ] . get ( . Right ) ) ) } ) ;
std . debug . print ( " {d}/{d} " , . { results [ x ] [ y ] . get ( . Horizontal ) , results [ x ] [ y ] . get ( . Vertical ) } ) ;
}
std . debug . print ( " \n " , . { } ) ;
}
}
return results [ 0 ] [ 0 ] . get ( . Down ) - lines [ 0 ] [ 0 ] ;
return results [ 0 ] [ 0 ] . get ( . Vertical ) - lines [ 0 ] [ 0 ] ;
}
pub fn solveAll ( reader : anytype ) ! usize {