Add initial source files for Tic-Tac-Toe game implementation

Signed-off-by: Elmar Kresse <elmar.kresse@stud.htwk-leipzig.de>
This commit is contained in:
Elmar Kresse
2025-07-03 15:53:46 +02:00
commit 2a94dfb8d5
10 changed files with 1121 additions and 0 deletions

BIN
MAIN.EXE Normal file

Binary file not shown.

9
MAIN.MAP Normal file
View File

@ -0,0 +1,9 @@
Start Stop Length Name Class
00000H 0090EH 0090FH _TEXT CODE
00910H 009ECH 000DDH _DATA DATA
009F0H 00AEFH 00100H STACK STACK
Program entry point at 0000:08A6

BIN
MAIN.OBJ Normal file

Binary file not shown.

BIN
MAIN.TR Normal file

Binary file not shown.

49
data.asm Normal file
View File

@ -0,0 +1,49 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; data.asm
; file contains variables and constant
; for music, drawing, text and game
;
;****************************************
;Sounds
placeSound DD 4070, 100000 ; Note with pause
placeSoundLength = $ - placeSound
gameOverSound DD 4560, 100000, 4304, 50000, 7239, 100000, 9121, 200000
gameOverSoundLength = $ - gameOverSound
;coordinates and size
x_wert DW ? ;16 Bit variable
y_wert DW ? ;16 Bit variable
d_wert DW ? ;16 Bit variable
spieler DW ? ;current player (0,1)
field DW ? ;selected field (0-8)
balance dw 0 ;balance for check won (3 = 3 in a row)
;Player Arrays
player1 DW 0,0,0,0,0,0,0,0,0
player2 DW 0,0,0,0,0,0,0,0,0
;main menue strings
title_str DB "TIC-TAC-TOE$"
signature_str DB "[Elmar Kresse 19INB]$"
choose1_str DB "1 - Mensch gegen Mensch$"
choose2_str DB "2 - Verlassen$"
cross_win DB "Kreuz hat gewonnen$"
circle_win DB "Kreis hat gewonnen$"
draw DB "Unentschieden$"
;reset ISR var
oldIOFF DW ?
oldISeg DW ?
;timer vector vars
old_timer DW 0 ;original int 1c vector
old_segment DW 0 ;original int 1c segment
timer_ticks DW 0 ;timer_ticks

344
draw.asm Normal file
View File

@ -0,0 +1,344 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; draw.asm
; file contains source code for
; drawing and maths for circle
;
; - draw_pixel MACRO x, y, c
; - circle_draw macro x, y, radius
; Reference Digital differential analyzer (graphics algorithm)
; https://en.wikipedia.org/wiki/Digital_differential_analyzer_(graphics_algorithm)
;
; - cross_draw MACRO x, y, d
; - rectangle_draw MACRO x, y, d
; - line_print_down PROC
; - line_print_straight PROC
; - paint_menu PROC FAR
; - prepare_display PROC
;****************************************
draw_pixel MACRO x, y, c
push ax
push bx
push cx
push dx
MOV AH, 0Ch ;setzen der Konfig fürs schreiben
MOV AL, c ; Farbe
MOV BH, 00h ;Set Seitennummber
MOV CX, x
MOV DX, y
INT 10h
pop dx
pop cx
pop bx
pop ax
ENDM
circle_draw macro x, y, radius
push dx
push cx
push bx
push ax
;Werte zurücksetzen
mov balance, 0
mov ax, 0
mov bx, 0
;Verschiebung Mitte
add x, 60
add y, 60
mov bx, radius
mov balance, radius
neg balance
zeichne_kreis_schleife:
;0 to 45
mov cx, x
add cx, bx
mov dx, y
sub dx, ax
draw_pixel cx, dx, 0Fh
;90 to 45
mov cx, x
add cx, ax
mov dx, y
sub dx, bx
draw_pixel cx, dx, 0Ch
;90 to 135
mov cx, x
sub cx, ax
mov dx, y
sub dx, bx
draw_pixel cx, dx, 04h
;180 to 135
mov cx, x
sub cx, bx
mov dx, y
sub dx, ax
draw_pixel cx, dx, 06h
;180 to 225
mov cx, x
sub cx, bx
mov dx, y
add dx, ax
draw_pixel cx, dx, 12h
;270 to 225
mov cx, x
sub cx, ax
mov dx, y
add dx, bx
draw_pixel cx, dx, 0Bh
;270 to 315
mov cx, x
add cx, ax
mov dx, y
add dx, bx
draw_pixel cx, dx, 01h
;360 to 315
mov cx, x
add cx, bx
mov dx, y
add dx, ax
draw_pixel cx, dx, 0Dh
push dx
mov dx, balance
add dx, ax
add dx, ax
mov balance, dx
pop dx
cmp balance, 0
jl balance_negative
;balance_positive:
dec bx
push dx
mov dx, balance
sub dx, bx
sub dx, bx
mov balance, dx
pop dx
balance_negative:
inc ax
cmp ax, bx
jg end_drawing
jmp zeichne_kreis_schleife
end_drawing:
; pause the screen for dos compatibility:
pop ax
pop bx
pop cx
pop dx
endm
cross_draw MACRO x, y, d
push ax
push bx
push cx
push dx
;Erste FOR Schleife nach rechts unten
mov cx, x
mov dx, y
xor cx,cx ; cx-register is the counter, setn to 0
loop1:
push cx
mov cx, cx
mov dx, y
add dx, cx
add cx, x
draw_pixel cx, dx, 0Fh
pop cx
inc cx
cmp cx, d ; cx vergleich mit der Größe (Dimension d)
jle loop1 ; Loop while less or equal
xor cx,cx ; cx-register is the counter, setn to 0
loop2:
push cx
mov cx, cx
mov dx, y
sub dx, cx
add cx, x
add dx, d
draw_pixel cx, dx, 0Dh
pop cx
inc cx
cmp cx, d ; cx vergleich mit der Größe (Dimension d)
jle loop2 ; Loop while less or equal
pop ax
pop bx
pop cx
pop dx
ENDM
rectangle_draw MACRO x, y, d
;Verwaltet move und call
mov cx, x
mov dx, y
mov x_wert, cx
mov y_wert, dx
mov d_wert, d
call line_print_down
call line_print_straight
ENDM
line_print_down PROC
xor cx,cx ; cx-register is the counter, setn to 0
loop3:
push cx
mov cx, cx
mov dx, y_wert
add cx, x_wert
draw_pixel cx, dx, 0Fh
add dx, d_wert
draw_pixel cx, dx, 0Fh
pop cx
inc cx
cmp cx, d_wert ; cx vergleich mit der Größe (Dimension d)
jle loop3 ; Loop while less or equal
ret
line_print_down endp
line_print_straight PROC
xor dx,dx ; cx-register is the counter, setn to 0
loop4:
push dx
mov dx, dx
mov cx, x_wert
add dx, y_wert
draw_pixel cx, dx, 0Fh
add cx, d_wert
draw_pixel cx, dx, 0Fh
pop dx
inc dx
cmp dx, d_wert ; cx vergleich mit der Größe (Dimension d)
jle loop4 ; Loop while less or equal
ret
line_print_straight endp
paint_menu PROC FAR
push ax
push bx
push dx
;set pointer
mov ah,2
mov dh,5
mov dl,14
mov bh,0
int 10h
mov dx,offset title_str
mov ah,9
int 21h
;set pointer
mov ah,2
mov dh,6
mov dl,10
mov bh,0
int 10h
mov dx,offset signature_str
mov ah,9
int 21h
;set pointer
mov ah,2
mov dh,7
mov dl,11
mov bh,0
int 10h
cmp cx, 2
mov dx,offset cross_win
je zeige_gewinner
cmp cx, 3
mov dx,offset circle_win
je zeige_gewinner
cmp cx, 4
jne kein_gewinner
mov ah,2
mov dh,7
mov dl,13
mov bh,0
int 10h
mov dx,offset draw
je zeige_gewinner
zeige_gewinner:
mov ah,9
int 21h
kein_gewinner:
;set pointer
mov ah,2
mov dh,9
mov dl,10
mov bh,0
int 10h
mov dx,offset choose1_str
mov ah,9
int 21h
;set pointer
mov ah,2
mov dh,10
mov dl,10
mov bh,0
int 10h
mov dx,offset choose2_str
mov ah,9
int 21h
pop ax
pop bx
pop dx
ret
paint_menu endp
prepare_display PROC
;Videomode clear alles entfernen
;Spielfeld initialisieren
rectangle_draw 80, 10, 405 ; Kreuz MACRO
rectangle_draw 84, 14, 130 ; 1
rectangle_draw 218, 14, 130 ; 2
rectangle_draw 352, 14, 130 ; 3
rectangle_draw 84, 148, 130 ; 4
rectangle_draw 218, 148, 130 ; 5
rectangle_draw 352, 148, 130 ; 6
rectangle_draw 84, 282, 130 ; 7
rectangle_draw 218, 282, 130 ; 8
rectangle_draw 352, 282, 130 ; 9
ret
prepare_display ENDP
;---------------------------------------- DRAW ENDE ---------------------------------------

401
game.asm Normal file
View File

@ -0,0 +1,401 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; game.asm
; file contains source code for the
; basic functions of the game logic
;
; - conkf MACRO x_kord, y_kord
; - conkf_prog PROC FAR
; - game_logic PROC
; - check_won_value MACRO a, b, c
; - check_draw PROC
; - reset_player_data PROC
; - check_won PROC
; - reset_timerisr PROC
; - start_game PROC
;****************************************
conkf MACRO x_kord, y_kord ;MACRO for coordinates to field
push dx
push cx
mov cx, x_kord
mov dx, y_kord
mov field, 0h
call conkf_prog
pop cx
pop dx
ENDM
conkf_prog PROC FAR ;PROC for coordinates to field
push ax
push bx
push cx
push dx
;horizontal x
cmp cx, 482
jg out_of_range
cmp cx, 352
mov x_wert, 357
jnl x_3
cmp cx, 218
mov x_wert, 223
jnl x_2
cmp cx, 84
mov x_wert, 89
jnl x_1
jmp out_of_range
x_3:
mov ax, 2
jmp y_kordi
x_2:
mov ax, 1
jmp y_kordi
x_1:
mov ax, 0
y_kordi:
;vertical y
cmp dx, 412
jg out_of_range
cmp dx, 282
mov y_wert, 287
jnl y_3
cmp dx, 148
mov y_wert, 153
jnl y_2
cmp dx, 14
mov y_wert, 19
jnl y_1
jmp out_of_range
y_3:
mov bx, 6
jmp calc_field
y_2:
mov bx, 3
jmp calc_field
y_1:
mov bx, 0
calc_field:
add ax, bx ;(A = ax) * (B = bx) = (goal = AX)
mov field, ax
jmp kord_final
out_of_range:
mov field, 10 ;not in range(0-8) 10 is set for later checks
kord_final:
pop dx
pop cx
pop bx
pop ax
ret
conkf_prog ENDP
game_logic PROC
conkf x_wert, y_wert
;check valid field 0-8
cmp field, 0ah
je end_game_logic
;Feld frei
push ax
push si
mov si, field
shl si, 1
cmp player1[si], 1
pop si
pop ax
je end_game_logic
push ax
push si
mov si, field
shl si, 1
cmp player2[si], 1
pop si
pop ax
je end_game_logic
mov ax, spieler
cmp ax, 0
je kreuz_spieler
jne kreis_spieler
kreuz_spieler:
cross_draw x_wert, y_wert, 120
;Sound
PUSH AX BX CX DX
MOV BX, OFFSET placeSound
MOV CX, OFFSET placeSoundLength
CALL playbeep
POP DX CX BX AX
mov spieler, 1 ;Spieler umschalten
;Geklicketes Feld belegen
push ax
push si
mov si, field
shl si, 1
mov player1[si], 1
pop si
pop ax
push cx
mov cx, offset player1
call check_won
pop cx
cmp ax, 1
jne end_game_logic
mov cx, 2
call reset_timerisr
call start_programm
kreis_spieler:
;Kreis zeichnen
circle_draw x_wert, y_wert, 60
;Sound
PUSH AX BX CX DX
MOV BX, OFFSET placeSound
MOV CX, OFFSET placeSoundLength
CALL playbeep
POP DX CX BX AX
mov spieler, 0 ;Spieler umschalten
;Geklicketes Feld belegen
push ax
push si
mov si, field
shl si, 1
mov player2[si], 1
pop si
pop ax
push cx
mov cx, offset player2
call check_won
pop cx
cmp ax, 1
jne end_game_logic
mov cx, 3
call reset_timerisr
call start_programm
end_game_logic:
call check_draw
ret
game_logic ENDP
check_won_value MACRO a, b, c
push ax
push bx
mov bx, 0
mov ax, a;
shl ax, 1
add bp, ax
add bx, ds:[bp]
mov bp, cx
mov ax, b;
shl ax, 1
add bp, ax
add bx, ds:[bp]
mov bp, cx
mov ax, c;
shl ax, 1
add bp, ax
add bx, ds:[bp]
mov bp, cx
cmp bx, 3
pop bx
pop ax
je got_winner
ENDM
check_draw PROC
;Überprüfen ob Unentschieden
push bx ;Counter ob alle Felder belegt sind
push ax ;Zahlvariable für Shiften
push cx ;Pointer für das Array des jeweiligen Spielers
push dx ;Zählvariable für Schleifen
push bp
mov bx, 0
mov ax, 0
mov dx, 0
mov cx, offset player1 ;pointer for player1
player1_field_loop:
mov ax, dx
shl ax, 1
mov bp, cx
add bp, ax
add bx, ds:[bp]
inc dx
cmp dx, 9
jne player1_field_loop
mov cx, offset player2 ;pointer for player2
mov dx, 0
player2_field_loop:
mov ax, dx
shl ax, 1
mov bp, cx
add bp, ax
add bx, ds:[bp]
inc dx
cmp dx, 9
jne player2_field_loop
cmp bx, 9
pop bp
pop dx
pop cx
pop ax
pop bx
je draw_end
jmp check_draw_end
draw_end:
mov cx, 4 ; 4 = Unentschieden
call reset_timerisr
call start_programm
check_draw_end:
ret
check_draw ENDP
reset_player_data PROC
push ax
push si
push bx ;Schleifen Zähler
mov bx, 0
resetloop_player1:
mov si, bx
shl si, 1
mov player1[si], 0
inc bx
cmp bx, 9
jne resetloop_player1
mov bx, 0
resetloop_player2:
mov si, bx
shl si, 1
mov player2[si], 0
inc bx
cmp bx, 9
jne resetloop_player2
pop bx
pop si
pop ax
ret
reset_player_data ENDP
check_won PROC
push bp
mov bp, cx
;vertical
check_won_value 0, 3, 6
check_won_value 1, 4, 7
check_won_value 2, 5, 8
;horizontal
check_won_value 2, 1, 0
check_won_value 3, 4, 5
check_won_value 6, 7, 8
;cross
check_won_value 0, 4, 8
check_won_value 6, 4, 2
jmp ende_check_won
got_winner:
pop bp
;play gameover sound
MOV BX, OFFSET gameOverSound
MOV CX, gameOverSoundLength
CALL playbeep
mov ax, 1 ;var for save winner exists
ret
ende_check_won:
pop bp
mov ax, 0
ret
check_won ENDP
reset_timerisr PROC
PUSH CX
PUSH DS
PUSH AX
PUSH DX
MOV AX, 251Ch ; Restore old user timer interrupt vector
MOV DX, [CS:old_timer]
MOV CX, [CS:old_segment]
MOV DS, CX
INT 21h
POP DX
POP AX
POP DS
POP CX
ret
reset_timerisr ENDP
start_game PROC
CLI
mov ax,00h
int 33h
or ax,ax
call reset_player_data ;Spieler Array reset
mov ax,12h ;Videomodus
int 10h
call prepare_display
mov ax, 1 ;Curser an
int 33h
;Ersten Spieler setzten
call prepare_mouse
mov spieler, 0
call prepare_display
STI
ret
start_game endp

140
logic.asm Normal file
View File

@ -0,0 +1,140 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; logic.asm
; file contains source code for the
; logic (mouse, timer, programm)
;
; - handle_timer_tick PROC
; - prepare_timer_tick PROC
; - prepare_mouse PROC
; - mouseProc PROC FAR
; - start_programm PROC
;****************************************
handle_timer_tick PROC
; Call the original interrupt vector
; by pushing flags register and doing a FAR CALL to old vector
PUSHF
CALL DWORD ptr [CS:old_timer]
INC WORD ptr [CS:timer_ticks] ; Increase timer counter
IRET
handle_timer_tick ENDP
prepare_timer_tick PROC
PUSH DS
MOV AX, 351Ch ; Get user timer interrupt vector
INT 21h
; ES:BX now has the address of the interrupt vector
MOV [CS:old_timer], BX
MOV AX, ES
MOV [CS:old_segment], AX
MOV AX, 251ch ; Set user timer interrupt vector
PUSH CS
POP DS
MOV DX, OFFSET handle_timer_tick
INT 21h
POP ds
ret
prepare_timer_tick ENDP
prepare_mouse PROC
mov dx, OFFSET mouseProc ;jump to click_event_handler
mov ax, 0Ch
mov cx, 00000010b ; on left click
push cs ;es:dx
pop es
int 33h
mov ax, 1 ;show cursor
int 33h
ret
prepare_mouse ENDP
mouseProc PROC FAR ;other doc segment therefore FAR
enter 0, 0
push ax
push bx
push cx
push dx
push es
push ds
mov ax, 2 ;hide cursor
int 33h
;dx contains coordinates of "rows"
mov y_wert, dx ;save y coordinate in variable
;cx contains coordinates of "columns"
mov x_wert, cx ;save y coordinate in variable
call game_logic
xor bx, bx ;button pressed clear result
mov ax, 1 ;show cursor
int 33h
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
leave
ret
mouseProc ENDP
start_programm PROC
mov AX, video_seg
mov es, AX
mov ax, @DATA
mov ds, ax
mov ax, 12h
int 10h
mov dx, 03C4h ;address of the index port (share)
mov al, 2 ;index of control register
out dx, al ;Set index: output out :: dx to port al(2)
inc dx ;index of dataport
mov al, 0Fh ;value (1 = bit plane enabled, here all) fi
out dx, al
call prepare_timer_tick
mov ax,0Dh
int 10h
call paint_menu
check_mode_loop:
xor ax, ax ;delete ah
int 16h ;keyboard query
cmp al,'1'
je short playgame
cmp al,'2'
je ende
jmp check_mode_loop
playgame:
call start_game
ret
start_programm ENDP

133
main.asm Normal file
View File

@ -0,0 +1,133 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; main.asm
; file contains source code for the
; main operations
;
;****************************************
.model small
.STACK 100h
.486
esc_code = 1Bh ;esc key
video_seg = 0B800h
.data
INCLUDE data.asm
.code
INCLUDE draw.asm
INCLUDE game.asmn
INCLUDE sound.asm
INCLUDE logic.asm
ISR1Ch: push ds
push ax
mov ax, @DATA
mov ds, ax
pop ax
pop ds
iret
;start of the main program
;----------------------------------------------------------------------------------------------------------
Beginn:
mov ax, @DATA
mov ds, ax
mov ax, 3
int 10h
;read old VT entry
mov al, 1Ch
mov ah, 35h
int 21h
;es:bx address old ISR
;save
mov oldIOFF, bx
mov oldISeg, es
;store new ISR
push ds ; store ds
push cs
pop ds ; ds <- cs
mov dx, OFFSET ISR1Ch ; address in ds:dx
mov al, 1Ch ; <vn>
mov ah, 25h
int 21h
pop ds ; restore ds
call start_programm
;--------------------------------------------------------------------------------------------------------
;Endlosschleife
;--------------------------------------------------------------------------------------------------------
endlloop:
xor ax, ax ;delete ah
int 16h ;Keyboard query, waits for any key is pressed
cmp al, esc_code ;If esc is not pressed, the program remains in the endless loop
jne short endlloop ;jmp not equal
call reset_timerisr
mov cx, 0
call start_programm
;-------------------------------------------------------------------------------------------------------
;End of the program and return to DOS
;-----------------------------------------------------------------------------------------------------
ende:
PUSH DS
MOV AX, 251Ch ;Restore old user timer interrupt vector
MOV DX, [CS:old_timer]
MOV CX, [CS:old_segment]
MOV DS, CX
INT 21h
POP DS
mov ax, 0 ;reset mouse programm
int 33h ;mouse interrupt
MOV ax, 3 ;Reset screen mode
INT 10h
mov dx, oldIOFF ;order is important
mov ax, oldISeg
mov ds, ax
mov al, 1Ch
mov ah, 25h
int 21h
mov ah, 4Ch ;Backflow to DOS
int 21h
.stack 100h
end Beginn
;---------------------------------------------------------------------------------------------------
; Convert X: Y coordinates to fields
; Check whether the field is free
; if free field
; test whether the player has won
; 1 2 3 0 1 2
; 1|2 3 4 0|0 1 2
; 4|5 6 7 3|3 4 5
; 7|8 9 10 6|6 7 8
;8 test cases
; 0,3,6
; 1,4,7
; 2,5,8
; 0,1,2
; 3,4,5
; 6,7,8
; 0,4,8
; 6,4,2

45
sound.asm Normal file
View File

@ -0,0 +1,45 @@
;****************************************
; Elmar Kresse 19-INB-1 (2021)
; sound.asm
; file contains source code for
; only playing sounds
;
; - playbeep PROC
;source: http://muruganad.com/8086/8086-assembly-language-program-to-play-sound-using-pc-speaker.html
;****************************************
playbeep PROC
MOV AL, 182
OUT 43h, AL
beep:
;set frequency
MOV AX, [BX]
OUT 42h, AL
MOV AL, AH
OUT 42h, AL
;sound on
IN AL, 61h
OR AL, 00000011b
OUT 61h, AL
ADD BX, 4
MOV WORD ptr [CS:timer_ticks], 0
;break
timer_loop:
CMP WORD ptr [CS:timer_ticks], 3
jne timer_loop
MOV WORD ptr [CS:timer_ticks], 0
;sound off
IN AL, 61h
AND AL, 11111100b
OUT 61h, AL
ADD BX, 4
SUB CX, 8
JNE beep
ret
playbeep ENDP