Возможно ли сократить код? А так же вывести периметр и площадь

Низкоуровневое программирование портов, микроконтроллеров и т.д.

Модератор: Andy

Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

14 дек 2015, 08:41

Всем доброго времени суток,

Задание такое (делается в emu8086): Пользователь вводит координаты левого верхнего (x1, y1) и правого нижнего (x2, y2) углов прямоугольника. Программа должна нарисовать прямоугольник на экране и вывести его периметр (P) и площадь (S).
Примечание: Для ввода/вывода использовать прерывания (INT). Не использовать никакие команды "emu, macro" и т.п.

Вот код:

Код: Выделить всё

include 'emu8086.inc'
org 100h 
 
jmp kod
 
dannie:
 
 
 
dlina dw 0
sirina dw 0
xkord dw 0
ykord dw 0
plosiad dw 0
perimetr dw 0
msg1 db 'Vvedite x koordinatu centra priamougolnika:', '$'
msg2 db 'Vvedite y koordinatu centra priamougolnika:', '$'
msg3 db 'Vvedite sirinu priamougolnika:', '$'
msg4 db 'Vvedite dlinu priamougolnika:', '$'
msg5 db 'Plosiad Vasego priamougolnika ravna: ', '$'
msg6 db 'Dlina Vashego priamougolnika ravna: ', '$'
msg7 db 'Certim? (Nazmite liubuiu klavishu)', '$'
 
 
p1 dw 0 ;x konec verhnei linii
p2 dw 0 ;y konec levoi linii
p3 dw 0 ;x konec niznei linii
p4 dw 0 ;y konec pravoi linii
 
 
kod:
;--vivodim znacenia
mov dx, offset msg1
mov ah, 9
int 21h
call scan_num
 
mov xkord, cx
 
call CLEAR_SCREEN
 
mov dx, offset msg2
mov ah, 9
int 21h
call scan_num
 
mov ykord, cx
 
call CLEAR_SCREEN
 
mov dx, offset msg3
mov ah, 9
int 21h
call scan_num
 
mov sirina, cx
 
 
call CLEAR_SCREEN
 
mov dx, offset msg4
mov ah, 9
int 21h
call scan_num
 
mov dlina, cx
 
 
;--
 
;--scitaem plosiad i perimetr
mov al, b.[dlina]
mov bl, b.[sirina]
mul bl
mov plosiad, ax
 
mov bx, 0
add bx, sirina
add bx, sirina
add bx, dlina
add bx, dlina
mov perimetr, bx
 
call CLEAR_SCREEN
 
mov dx, offset msg5
mov ah, 9
int 21h
 
mov dx, offset msg6
mov ah, 9
int 21h
 
mov dx, offset msg7
mov ah, 9
int 21h
 
mov ah, 0
int 16h
 
;--nahodim verhniy praviy ugol priamogugolnika 
mov ax, xkord
mov bl, 2
div bl
mov b.[xkord], al
 
mov ax, ykord
mov bl, 2
div bl
mov b.[ykord], al
;--
 
 
;--vistavliaem video rezim  320x200, 256 cvetov
mov al, 13h
mov ah, 0
int 10h
;--
 
mov cx, xkord
mov dx, ykord
 
mov bx,dlina
add bx,xkord
mov p1, bx
 
 
;--certim verhniuiu liniu
mov al, 50
verhniaiaLinia:
 
 
 
mov ah, 0ch
int 10h
 
inc cx
 
cmp cx,p1
 
JNAE verhniaiaLinia
;--
 
mov cx, xkord
mov dx, ykord
 
mov bx, ykord
add bx, sirina
mov p2, bx
 
;--certim levuiu liniu
 
levaiaLinia:
 
 
mov ah,0ch
int 10h
 
inc dx
 
cmp dx,p2
 
JNAE levaiaLinia
 
;--
mov bx, cx
add bx, dlina
mov p3, bx
 
;--certim nizniuiu liniu
 
nizniaiaLinia :
 
 
mov ah,0ch
int 10h
 
inc cx
 
cmp cx,p3
 
JNAE nizniaiaLinia 
 
;--
mov bx,ykord
mov p4, bx
;--certim pravuiu liniu
 
pravaiaLinia:
 
 
mov ah,0ch
int 10h
 
dec dx
 
cmp dx,p4
 
JNB pravaiaLinia 
 
ret
 
DEFINE_SCAN_NUM
DEFINE_CLEAR_SCREEN
end
1. По заданным координатам прямоугольник чертится, с этим проблем нет, но почему-то не выводятся площадь и периметр,хотя, вроде как, должны.
2. Можно ли сократить код? Ибо преподу может не понравится такой длинный код.

Заранее благодарю за оказанную помощь.
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

18 дек 2015, 11:00

;--scitaem plosiad i perimetr
mov al, b.[dlina]
mov bl, b.[sirina]
mul bl
mov plosiad, ax
// непонятный префикс b. - удален
mov ax, dlina
mul sirina
mov plosiad, ax
mov bx, 0
add bx, sirina
add bx, sirina
add bx, dlina
add bx, dlina
mov perimetr, bx
mov ax, sirina
add ax, dlina
shl ax, 1
mov perimetr, ax

Оптимизация по рисованию:
1) за один цикл можно чертить сразу две параллельные линии
2) Вместо проверки на достижение определенной координаты по Х,У - удобнее использовать цикл по ширине/высоте. Меньше переменных, меньше операций
It's a long way to the top if you wanna rock'n'roll
Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

22 дек 2015, 09:36

somewhere писал(а):
Оптимизация по рисованию:
1) за один цикл можно чертить сразу две параллельные линии
2) Вместо проверки на достижение определенной координаты по Х,У - удобнее использовать цикл по ширине/высоте. Меньше переменных, меньше операций

Огромное Вам спасибо за ответы и помощь :) Да, я это прекрасно понимаю, однако препод сказал,чтоб циклы не использовались...
Однако,мне самому интересно, как отрисовывать одновременно 2 параллельные линии припомощи цикла,а потому не могли бы Вы показать реализацию в моей проге?
Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

23 дек 2015, 08:44

А можно ли чем то заменить директиву "include emu8086.inc"? Просто препод хочет,чтоб не использовались директивы и всякие команды macro.
Чем тогда можно заменить "call scan_num" и "call CLEAR_SCREEN"? Чтоб убрать из программы emu8086.inc?
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

23 дек 2015, 08:56

Придется вынести из этого файла две этих процедуры и вставить в свой код.
It's a long way to the top if you wanna rock'n'roll
Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

23 дек 2015, 11:53

Я понял, вот две эти процедуры, только вот я не понимаю, как мне их в код закинуть?

SCAN_NUM:

Код: Выделить всё

DEFINE_SCAN_NUM         MACRO
LOCAL make_minus, ten, next_digit, set_minus
LOCAL too_big, backspace_checked, too_big2
LOCAL stop_input, not_minus, skip_proc_scan_num
LOCAL remove_not_digit, ok_AE_0, ok_digit, not_cr

; protect from wrong definition location:
JMP     skip_proc_scan_num

SCAN_NUM        PROC    NEAR
        PUSH    DX
        PUSH    AX
        PUSH    SI
        
        MOV     CX, 0

        ; reset flag:
        MOV     CS:make_minus, 0

next_digit:

        ; get char from keyboard
        ; into AL:
        MOV     AH, 00h
        INT     16h
        ; and print it:
        MOV     AH, 0Eh
        INT     10h

        ; check for MINUS:
        CMP     AL, '-'
        JE      set_minus

        ; check for ENTER key:
        CMP     AL, 13  ; carriage return?
        JNE     not_cr
        JMP     stop_input
not_cr:


        CMP     AL, 8                   ; 'BACKSPACE' pressed?
        JNE     backspace_checked
        MOV     DX, 0                   ; remove last digit by
        MOV     AX, CX                  ; division:
        DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
        MOV     CX, AX
        PUTC    ' '                     ; clear position.
        PUTC    8                       ; backspace again.
        JMP     next_digit
backspace_checked:


        ; allow only digits:
        CMP     AL, '0'
        JAE     ok_AE_0
        JMP     remove_not_digit
ok_AE_0:        
        CMP     AL, '9'
        JBE     ok_digit
remove_not_digit:       
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered not digit.
        PUTC    8       ; backspace again.        
        JMP     next_digit ; wait for next input.       
ok_digit:


        ; multiply CX by 10 (first time the result is zero)
        PUSH    AX
        MOV     AX, CX
        MUL     CS:ten                  ; DX:AX = AX*10
        MOV     CX, AX
        POP     AX

        ; check if the number is too big
        ; (result should be 16 bits)
        CMP     DX, 0
        JNE     too_big

        ; convert from ASCII code:
        SUB     AL, 30h

        ; add AL to CX:
        MOV     AH, 0
        MOV     DX, CX      ; backup, in case the result will be too big.
        ADD     CX, AX
        JC      too_big2    ; jump if the number is too big.

        JMP     next_digit

set_minus:
        MOV     CS:make_minus, 1
        JMP     next_digit

too_big2:
        MOV     CX, DX      ; restore the backuped value before add.
        MOV     DX, 0       ; DX was zero before backup!
too_big:
        MOV     AX, CX
        DIV     CS:ten  ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
        MOV     CX, AX
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered digit.
        PUTC    8       ; backspace again.        
        JMP     next_digit ; wait for Enter/Backspace.
        
        
stop_input:
        ; check flag:
        CMP     CS:make_minus, 0
        JE      not_minus
        NEG     CX
not_minus:

        POP     SI
        POP     AX
        POP     DX
        RET
make_minus      DB      ?       ; used as a flag.
ten             DW      10      ; used as multiplier.
SCAN_NUM        ENDP

skip_proc_scan_num:

DEFINE_SCAN_NUM         ENDM
С CLEAR SCREEN разобрался :)
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

23 дек 2015, 20:16

в любое место до метки kod, само тело процедуры от proc near до endp
It's a long way to the top if you wanna rock'n'roll
Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

24 дек 2015, 15:39

Я понял, но поскольку теперь изменил чуть программу,то соответственно не проходит вставка :)

Вот так выглядит программа:

Код: Выделить всё

include 'emu8086.inc' ; подключение директивы
org 100h 
; приветствие
mov dx, offset msg1
mov ah, 9
int 21h   
call scan_num           
; очистка экрана
call CLEAR_SCREEN
 
; вывод значений
mov dx, offset msg2
mov ah, 9
int 21h
call scan_num
 
mov xkord, cx
 
;очистка экрана
call CLEAR_SCREEN
 
mov dx, offset msg3
mov ah, 9
int 21h
call scan_num
 
mov ykord, cx
 
;очистка экрана
call CLEAR_SCREEN
 
mov dx, offset msg4
mov ah, 9
int 21h
call scan_num
 
mov shirina, cx

; очистка экрана
call CLEAR_SCREEN
 
mov dx, offset msg5
mov ah, 9
int 21h
call scan_num
 
mov dlina, cx
 
; вычисляем площадь и периметр прямоугольника          
; площадь прямоугольника
mov ax, dlina
mul shirina
mov plosiad, ax
 
; периметр прямоугольника
mov bx, shirina
add bx, dlina
add bx, bx
mov perimetr, bx
 
; очистка экрана
call CLEAR_SCREEN
 
mov dx, offset msg6
mov ah, 9
int 21h
 
mov dx, offset msg7
mov ah, 9
int 21h
 
mov dx, offset msg8
mov ah, 9
int 21h
 
mov ah, 0
int 16h
 
; находим правый верхний угол прямоугольника 
mov ax, xkord
mov bl, 2
div bl
mov b.[xkord], al
 
mov ax, ykord
mov bl, 2
div bl
mov b.[ykord], al
 
; выставляем видео режим 640x480, 16 цветов
mov al, 12h    
mov ah, 0
int 10h
 
mov cx, xkord
mov dx, ykord
 
mov bx,dlina
add bx,xkord
mov p1, bx
 
; чертим верхнюю линию
mov al, 50  
 
VerhLinia:
 
mov ah, 0ch
int 10h
 
inc cx
 
cmp cx,p1
 
JNAE VerhLiniia
 
mov cx, xkord
mov dx, ykord
 
mov bx, ykord
add bx, shirina
mov p2, bx
 
; чертим левую линию
 
LevLinia:
 
 
mov ah,0ch 
; левая линия фиолетового цвета
mov al, 5
int 10h
 
inc dx
 
cmp dx,p2
 
JNAE LevLinia
 
mov bx, cx
add bx, dlina
mov p3, bx
 
; чертим нижнюю линию
 
NiznLinija:
 
 
mov ah,0ch  
; нижняя линия красного цвета
mov al, 4
int 10h
 
inc cx
 
cmp cx,p3
 
JNAE NiznLinia 
 
mov bx,ykord
mov p4, bx       
 
; чертим правую линию
 
PravLinija:
 
 
mov ah,0ch  
; правая линия голубого цвета
mov al, 3
int 10h
 
dec dx
 
cmp dx,p4
 
JNB PravLinia 
Oxidous
Сообщения: 15
Зарегистрирован: 24 сен 2015, 13:53

24 дек 2015, 16:44

Продолжение:

Код: Выделить всё

ret

CLEAR_SCREEN PROC NEAR
        PUSH    AX      ; store registers...
        PUSH    DS      ;
        PUSH    BX      ;
        PUSH    CX      ;
        PUSH    DI      ;

        MOV     AX, 40h
        MOV     DS, AX  ; for getting screen parameters.
        MOV     AH, 06h ; scroll up function id.
        MOV     AL, 0   ; scroll all lines!
        MOV     BH, 07  ; attribute for new lines.
        MOV     CH, 0   ; upper row.
        MOV     CL, 0   ; upper col.
        MOV     DI, 84h ; rows on screen -1,
        MOV     DH, [DI] ; lower row (byte).
        MOV     DI, 4Ah ; columns on screen,
        MOV     DL, [DI]
        DEC     DL      ; lower col.
        INT     10h

        ; set cursor position to top
        ; of the screen:
        MOV     BH, 0   ; current page.
        MOV     DL, 0   ; col.
        MOV     DH, 0   ; row.
        MOV     AH, 02
        INT     10h

        POP     DI      ; re-store registers...
        POP     CX      ;
        POP     BX      ;
        POP     DS      ;
        POP     AX      ;

        RET
CLEAR_SCREEN ENDP

dlina dw 0
shirina dw 0
xkord dw 0
ykord dw 0
plosiad dw 0
perimetr dw 0  
msg1 db 'Pogrammu napisal: Imia Familija. Nazmite <Enter> ', '$'
msg2 db 'Vvedite X koordinatu centra priamougolnika: ', '$'
msg3 db 'Vvedite Y koordinatu centra priamougolnika: ', '$'
msg4 db 'Vvedite shirinu priamougolnika (max 480): ', '$'
msg5 db 'Vvedite dlinu priamougolnika (max 640): ', '$'
msg6 db 'Plosiad Vashego priamougolnika: ', '$'
msg7 db 'Perimetr vashego priamougolnika: ', '$'
msg8 db 'Dlia sozdanija priamougolnika nazmite <ENTER>', '$'
 
 
p1 dw 0 ;конец верхней линии x
p2 dw 0 ;конец левой линии y
p3 dw 0 ;конец нижней линии x
p4 dw 0 ;конец правой линии y
 
DEFINE_SCAN_NUM
end
Я CLEAR_SCREEN вынес в конец кода, так теперь получается, что в коде call CLEAR_SCREEN ссылаются (обращаются) на процедуру, что я вынес в конец кода? Я правильно её вынес? Потому как, вроде работает.
А вот SCAN_NUM никак не могу вынести,ибо сразу же начинает программа ругаться:

illegal instruction: PUTC ' ' or wrong parameters
illegal instruction: PUTC 8 or wrong parameters
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

24 дек 2015, 21:03

потому что нет у процессора инструкции PUTC. Это макрос, его надо найти в том же файле.
It's a long way to the top if you wanna rock'n'roll
Ответить