// 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 }