2020/c64/day09.asm

597 lines
13 KiB
NASM

// vim: filetype=kickass
* = * "Day 09 Input"
!input:
.import text "../inputs/09"
.byte 0
* = * "Day 09 Code"
day09:
{
.const buffer = $b000
.const buffer_end = $bfa0
.const input_pointer = $40 // $40..42
.const atoi_result = $42 // $42..46
.const buffer_pointer = $46 // $46..48
.const outer_pointer = $48 // $48..4a
.const middle_pointer = $4a // $4a..4c
.const inner_pointer = $4c // $4c..4e
.const part1 = $4e // $4e..52
.const lower_pointer = $52 // $52..54
.const upper_pointer = $54 // $54..56
.const sum = $56 // $56..5a
.const min_value = $5a // $5a..5e
.const max_value = $5e // $5e..62
// XXX I'm using 32 bit integers for this day, even though some
// inputs are 64 bit. Seems like I get away with it though.
move_16_imm($03, !str_title+)
jsr write_string
move_16_imm(input_pointer, !input-)
move_16_imm(buffer_pointer, buffer)
ldy #0
!line:
// 32-bit integer to store the result in.
lda #0
sta atoi_result + 0
sta atoi_result + 1
sta atoi_result + 2
sta atoi_result + 3
!digit:
// Check for the newline character at the end of the line.
lda (input_pointer), y
cmp #'\n'
beq !newline+
// Multiply the stored number by 10.
u32_mul10(atoi_result)
// Subtract '0' from the current digit to convert it to binary.
lda (input_pointer), y
sec
sbc #'0'
// Add the binary digit to the stored number
i32_add_a(atoi_result)
y_buf_inc(input_pointer)
jmp !digit-
!newline:
sty zp_temp
ldy #0
lda atoi_result + 0
sta (buffer_pointer), y
iny
lda atoi_result + 1
sta (buffer_pointer), y
iny
lda atoi_result + 2
sta (buffer_pointer), y
iny
lda atoi_result + 3
sta (buffer_pointer), y
lda buffer_pointer
clc
adc #4
sta buffer_pointer
bcc !cc+
inc buffer_pointer + 1
!cc:
ldy zp_temp
y_buf_inc(input_pointer)
// Check for the null terminator.
lda (input_pointer), y
beq !done+
jmp !line-
!done:
// outer for loop initial value
// outer_pointer = buffer + 25
lda #<(buffer + 25 * 4)
sta outer_pointer + 0
lda #>(buffer + 25 * 4)
sta outer_pointer + 1
!outer:
// middle for loop initial value
// middle_pointer = outer_pointer - 25
sec
lda outer_pointer + 0
sbc #(25 * 4)
sta middle_pointer + 0
lda outer_pointer + 1
sbc #0
sta middle_pointer + 1
// TODO if *middle_pointer > *outer_pointer: continue
!middle:
// inner_pointer = middle_pointer + 1
clc
lda middle_pointer + 0
adc #(1 * 4)
sta inner_pointer + 0
lda middle_pointer + 1
adc #0
sta inner_pointer + 1
!inner:
// if *inner_pointer + *middle_pointer == *outer_pointer:
// continue 'outer;
// *atoi_result = *inner_pointer + *middle_pointer
clc
ldy #0
lda (inner_pointer), y
adc (middle_pointer), y
sta (atoi_result), y
iny
lda (inner_pointer), y
adc (middle_pointer), y
sta (atoi_result), y
iny
lda (inner_pointer), y
adc (middle_pointer), y
sta (atoi_result), y
iny
lda (inner_pointer), y
adc (middle_pointer), y
sta (atoi_result), y
// if *atoi_result == *outer_pointer:
ldy #0
lda (atoi_result), y
cmp (outer_pointer), y
bne !not_equal+
iny
lda (atoi_result), y
cmp (outer_pointer), y
bne !not_equal+
iny
lda (atoi_result), y
cmp (outer_pointer), y
bne !not_equal+
iny
lda (atoi_result), y
cmp (outer_pointer), y
bne !not_equal+
// continue 'outer;
jmp !middle_done+
!not_equal:
// inner for loop increment
// *inner_pointer += 1 * 4
clc
lda inner_pointer + 0
adc #4
sta inner_pointer + 0
bcc !+
inc inner_pointer + 1
!:
// inner for loop conditional
// inner_pointer != outer_pointer
lda inner_pointer + 0
cmp outer_pointer + 0
bne !inner-
lda inner_pointer + 1
cmp outer_pointer + 1
bne !inner-
// for loop increment
// *middle_pointer += 1 * 4
clc
lda middle_pointer + 0
adc #4
sta middle_pointer + 0
bcc !+
inc middle_pointer + 1
!:
// for loop conditional
// middle_pointer != outer_pointer
lda middle_pointer + 0
cmp outer_pointer + 0
bne !middle_continue+
lda middle_pointer + 1
cmp outer_pointer + 1
bne !middle_continue+
jmp !outer_done+
!middle_continue:
jmp !middle-
!middle_done:
// outer for loop increment
// *outer_pointer += 1 * 4
clc
lda outer_pointer + 0
adc #4
sta outer_pointer + 0
bcc !+
inc outer_pointer + 1
!:
// outer for loop conditional
// *outer_pointer != $cfa0
lda outer_pointer + 0
cmp #$a0
bne !outer_continue+
lda outer_pointer + 1
cmp #$bf
bne !outer_continue+
jmp *
!outer_continue:
jmp !outer-
!outer_done:
// print (part1 = *outer_pointer)
ldy #0
lda (outer_pointer), y
sta part1 + 0
sta udivmod32_dividend + 0
iny
lda (outer_pointer), y
sta part1 + 1
sta udivmod32_dividend + 1
iny
lda (outer_pointer), y
sta part1 + 2
sta udivmod32_dividend + 2
iny
lda (outer_pointer), y
sta part1 + 3
sta udivmod32_dividend + 3
jsr print_decimal_u32
lda #0
sta lower_pointer + 0
sta upper_pointer + 0
sta sum + 0
sta sum + 1
sta sum + 2
sta sum + 3
lda #$b0
sta lower_pointer + 1
sta upper_pointer + 1
!outer:
!upper:
// while sum < part1
lda sum + 3
cmp part1 + 3
beq !+ // sum[3] == part1[3]
bcc !upper_success+ // sum[3] < part1[3] => sum < part
bcs !lower+ // sum[3] >= part1[3] => sum > part
!:
lda sum + 2
cmp part1 + 2
beq !+ // sum[2] == part1[2]
bcc !upper_success+ // sum[2] < part1[2] => sum < part
bcs !lower+ // sum[2] >= part1[2] => sum > part
!:
lda sum + 1
cmp part1 + 1
beq !+ // sum[1] == part1[1]
bcc !upper_success+ // sum[1] < part1[1] => sum < part
bcs !lower+ // sum[1] >= part1[1] => sum > part
!:
lda sum + 0
cmp part1 + 0
beq !outer_end+ // sum[0] == part1[0] => sum == part
bcs !lower+ // sum[0] >= part1[0] => sum > part
!upper_success:
// sum += *upper_pointer
ldy #0
clc
lda sum + 0
adc (upper_pointer), y // (upper_pointer) + 0
sta sum + 0
iny
lda sum + 1
adc (upper_pointer), y // (upper_pointer) + 1
sta sum + 1
iny
lda sum + 2
adc (upper_pointer), y // (upper_pointer) + 2
sta sum + 2
iny
lda sum + 3
adc (upper_pointer), y // (upper_pointer) + 3
sta sum + 3
// upper_pointer += 1 * 4;
clc
lda upper_pointer + 0
adc #4
sta upper_pointer + 0
bcc !+
inc upper_pointer + 1
!:
jmp !upper-
!outer_end:
// Hidden shortcut to outer_end because the jump was too long
jmp !outer_end+
!lower:
// while sum > part1
lda sum + 3
cmp part1 + 3
beq !+ // sum[3] == part1[3]
bcc !outer- // sum[3] < part[3] => sum < part
bcs !lower_success+ // sum[3] >= part[3] => sum > part
!:
lda sum + 2
cmp part1 + 2
beq !+ // sum[2] == part1[2]
bcc !outer- // sum[2] < part[2] => sum < part
bcs !lower_success+ // sum[2] >= part[2] => sum > part
!:
lda sum + 1
cmp part1 + 1
beq !+ // sum[1] == part1[1]
bcc !outer- // sum[1] < part[1] => sum < part
bcs !lower_success+ // sum[1] >= part[1] => sum > part
!:
lda sum + 0
cmp part1 + 0
beq !outer_end+ // sum[0] == part1[0]
bcs !outer- // sum[0] < part[0] => sum < part
!lower_success:
// sum -= *lower_pointer
ldy #0
sec
lda sum + 0
sbc (lower_pointer), y // (lower_pointer) + 0
sta sum + 0
iny
lda sum + 1
sbc (lower_pointer), y // (lower_pointer) + 1
sta sum + 1
iny
lda sum + 2
sbc (lower_pointer), y // (lower_pointer) + 2
sta sum + 2
iny
lda sum + 3
sbc (lower_pointer), y // (lower_pointer) + 3
sta sum + 3
// lower_pointer += 1 * 4;
clc
lda lower_pointer + 0
adc #4
sta lower_pointer + 0
bcc !+
inc lower_pointer + 1
!:
jmp !lower-
!lower_end:
!outer_end:
// Find the minimum and maximum values
lda #$ff
sta min_value + 0
sta min_value + 1
sta min_value + 2
sta min_value + 3
lda #$00
sta max_value + 0
sta max_value + 1
sta max_value + 2
sta max_value + 3
!loop:
ldy #3
lda (lower_pointer), y // lower[i] >> 24
cmp min_value + 3
beq !+
bcs !not_less+
bcc !less+
!:
dey
lda (lower_pointer), y // lower[i] >> 16
cmp min_value + 2
beq !+
bcs !not_less+
bcc !less+
!:
dey
lda (lower_pointer), y // lower[i] >> 8
cmp min_value + 1
beq !+
bcs !not_less+
bcc !less+
!:
dey
lda (lower_pointer), y // lower[i] >> 0
cmp min_value + 0
bcs !not_less+
!less:
ldy #0
lda (lower_pointer), y
sta min_value + 0
iny
lda (lower_pointer), y
sta min_value + 1
iny
lda (lower_pointer), y
sta min_value + 2
iny
lda (lower_pointer), y
sta min_value + 3
!not_less:
ldy #3
lda (lower_pointer), y // lower[i] >> 24
cmp max_value + 3
beq !+
bcc !not_more+
bcs !more+
!:
dey
lda (lower_pointer), y // lower[i] >> 16
cmp max_value + 2
beq !+
bcc !not_more+
bcs !more+
!:
dey
lda (lower_pointer), y // lower[i] >> 8
cmp max_value + 1
beq !+
bcc !not_more+
bcs !more+
!:
dey
lda (lower_pointer), y // lower[i] >> 0
cmp max_value + 0
bcc !not_more+
!more:
ldy #0
lda (lower_pointer), y
sta max_value + 0
iny
lda (lower_pointer), y
sta max_value + 1
iny
lda (lower_pointer), y
sta max_value + 2
iny
lda (lower_pointer), y
sta max_value + 3
!not_more:
clc
lda lower_pointer + 0
adc #4
sta lower_pointer + 0
bcc !+
inc lower_pointer + 1
!:
// for loop condition
// lower_pointer != upper_pointer
cmp upper_pointer + 0
bne !+
lda lower_pointer + 1
cmp upper_pointer + 1
beq !end+
!:
jmp !loop-
!end:
clc
lda min_value + 0
adc max_value + 0
sta udivmod32_dividend + 0
lda min_value + 1
adc max_value + 1
sta udivmod32_dividend + 1
lda min_value + 2
adc max_value + 2
sta udivmod32_dividend + 2
lda min_value + 3
adc max_value + 3
sta udivmod32_dividend + 3
move_16_imm($03, str_part2)
jsr write_string
jsr print_decimal_u32
move_16_imm($03, str_done)
jsr write_string
jmp *
rts
}
!str_title:
.text "# Day 09"
.byte '\n', '\n'
.text "Part 1: "
.byte 0