lalahop

Assembleur 8086+ : exercice 6

Table des matières

Cet exercice sera le dernier de la saga assembleur 8086+. Nous allons donc finir par un jeu rudimentaire 😎 .

Comme d'habitude, je ne détaillerai rien concernant la compilation/l'édition des liens encore cette fois-ci. Reportez-vous au premier billet pour plus d'informations.

Exercice 6 : énoncé

Nous allons faire un mini jeu de motus en assembleur. Le but est de deviner le mot qui sera défini dans la zone data en un minimum d'essais. Si le mot n'est pas découvert en 7 essais, la partie est perdue. La première lettre du mot sera montrée au joueur dès le début d'une partie. Lors de chaque essai, il faudra afficher le numéro de l'essai, un rappel des lettres trouvés lors des essais précédents ainsi qu'une invitation à saisir une nouvelle proposition. Des messages "perdu"/"gagné" devront également être prévus.

Note : Comme d'habitude, cet énoncé n’est pas de moi : je l’ai repris à T.M. / E.R. et je l’ai modifié.

Exercice 6 : aides

Pas d'aide pour cet exercice car il n'y a aucune nouvelle notion ni aucune difficulté.

TITLE MOTUS
 
DOSSEG
.MODEL SMALL
.STACK 100H

 
 
.DATA
	mot db "bonjour$"	; le mot à trouver
	longueur db 7		; longueur du mot à trouver

	mot2 db "b------$"	; les lettres connues
 
	trouve db 1		; nb lettres trouvées
	essai db 1		; combien d'essai nécessaires ?

	saisie db 8,9 dup(?)	; stockera la saisie utilisateur
 
	; messages écran
	msgEssai db 13,10,"Essai $"
	demandeSaisie db ", saisissez un mot : ",13,10,10,"$"

	msgGagne db "Bravo, vous avez trouve le mot !",13,10,"$"
	msgPerdu db "Perdu, vous n'avez pas trouve en 7 essais !",13,10,"$"

	ligne db 13,10,"$"
 
.CODE
	mov ax, @DATA

	mov ds, ax
 
	mov cx, 7
	bcl:

		push cx
 
		;AFFICHAGE NUM ESSAI
		; "Essai numero"
		mov ah, 09h
		mov dx, offset msgEssai
		int 21h
 
		; affichage numero de l'essai
		mov ah, 02h
		mov dl, [essai]
		add dl, 30h
		int 21h

		; affichage "saisissez un mot"
		mov ah, 09h
		mov dx, offset demandeSaisie
		int 21h

		;SAISIE DE LA PROPOSITION
		; affiche lettres déjà connues
		mov ah, 09h
		mov dx, offset mot2
		int 21h

		; retour ligne
		mov ah, 09h
		mov dx, offset ligne
		int 21h

		; saisie
		mov ah, 0Ch
		mov al, 0ah
		mov dx, offset saisie
		int 21h
 
		; retour ligne
		mov ah, 09h
		mov dx, offset ligne
		int 21h
 
		;EVALUATION DE LA SAISIE
		mov [trouve], 0		; à chaque essai, on considére qu'aucune lettre n'a été trouvée
		mov bx, 0
		mov dl, longueur
 
		; On va comparer lettre par lettre la saisie au mot à trouver

		bcl2:
			cmp bx, dx
			ja finbcl2
 
			mov al, [mot+bx]


			cmp [saisie+bx+2], al		; Attention il y a une différence de 2 entre la saisie et le mot
			JNE remonte			; revoir le format d'une saisie : les 2 octets initiaux servent à
							; stocker taille maximale de la chaîne et taille réelle
			mov [mot2+bx], al		; Si l'on a la même lettre, on l'ajoute aux lettres connues

			inc [trouve]			; et on incrémente le compteur de lettres trouvées
 
			remonte:
				inc bx

				jmp bcl2
		finbcl2:
 
 
		;EVALUATION GAGNE/PERDU
		mov al, longueur			
		cmp trouve, al				; Si toutes les lettres ont été trouvé, c'est gagné

		je gagne
 
		inc essai				; Sinon on incrémente le nombre d'essais, 
		pop cx					; on restaure cx et on repart pour un essai
		loop bcl
 
		; Si l'on arrive là, alors la boucle s'est finie donc les essais sont écoulés

		; donc c'est perdu : affichage du message
		mov ah, 09h
		mov dx, offset msgPerdu
		int 21h

		jmp fin
 
		gagne:	
			; affiche message "gagné"
			mov ah, 09h
			mov dx, offset msgGagne
			int 21h

 
	fin:
		mov ax, 4c00h
		int 21h
END

Exercice 6 : sous Windows, avec Nasm et le linker Val

segment .data
	mot db "bonjour$"	; le mot à trouver
	longueur db 7		; longueur du mot à trouver

 
	mot2 db "b------$"	; les lettres connues
 
	trouve db 1		; nb lettres trouvées
	essai db 1		; combien d'essai necessaires ?

	saisie times 10 db 8
 
	; messages écran
	msgEssai db 13,10,"Essai $"

	demandeSaisie db ", saisissez un mot : ",13,10,10,"$"
	msgGagne db "Bravo, vous avez trouve le mot !",13,10,"$"

	msgPerdu db "Perdu, vous n'avez pas trouve en 7 essais !",13,10,"$"
	ligne db 13,10,"$"

 
 
segment stack stack
	resb 64
	stackstop:
 
 

segment .code
..start:
	mov ax, data
	mov ds, ax

 
	mov cx, 7
	bcl:
		push cx

 
		;AFFICHAGE NUM ESSAI
		; "Essai numero"
		mov ah, 09h
		mov dx, msgEssai
		int 21h

 
		; affichage numero de l'essai
		mov ah, 02h
		mov dl, [essai]

		add dl, 30h
		int 21h
 
		; affichage "saisissez un mot"
		mov ah, 09h

		mov dx, demandeSaisie
		int 21h
 
 
		;SAISIE DE LA PROPOSITION
		; affiche lettres déjà connues

		mov ah, 09h
		mov dx, mot2
		int 21h

 
		; retour ligne
		mov ah, 09h
		mov dx, ligne
		int 21h

 
		; saisie
		mov ah, 0Ch
		mov al, 0ah

		mov dx, saisie
		int 21h
 
		; retour ligne
		mov ah, 09h

		mov dx, ligne
		int 21h
 
 
		;EVALUATION DE LA SAISIE
		mov byte [trouve], 0		; à chaque essai, on considére qu'aucune lettre n'a été trouvée

		mov bx, 0
		mov dl, [longueur]

 
		; On va comparer lettre par lettre la saisie au mot à trouver
		bcl2:
			cmp bx, dx
			ja finbcl2
 
			mov al, [mot+bx]

 
			cmp [saisie+bx+2], al		; Attention il y a une différence de 2 entre la saisie et le mot
			JNE remonte			; revoir le format d'une saisie : les 2 octets initiaux servent à

							; stocker taille maximale de la chaîne et taille réelle
 
			mov [mot2+bx], al		; Si l'on a la même lettre, on l'ajoute aux lettres connues

			inc byte [trouve]		; et on incrémente le compteur de lettres trouvées
 
			remonte:
				inc bx

				jmp bcl2
		finbcl2:
 
 
		;EVALUATION GAGNE/PERDU
		mov al, [longueur]			
		cmp [trouve], al				; Si toutes les lettres ont été trouvé, c'est gagné

		je gagne
 
		inc byte [essai]				; Sinon on incrémente le nombre d'essais, 
		pop cx						; on restaure cx et on repart pour un essai

		loop bcl
 
		; Si l'on arrive là, alors la boucle s'est finie donc les essais sont écoulés
		; donc c'est perdu : affichage du message
		mov ah, 09h

		mov dx, msgPerdu
		int 21h
		jmp fin
 
		gagne:	
			; affiche message "gagné"

			mov ah, 09h
			mov dx, msgGagne
			int 21h

 
	fin:
		mov ax, 4c00h
		int 21h

Exercice 6 : sous GNU/Linux, avec Nasm et ld

section .data
	mot db "bonjour"	; le mot à trouver
	lenmot: equ $-mot	; longueur du mot à trouver

 
	mot2 db "b------"	; les lettres connues
	lenmot2: equ $-mot2
 
	trouve db 1		; nb lettres trouvées

	essai db 1		; combien d'essai necessaires ?	
 
	msgEssai db 13,10,"Essai "

	lenMsgEssai: equ $-msgEssai	
 
	demandeSaisie db ", saisissez un mot : ",13,10,10

	lenDemandeSaisie: equ $-demandeSaisie	
 
	msgGagne db "Bravo, vous avez trouvé le mot !",10
	lenMsgGagne: equ $-msgGagne	
 
	msgPerdu db "Perdu, vous n'avez pas trouvé le mot en 7 essais !",10

	lenMsgPerdu: equ $-msgPerdu
 
	ligne db 13,10
	lenligne: equ $-ligne
 
 

section .bss
	saisie resb 8		; Stocker la saisie. Prévoir une case de plus pour le retour-chariot
 
section .text

	global _start
 
_start:	
	bcl:					; loop ainsi que les sauts conditionnels ne sont pas utilisables
		cmp byte [essai], 7		; car l'adresse destination est trop éloignée. On procède donc

		jle suite			; à une indirection : un saut conditionnel pointe sur un 
						; saut inconditionnel (qui ne fait pas partie des sauts courts).
		jmp finbcl
 
	suite:	
		; AFFICHAGE NUM ESSAI

		; "Essai numero"
		mov eax, 4
		mov ebx, 1

		mov ecx, msgEssai
		mov edx, lenMsgEssai
		int 80h	

 
		; affichage numero de l'essai
		mov eax, 4
		mov ebx, 1

		mov ecx, essai
		add byte [ecx], 30h		; Rappel : 30h c'est la différence entre un chiffre

		mov edx, 1			; et son équivalent caractère imprimable dans la table ASCII
		int 80h	
		sub byte [ecx], 30h

 
		; affichage "saisissez un mot"
		mov eax, 4
		mov ebx, 1

		mov ecx, demandeSaisie
		mov edx, lenDemandeSaisie
		int 80h

 
		;SAISIE DE LA PROPOSITION
		; affiche lettres déjà connues
		mov eax, 4
		mov ebx, 1

		mov ecx, mot2
		mov edx, lenmot2
		int 80h

 
		; retour ligne
		mov eax, 4
		mov ebx, 1

		mov ecx, ligne
		mov edx, lenligne
		int 80h

 
		; saisie
		mov eax, 3
		mov ebx, 0

		mov ecx, saisie
		mov edx, lenmot
		inc edx

		int 80h
 
		; retour ligne
		mov eax, 4
		mov ebx, 1

		mov ecx, ligne
		mov edx, lenligne
		int 80h

 
 
		;EVALUATION DE LA SAISIE
		mov byte [trouve], 0			; à chaque essai, on considére qu'aucune lettre n'a été trouvée

		mov ebx, 0
		mov dl, lenmot
		sub dx, 1

 
		; On va comparer lettre par lettre la saisie au mot à trouver
		bcl2:
			cmp bx, dx
			ja finbcl2
 
			mov al, [mot+ebx]

 
			cmp [saisie+ebx], al
			JNE remonte
 
			mov [mot2+ebx], al		; Si l'on a la même lettre, on l'ajoute aux lettres connues

			inc byte [trouve]		; et on incrémente le compteur de lettres trouvées
 
			remonte:
				inc ebx

				jmp bcl2
		finbcl2:
 
 
		;EVALUATION GAGNE/PERDU
		mov al, lenmot
		cmp [trouve], al			; Si toutes les lettres ont été trouvé, c'est gagné

		je gagne
 
		inc byte [essai]			; Sinon on incrémente le nombre d'essais et on repart pour un essai
		jmp bcl
 
	finbcl:

		; Si l'on arrive là, alors la boucle s'est finie donc les essais sont écoulés
		; donc c'est perdu : affichage du message
		mov eax, 4
		mov ebx, 1

		mov ecx, msgPerdu
		mov edx, lenMsgPerdu
		int 80h

		jmp fin
 
		gagne:	
			; affiche message "gagné"
			mov eax, 4
			mov ebx, 1

			mov ecx, msgGagne
			mov edx, lenMsgGagne
			int 80h

 
	fin:
		mov eax, 1
		mov ebx, 0

		int 80h