TITLE Kaprekar.asm: dal compito di Calcolatori dell'11 settembre 2026

comment *
	Programma che calcola la costante di Kaprekar

		data creazione: 13 settembre 2026
		ultima revisione: 21 settembre 2026
		
	N.B. La procedura "fourdigit_display_ax" serve solo per convertire
	     e stampare a video il contenuto di AX - non era richiesta dal
		 compito
*

;-----------------------------------------------------------------
; Definizione costanti

CR EQU 13                      ; carriage return
LF EQU 10                      ; line feed
DOLLAR EQU '$'

;-----------------------------------------------------------------
;    M  A  C  R  O
;-----------------------------------------------------------------

;------------------------------
display macro xxxx           ; N.B. ogni stringa deve terminare con '$' 
        push dx
	    push ax
	    mov dx,offset xxxx
	    mov ah,9
	    int 21h
	    pop ax
        pop dx
endm

;------------------------------
get_max_in_al macro ; Ingresso: vettore di 4 elementi puntato da BX
                    ; Uscita: in AL il max 
local ciclo,new_max,aggiorna

push bx ; N.B. non si fa push AX perche' AL e' passato in uscita
push cx
push dx
push si

    mov si,bx

    xor dx,dx ; indice iniziale = 0
    mov al,[si] ; primo elemento del vettore puntato da si
	mov bx,1
    mov cx,3 ; = 4-1
ciclo:
    mov ah,[si][bx]
	cmp ah,al
	jle aggiorna ; confronto signed (c'e' da considerare anche -1), a differenza di jbe
new_max:
    mov al,ah
	mov dx,bx
aggiorna:
    inc bx
	loop ciclo     

    mov bx,dx
    mov byte ptr [si][bx],-1 ; si elimina il max ponendolo a un valore fuori range
	                         ; N.B. il vettore di input viene modificato!!!

pop si
pop dx
pop cx
pop bx

endm

;*************
; Array2Word
;*************
Array2Word macro vettore,valore
local converti

push ax
push bx
push cx
push dx
push si
push di
push bp

mov bp,10 ; valore della base: resta costante
mov si,1 ; inizializzazione del peso: si useranno 1,10,100,1000
mov bx, offset vettore
add bx,3 ; il puntatore iniziale punta all'ultimo elemento dell'array
mov cx,4 ; numero di byte dell'array da convertire
xor dh,dh ; per usare dx come sorgente nella mul
xor di,di ; accumulatore del risultato
converti:
mov ax,si
mov dl,[bx]
mul dx    ; mul <sorgente>: dx|ax = <sorgente> * ax (DX sara' 0, perche' il numero e' minore di 9999)
add di,ax ; il valore e' accumulato in DI
dec bx ; punta al nuovo elemento dell'array
mov ax,si ; si rimette il peso appena usato in ax
mul bp ; moltiplica per 10 il peso precedente, che e' in ax, 
       ; e lo mette in dx|ax (ossia in ax, visto che il max peso vale 1000)
mov si,ax ; nuovo peso
loop converti

mov word ptr valore,di

pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax		  
endm

;*************
; Word2Array
;*************
Word2Array macro valore,vettore
local converti

push ax
push bx
push cx
push dx
push di

mov ax,valore
mov bx,10 ; base
mov cx,4
mov di,offset vettore
add di,3 ; punta alla fine del vettore
converti:
xor dx,dx
div bx    ; in DX il resto, in AX il quoziente di [DX:AX]/[BX]
mov [di],dl ; scrittura di una delle quattro cifre decimali
dec di ; punta al prossimo carattere
loop converti

pop di
pop dx
pop cx
pop bx
pop ax		  
endm



;-----------------------------------------------------------------
;
PILA SEGMENT STACK 'STACK'     ; definizione del segmento di stack
      DB      64 DUP('STACK')  ; lo stack e' riempito con la stringa 'stack'
                               ; per identificarlo meglio in fase di debug
PILA ENDS                      

;-----------------------------------------------------------------
;
DATI SEGMENT PUBLIC 'DATA'    ; definizione del segmento dati

CRLF         db CR,LF,DOLLAR ; per andare a capo nella stampa a video

N equ 4

;V db 6,1,7,4 ; punto fisso (Costante di Kaprekar): 1 iterazione
;V db 1,0,0,4 ; ci mette il massimo numero di iterazioni: 7
;V db 0,0,2,5 ; 7 iterazioni
;V db 0,1,6,9 ; 7 iterazioni
;V db 2,1,1,1 ; 5 iterazioni
;V db 0,1,4,4 ; 3 iterazioni
V db 4,7,8,7 ;

U db N dup (?) ; vettori
W db N dup (?)
NV dw ?        ; numeri
NU dw ?
NW dw ?
DELTA dw ?

; Per stampa a video con "fourdigit_display_ax"
fourdigit_stringa_ax db 5 dup(?) ; 4 caratteri + '$'

DATI ENDS  
 
;=================================================================

CSEG1 SEGMENT PUBLIC 'CODE'

;###################################################################################
;                                 MAIN program
;###################################################################################
MAIN proc far
        ASSUME CS:CSEG1,DS:DATI,SS:PILA,ES:NOTHING;

        MOV AX,SEG DATI
        MOV DS,AX

        ; stampa a video di esordio
		display CRLF
		
		; conversione del vettore in un numero e stampa di quest'ultimo
		Array2Word V,NV ; mov NV,0783	
        mov ax,NV		
		call near ptr fourdigit_display_ax
		display CRLF
		display CRLF
		
		; immissione nello stack dei tre puntatori a vettore
		mov ax,offset V
		push ax
		mov ax,offset W
		push ax	
		mov ax,offset U
		push ax

nuova_iterazione:		
        call near ptr Sort4_light	; creazione dei vettori U e W da V
                                    ; N.B. Il V originale viene distrutto!!!		

        ; conversione di U e W in interi a 16 bit
		Array2Word U,NU	
        mov ax,NU		
		call near ptr fourdigit_display_ax
		display CRLF
		Array2Word W,NW	
        mov ax,NW		
		call near ptr fourdigit_display_ax
		display CRLF
 	
	    ; differenza tra i due interi
        mov ax,NU
		mov bx,NW
		sub ax,bx
		mov DELTA,ax
		call near ptr fourdigit_display_ax
		display CRLF
		display CRLF	

        ; controllo della condizione di terminazione		
		cmp NV,ax ; N.B. qui ax == DELTA
		je termina
		
		; conversione di DELTA in vettore e scrittura in V e NV
		Word2Array DELTA,V
		mov ax,DELTA
        mov NV,ax		
		jmp nuova_iterazione
			
termina:
        ; stampa a video dell'ultimo valore di DELTA	
		call near ptr fourdigit_display_ax ; N.B. qui ax == DELTA

esci:
		display crlf
        MOV AH,4CH                 ; ritorno al DOS
        INT 21H

main endp

;===============================================================================
;                           procedura di ordinamento
;
; Per U: algoritmo di ordinamento (decrescente) attraverso il calcolo ripetuto 
; del max nel vettore residuo ("ordinamento per selezione" - selection sort)
;===============================================================================

Sort4_light proc near 

push ax
push bx
push cx
push dx
push si
push di
push bp

mov bp, sp
; Recupero due dei tre puntatori passati nello stack
mov bx, [bp+20] ; bx = Indirizzo base fisso di V
mov di, [bp+16] ; di = Indirizzo base fisso di U

; N.B. Il V originale viene distrutto, e diventa -1,-1,-1,-1
; La macro lavora su un vettore di dimensione 4 puntato da BX
get_max_in_al
mov [di],al
get_max_in_al
mov [di+1],al
get_max_in_al
mov [di+2],al
get_max_in_al
mov [di+3],al

; Riempimento del vettore W (ordinato in senso crescente)
ordinamento_inverso:

mov si, [bp+18] ; si = Indirizzo base fisso di W
add si,3 ; parto a scrivere dal fondo di W
		
mov cx,4
trasferisci_da_U_a_W:
mov al,[di]	
mov [si],al
inc di
dec si
loop trasferisci_da_U_a_W
		
pop bp	
pop di
pop si
pop dx
pop cx
pop bx
pop ax

ret

Sort4_light endp



;=====================================================================================================
; routine di conversione e stampa a video formattata di un intero positivo 
; di quattro cifre decimali posto nel registro AX
;
fourdigit_display_ax proc near 

        push ax ; N.B. serve perche' AX e' modificato dall'istruzione DIV
        push bx
		push cx
		push dx
		push di
                                 ; in ax c'e' il numero da convertire
        mov bx,offset fourdigit_stringa_ax ; offset stringa destinazione
        mov cx,10                ; base di numerazione

		mov di,4
newdigit:  
        xor dx,dx
        div cx                   ; in DX=[0|DL] il resto (tra 0 e 9), in AX il quoziente di [DX:AX]/[CX]
		or dl,30h                ; ASCIIficazione del resto
        mov [bx][di-1],dl        ; salvataggio della cifra decimale nella stringa destinazione
        dec di
        jnz newdigit                                  

        mov byte ptr [bx][4],'$'        ; '$' per poter stampare
        display fourdigit_stringa_ax

        pop di
		pop dx
        pop cx
        pop bx
		pop ax
        ret

fourdigit_display_ax endp


cseg1 ends

END MAIN                     ; il programma comincia all'indirizzo di MAIN

                  
