500 lines
8.3 KiB
NASM
500 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
|
|
|
|
|
|
}
|