Skip to content

Instantly share code, notes, and snippets.

@neuro-sys
Last active February 26, 2019 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neuro-sys/ac0d77844f374295bfb7d410a4542602 to your computer and use it in GitHub Desktop.
Save neuro-sys/ac0d77844f374295bfb7d410a4542602 to your computer and use it in GitHub Desktop.
; Description
; A number is input in computer then a new no should get
; printed by adding one to each of its digit. If you encounter a 9,
; insert a 10 (don't carry over, just shift things around).
;
; For example, 998 becomes 10109.
;
; Bonus
; This challenge is trivial to do if you map it to a string to
; iterate over the input, operate, and then cast it back. Instead, try
; doing it without casting it as a string at any point, keep it numeric
; (int, float if you need it) only.
bdos equ $5
c_read equ $1
c_write equ $2
c_writestr equ $9
org $100
ld c, c_writestr
ld de, message
call bdos
call readinput
call inputtonum
call convertnum
call printnum
rst 0 ; return to ccp
; reads from keyboard and stores in buffer with $ff end marker
; quits after cr
readinput: ld hl, buffer
push hl ; save buffer pointer
nextchar: ld c, c_read
call bdos
cp 13 ; is cr?
jp z, readend
sub '0' ; get digit value
pop hl ; restore buffer pointer
ld (hl), a
inc hl
push hl
jp nextchar
readend: pop hl
ld (hl), $ff ; end marker
ld e, 10
ld c, c_write
call bdos ; print newline
ret
; converts buffer area into an 16-bit unsigned integer
; and stores in inputnum
inputtonum: call getinputlen ; bc = num of digits
dec bc
ld hl, buffer ; buffer pointer
add hl, bc
ld de, 0 ; digit counter
inputtonuml1: push de ; save digit counter
push hl ; save buffer pointer
ld b, e ; b = digit counter
call npower10 ; hl = 10^b
ex de, hl ; de = 10^b
pop hl ; restore buffer pointer
ld a, (hl) ; a = current input digit
push hl
call mul16 ; hl = current digit * 10^b
ex de, hl
ld hl, inputnum
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
add hl, de
ex de, hl
ld hl, inputnum
ld (hl), e
inc hl
ld (hl), d ; inputnum = inputnum + hl
pop hl
pop de
ld bc, buffer
or a
sbc hl, bc
add hl, bc
jp z, inputnumend
dec hl ; next buffer
inc de ; next digit
jp inputtonuml1
inputnumend: ret
; bc holds input size
getinputlen: ld hl, buffer
ld bc, 0 ; counter
getinputlenl1: ld a, $ff
cp (hl)
ret z
inc hl
inc bc
jp getinputlenl1
; writes the number in inputnum to console
; uses buffer area
printnum: call getnumdigits
ld c, l
ld b, h
ld a, $ff
ld hl, buffer
add hl, bc
ld (hl), a ; end marker
dec hl ; prev char
ex de, hl ; de = buffer[buffer_len-1]
ld hl, inputnum ; hl = &inputnum[0]
printnuml2: push hl
push de
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
ex de, hl
ld bc, 10
call div16_2
push hl ; save remainder
ld hl, inputnum
ld (hl), e
inc hl
ld (hl), d ; save new inputnum
pop hl ; restore remainder
ld a, e
cp 0
jp z, printnuml1
ld a, l
pop de
pop hl
ld (de), a
dec de ; prev char
jp printnuml2
printnuml1: ld a, l ; last remainder
pop de
pop hl ; reset stack
ld (de), a
ld hl, buffer
printnuml4: ld a, (hl)
cp $ff
jp z, printnuml3
push hl
add '0'
ld e, a
ld c, c_write
call bdos
pop hl
inc hl
jp printnuml4
printnuml3: ret
; hl is the number of digits in inputnum
getnumdigits: ld hl, inputnum
ld e, (hl)
inc hl
ld d, (hl) ; de = inputnum
ld hl, 0 ; hl is counter
getnumdigitsl1: ld bc, 10
push hl
call div16_2
pop hl
inc hl
ld a, e
cp d
ret z
jp getnumdigitsl1
; expects inputnum to hold a 16-bit unsigned integer
; converts as per the spec
; stores the final 16-bit unsigned integer in output
; uses a buffer area
convertnum: ld hl, inputnum
ld a, (hl)
inc hl
ld h, (hl)
ld l, a ; hl = number
ex de, hl ; de = number
ld bc, buffer ; address of buffer
push bc ; save buffer pointer
condigits: ld bc, 10
call div16_2 ; number / 10
pop bc ; restore buffer pointer
ld a, l
ld (bc), a ; save remainder
inc bc ; next address of fifo buffer
push bc ; save buffer pointer
ld a, e
or d
jp nz, condigits ; if quotient is zero, loop
pop bc ; reset stack
ld a, $ff
ld (bc), a ; end of buffer marker
ld bc, buffer ; address of buffer fifo buffer
push bc ; save buffer pointer
exx
ld b, 0 ; digit counter
exx
ld hl, inputnum
xor a
ld (hl), a
inc hl
ld (hl), a ; reset inputnum
procdigits: pop bc ; restore digit pointer
ld a, (bc) ; get current digit
cp $ff ; is it the end?
jp z, procend ; stop processing
push bc ; save digit pointer
exx
ld a, b ; load acc with digit index
inc b ; increment digit index
exx
ld b, a ; b = digit_index
call npower10
ex de, hl ; de = 10^digit_index
pop bc ; restore digit pointer
ld a, (bc) ; get
inc bc ; next digit
push bc ; save digit pointer
inc a ; digit value + 1
cp 10 ; is new number 10?
jp nz, skipb10ovf ; skip base 10 overflow case
exx
inc b ; increment digit index one more
exx
skipb10ovf: ld c, a
ld b, 0 ; bc = digit value + 1
call mul16_2 ; (digit_value + 1) * 10^digit_index
ex de, hl ; de = new digit value
ld hl, inputnum
ld a, (hl)
inc hl
ld h, (hl)
ld l, a ; hl = inputnum
add hl, de ; hl = inputnum + digit value
ex de, hl
ld hl, inputnum
ld (hl), e
inc hl
ld (hl), d ; inputnum = hl
jp procdigits
procend ret
buffer: ds 64
inputnum: ds 2 ; 16-bit unsigned integer
message: db "enter a number: $"
; hl = 10^b
npower10: xor a
cp b
ld hl, 1
ret z ; if b is zero, ret 10^0 = 1
ld de, 10
ld a, 1
cp b
jp nz, npower10_l1
ex de, hl
ret ; if b is 1, ret 10^1 = 10
npower10_l1 dec b
npower10_l2 ld c, b ; save counter
ld a, 10
call mul16
ex de, hl
ld b, c ; restore counter
djnz npower10_l2
ex de, hl
ret
; a is multiplier
; de is multiplicand
; hl is result
mul16: ld b, 16
ld hl, 0
mul16_l1 sra a
jp nc, mul16_skip_add
add hl, de
mul16_skip_add sla e
rl d
djnz mul16_l1
ret
; de is dividend
; bc is divisor
; out de is quotient
; out hl is remainder
div16_2: ld hl, 0 ; set accumulator to zero
ex af, af'
ld a, 16
div16_2_l1 ex af, af'
ld a, h
or a
jp m, div16_2_l2 ; a < 0
sla e
rl d ; left shift dividend
rl l
rl h ; left shift accumulator
or a
sbc hl, bc ; a = a - m
jp div16_2_l3
div16_2_l2 sla e
rl d ; left shift dividend
rl l
rl h ; left shift accumulator
add hl, bc ; a = a + m
div16_2_l3 ld a, h
or a
jp m, div16_2_l4 ; a < 0
set 0, e ; q(0) = 1
jp div16_2_l5
div16_2_l4 res 0, e ; q(0) = 0
div16_2_l5 ex af, af'
dec a
jp nz, div16_2_l1
ld a, h
or a
jp p, div16_2_l6 ; a < 0
add hl, bc ; yes, a = a + m
div16_2_l6 ret
; de is multiplier
; bc is multiplicand
; hl is result
mul16_2: ld hl, 0 ; accumulator set to zero
ex af, af'
ld a, 16 ; set counter
mul16_2_l1 ex af, af'
sra d
rr e ; shift multiplier right one bit
jr nc, mul16_2_l2
add hl, bc ; add multiplicand to accumulator
mul16_2_l2 sla c ; shift multiplicand left one bit
rl b
ex af, af'
dec a ; counter = counter - 1
jr nz, mul16_2_l1
ret
@neuro-sys
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment