2020/c64/day02.asm

501 lines
8.3 KiB
NASM

// vim: filetype=kickass
* = * "Day 02 Input"
!input:
.import binary "../inputs/02"
.byte 0
!str_title:
.text "# Day 02"
.byte '\n', '\n'
.text "Part 1: "
.byte 0
* = * "Day 02 Code"
day02:
{
.const input_pointer = $40
.const range_low = $42
.const range_high = $43
.const letter = $44
.const is_valid = $45
.const valid_count = $46
{
move_16_imm($03, !str_title-)
jsr write_string
.break
move_16_imm(input_pointer, !input-)
ldy #0
sty valid_count + 0
sty valid_count + 1
part1_loop:
jsr parse_rule
beq part1_done
// Increment range_high so we can beq.
inc range_high
// Decrement range_low so it overflows on invalid passwords
dec range_low
password:
lda (input_pointer), y
y_buf_inc(input_pointer)
cmp #$0a
beq newline
cmp letter
bne password
dec range_low
dec range_high
bne password
// range_high went to 0, so it contains the letter too many times
// Skip to newline, then loop back around.
!:
lda (input_pointer), y
y_buf_inc(input_pointer)
cmp #$0a
bne !-
jmp part1_loop
newline:
// If range_low is positive, we didn't meet the minimum
lda range_low
bpl part1_loop
inc valid_count + 0
bne part1_loop
inc valid_count + 1
jmp part1_loop
part1_done:
.break
lda valid_count + 0; sta udivmod32_dividend + 0
lda valid_count + 1; sta udivmod32_dividend + 1
lda #0
sta udivmod32_dividend + 2
sta udivmod32_dividend + 3
jsr print_decimal_u32
}
{
move_16_imm($03, str_part2)
jsr write_string
.break
move_16_imm(input_pointer, !input-)
ldy #0
sty valid_count + 0
sty valid_count + 1
part2_loop:
jsr parse_rule
beq part2_done
lda #0
sta is_valid
password:
lda (input_pointer), y
tax
y_buf_inc(input_pointer)
cmp #$0a
beq newline
dec range_low
bne !+
cmp letter
bne !+
lda #1
eor is_valid
sta is_valid
!:
dec range_high
bne !+++
txa
cmp letter
bne !+
lda #1
eor is_valid
sta is_valid
!:
// If we checked both numbers, we can skip the rest of the password.
!:
lda (input_pointer), y
y_buf_inc(input_pointer)
cmp #$0a
bne !-
jmp newline
!:
jmp password
newline:
lda is_valid
beq part2_loop
inc valid_count + 0
bne part2_loop
inc valid_count + 1
jmp part2_loop
part2_done:
.break
lda valid_count + 0; sta udivmod32_dividend + 0
lda valid_count + 1; sta udivmod32_dividend + 1
lda #0
sta udivmod32_dividend + 2
sta udivmod32_dividend + 3
jsr print_decimal_u32
}
move_16_imm($03, str_done)
jsr write_string
ldy #0
!:
ldx #0
!: inx; bne !-
!: inx; bne !-
!: inx; bne !-
!: inx; bne !-
iny
bne !-----
lda #1
sta $d020
ldy #0
!:
ldx #0
!: inx; bne !-
!: inx; bne !-
iny
bne !---
sta $d021
ldy #0
!:
ldx #0
!: inx; bne !-
!: inx; bne !-
!: inx; bne !-
iny
bne !----
{
.const timer = $40
.const xvel = $41
lda #(sprite1 / 64)
sta $07f8
lda #(sprite2 / 64)
sta $07f9
lda #(sprite3 / 64)
sta $07fa
lda #(sprite4 / 64)
sta $07fb
lda #0
sta $d001 // TL y
sta $d003 // TR y
lda #0
sta $d005 // BL y
sta $d007 // BR y
lda #0
sta $d000 // TL x
sta $d004 // BL x
lda #48
sta $d002 // TR x
sta $d006 // BR x
lda #0
sta $d010
lda #$0f
sta $d015 // sprite enable
sta $d01c // enable multicolor
sta $d01d // double width
sta $d017 // double height
lda #$09
sta $d025
lda #$08
sta $d026
lda #$00
sta $d027
sta $d028
sta $d029
sta $d02a
lda #0
sta timer
lda #127
sta xvel
SetRasterInterrupt(raster_irq)
cli
jmp *
raster_irq:
pha
txa
pha
tya
pha
dec timer
beq !+
jmp done
!:
lda #200
sta timer
// 0-214: Move bottom sprites
inc $d005
inc $d007
bne !+
// If they wrap around, disable them
lda $d015
and #%0011
sta $d015
!:
// 42-256: Move top sprites
// if top_sprite.disabled || top_sprite.y >= 42
lda $d015
and #$08
beq !+
lda $d007
cmp #42
bcc !++
!:
inc $d001
inc $d003
bne !+
// If they wrap around, disable them
lda $d015
and #%1100
sta $d015
!:
lda xvel
beq !+
jmp no_flip
!:
// If velocity is negative, flip the sprites
ldy #63
flip_loop:
//
// Sprite 1
//
lda sprite1 - 3, y
sta zp_temp
ldx sprite1 - 1, y
lda flip_map, x
sta sprite1 - 3, y
ldx zp_temp
lda flip_map, x
sta sprite1 - 1, y
ldx sprite1 - 2, y
lda flip_map, x
sta sprite1 - 2, y
//
// Sprite 2
//
lda sprite2 - 3, y
sta zp_temp
ldx sprite2 - 1, y
lda flip_map, x
sta sprite2 - 3, y
ldx zp_temp
lda flip_map, x
sta sprite2 - 1, y
ldx sprite2 - 2, y
lda flip_map, x
sta sprite2 - 2, y
//
// Sprite 3
//
lda sprite3 - 3, y
sta zp_temp
ldx sprite3 - 1, y
lda flip_map, x
sta sprite3 - 3, y
ldx zp_temp
lda flip_map, x
sta sprite3 - 1, y
ldx sprite3 - 2, y
lda flip_map, x
sta sprite3 - 2, y
//
// Sprite 4
//
lda sprite4 - 3, y
sta zp_temp
ldx sprite4 - 1, y
lda flip_map, x
sta sprite4 - 3, y
ldx zp_temp
lda flip_map, x
sta sprite4 - 1, y
ldx sprite4 - 2, y
lda flip_map, x
sta sprite4 - 2, y
dey; dey; dey
beq !+
jmp flip_loop
!:
lda $d000; clc; adc #48; sta $d000; sta $d004
lda $d002; sec; sbc #48; sta $d002; sta $d006
no_flip:
lda xvel
cmp #$80; ror
cmp #$80; ror
cmp #$80; ror
cmp #$80; ror
cmp #$80; ror
tax
// Move left sprites
txa; clc; adc $d000; sta $d000; sta $d004
bne !+
// If they wrap around, disable them
lda $d015
and #%1010
sta $d015
!:
// Move right sprites
txa; clc; adc $d002; sta $d002; sta $d006
bne !+
// If they wrap around, disable them
lda $d015
and #%0101
sta $d015
!:
dec xvel
done:
pla
tay
pla
tax
pla
rti
}
mul10:
asl
sta zp_temp
asl
asl
adc zp_temp
rts
parse_rule:
low_number:
// 13-16 k: kkkkkgmkbvkkrskhd
// ^^^
lda (input_pointer), y
bne !+
// Check for null terminator
rts
!:
y_buf_inc(input_pointer)
sec; sbc #'0'
sta range_low
lda (input_pointer), y
y_buf_inc(input_pointer)
cmp #$2d
beq !+
tax
lda range_low
jsr mul10
sta range_low
txa
sec; sbc #'0'
clc; adc range_low
sta range_low
y_buf_inc(input_pointer)
!:
high_number:
// 13-16 k: kkkkkgmkbvkkrskhd
// ^^^
lda (input_pointer), y
y_buf_inc(input_pointer)
sec; sbc #'0'
sta range_high
lda (input_pointer), y
y_buf_inc(input_pointer)
cmp #$20
beq !+
tax
lda range_high
jsr mul10
sta range_high
txa
sec; sbc #'0'
clc; adc range_high
sta range_high
y_buf_inc(input_pointer)
!:
//
// 13-16 k: kkkkkgmkbvkkrskhd
// ^^^
//
lda (input_pointer), y
sta letter
// TODO adc #3 instead?
y_buf_inc(input_pointer)
y_buf_inc(input_pointer)
y_buf_inc(input_pointer)
lda #1
rts
}