Compare commits

...

2 Commits

Author SHA1 Message Date
Lucia Ceionia
43d12dae95 day 7 part 2 2023-12-07 02:48:10 -06:00
Lucia Ceionia
b71d3da003 day 7 part 1 2023-12-07 01:21:29 -06:00
6 changed files with 1784 additions and 0 deletions

3
07/Makefile Normal file
View File

@ -0,0 +1,3 @@
all:
nasm -g -felf32 main.s && ld -melf_i386 -g main.o

1000
07/input Normal file

File diff suppressed because it is too large Load Diff

5
07/input_test Normal file
View File

@ -0,0 +1,5 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483

376
07/main.s Normal file
View File

@ -0,0 +1,376 @@
global _start
[bits 32]
[section .text]
%include "utils.s"
; for h in hands
; ; score hands
; tmp := 0
; counts[15] := [0; 15]
; joker_values := [0; 5]
; for c in h
; if c > '9'
; if c = 'T' then value := 10
; elif c = 'J' then
; value := 1
; joker_values[char_idx] := 1
; end
; elif c = 'Q' then value := 11
; elif c = 'K' then value := 12
; elif c = 'A' then value := 13
; else
; value := c - '0'
; end
; tmp := (tmp * 14) + value
; put in counts
; end
; ; joker bs
; orig_val := tmp
; best_score := orig_val
; loop
; fake_counts := counts
; tmp := orig_val
; for j in joker_values where j != 0
; fake_counts[j] += 1
; end
;
; ; check hand type
; has_five := 0
; has_four := 0
; has_three := 0
; has_two := 0
; for n in fake_counts
; if n = 5 then inc has_five
; if n = 4 then inc has_four
; if n = 3 then inc has_three
; if n = 2 then inc has_two
; end
; if has_five then tmp := tmp + 60,000,000
; elif has_four then tmp := tmp + 50,000,000
; elif has_three and has_two then tmp := tmp + 40,000,000
; elif has_three then tmp := tmp + 30,000,000
; elif has_two = 2 then tmp := tmp + 20,000,000
; elif has_two = 1 then tmp := tmp + 10,000,000
; if tmp > best_score then best_score := tmp
;
; last_joker_carried := 1
; i := 0
; loop
; if joker_values[i] + 1 = 14 then
; joker_values[i] = 2
; else
; joker_values[i] += 1
; last_joker_carried := 0
; end
; .cont:
; inc i
; if i = 5 then break
; if !last_joker_carried then break
; end
; if last_joker_carried then break
; end
; ; store in array
; stosd best_score -> hand_array
; stosd bid -> hand_array
; end
;
; bubble sort hand_array
;
; calc total
; rank := 1
; for (_, bid) in hand_array
; final_value += rank * bid
; rank += 1
; end
;
; done
_start:
mov esi, file
mov edi, hand_array
; for l in lines
; ...
; end
for_in_lines:
; check for end
cmp esi, file.over
jae for_in_lines_end
; score hand
; tmp := 0
xor ebp, ebp ; tmp
; counts[15] := [0; 15]
push edi
mov edi, counts
mov ecx, 15
xor eax, eax
rep stosb
pop edi
; zero joker_values
mov dword [joker_values], 0
mov dword [joker_values+4], 0
get_hand_score:
; do 5 times
; ...
; end
mov ecx, 5
xor ebx, ebx ; char value
push edi ; save edi
xor edi, edi ; idx
.next_char:
lodsb
; if c > '9'
cmp al, '9'
jle .is_num
mov edx, 10
cmp al, 'T'
cmove ebx, edx
cmp al, 'J'
jne .not_joker
mov ebx, 1
mov byte [joker_values+edi], 1
jmp .add_to_tmp_skip_counts
.not_joker:
mov edx, 11
cmp al, 'Q'
cmove ebx, edx
mov edx, 12
cmp al, 'K'
cmove ebx, edx
mov edx, 13
cmp al, 'A'
cmove ebx, edx
jmp .add_to_tmp
.is_num:
; else val := c - '0'
sub al, '0'
movzx ebx, al
; end
.add_to_tmp:
; put in counts
inc byte [counts+ebx]
.add_to_tmp_skip_counts:
; tmp *= 14
; tmp += score
mov eax, ebp
mov edx, 14
mul edx
add eax, ebx
mov ebp, eax
inc edi ; idx
loop .next_char
pop edi ; restore edi
; joker bs
joker_bs:
push ebp ; best_score (esp + 4)
push ebp ; orig_val (esp)
; loop .. end
joker_loop:
; fake_counts := counts
; tmp := orig_val
mov eax, [counts+0]
mov [fake_counts+0], eax
mov eax, [counts+4]
mov [fake_counts+4], eax
mov eax, [counts+8]
mov [fake_counts+8], eax
mov eax, [counts+12]
mov [fake_counts+12], eax
mov ebp, [esp] ; tmp := orig_val
; for j in joker_values where j != 0
; fake_counts[j] += 1
; end
push esi
mov ecx, 5
mov esi, joker_values
xor eax, eax
add_fake_counts:
lodsb
inc byte [fake_counts+eax]
.cont:
loop add_fake_counts
mov byte [fake_counts], 0 ; idx 0 is always 0
pop esi
; check hand type
mov byte [has_five], 0
mov byte [has_four], 0
mov byte [has_three], 0
mov byte [has_two], 0
; for n in fake_counts
mov ecx, 15
push esi ; save line
mov esi, fake_counts
check_counts:
lodsb
cmp al, 5
jne .check_4
inc byte [has_five]
.check_4:
cmp al, 4
jne .check_3
inc byte [has_four]
.check_3:
cmp al, 3
jne .check_2
inc byte [has_three]
.check_2:
cmp al, 2
jne .check_cont
inc byte [has_two]
.check_cont:
loop check_counts
; end
pop esi ; restore line
cmp byte [has_five], 0
je .maybe_four
add ebp, 60000000
jmp .save
.maybe_four:
cmp byte [has_four], 0
je .maybe_three
add ebp, 50000000
jmp .save
.maybe_three:
cmp byte [has_three], 0
je .maybe_twos
add ebp, 30000000
.maybe_twos:
mov cl, byte [has_two]
cmp cl, 0
je .save
mov eax, 10000000/2
shl eax, cl
add ebp, eax
.save:
; if tmp > best_score then best_score := tmp
cmp ebp, [esp+4] ; best_score
jbe .not_better
mov [esp+4], ebp
.not_better:
mov edx, 1 ; last_joker_carried := 1
xor ecx, ecx ; i := 0
; loop..end
increment_jokers:
; if joker_values[i] + 1 = 14 then
; joker_values[i] = 2
; else
; joker_values[i] += 1
; last_joker_carried := 0
; end
cmp byte [joker_values+ecx], 0
je .cont
cmp byte [joker_values+ecx], 13
jne .else
mov byte [joker_values+ecx], 2
jmp .cont
.else:
inc byte [joker_values+ecx]
xor edx, edx
.cont:
inc ecx ; i += 1
; if i = 5 then break
; if !last_joker_carried then break
cmp ecx, 5
je increment_jokers_end
test edx, edx
jz increment_jokers_end
jmp increment_jokers
increment_jokers_end:
; if last_joker_carried then break
test edx, edx
jnz joker_bs_end
joker_loop_end:
jmp joker_loop
joker_bs_end:
pop eax ; orig_val (discard)
pop eax ; best_score
real_save:
; store best_score & bid in array
stosd
inc esi ; skip space
call dec_parse ; bid
stosd
for_in_lines_cont:
jmp for_in_lines
for_in_lines_end:
; bubble sort hand_array
bubble_sort:
; get length (array is null terminated)
mov esi, hand_array
xor eax, eax
get_len:
cmp dword [esi+eax*8], 0
je .done
inc eax
jmp get_len
.done:
mov ebp, eax ; n
do_sort:
xor edx, edx ; newn
mov ecx, 1 ; i
.inner:
mov eax, [esi+ecx*8-8] ; A[i-1]
cmp eax, [esi+ecx*8] ; A[i]
jbe .inner_cont
; swap elements
xchg eax, [esi+ecx*8]
mov [esi+ecx*8-8], eax
mov eax, [esi+ecx*8-4] ; A[i-1] bid
xchg eax, [esi+ecx*8+4] ; A[i] bid
mov [esi+ecx*8-4], eax
mov edx, ecx ; newn
.inner_cont:
inc ecx
cmp ecx, ebp
jb .inner
mov ebp, edx ; n := newn
cmp ebp, 1
ja do_sort ; until n <= 1
done_sort:
; calc total
; rank := 1
mov ebx, 1
mov esi, hand_array
calc_total:
lodsd ; _
lodsd ; bid
test eax, eax
jz calc_total_done
mul ebx
add [final_value], eax
inc ebx
jmp calc_total
calc_total_done:
game_over:
mov eax, [final_value]
call print_dec
jmp exit
[section .data]
final_value: dd 0
joker_values: times 8 db 0 ; we only use 5 but this makes zeroing easier
counts: times 16 db 0 ; only use 14 or 13 but whatever
fake_counts: times 16 db 0
has_five: db 0
has_four: db 0
has_three: db 0
has_two: db 0
file_lim: dd file.over - file
file: incbin "input"
.over:
[section .bss]
hand_array: resd 4096

254
07/main_part1.s Normal file
View File

@ -0,0 +1,254 @@
global _start
[bits 32]
[section .text]
%include "utils.s"
; for h in hands
; ; score hands
; tmp := 0
; counts[15] := [0; 15]
; for c in h
; if c > '9'
; if c = 'T' then score := 10
; elif c = 'J' then score := 11
; elif c = 'Q' then score := 12
; elif c = 'K' then score := 13
; elif c = 'A' then score := 14
; else
; score := c - '0'
; end
; tmp := (tmp * 14) + score
; put in counts
; end
; ; check hand type
; has_five := 0
; has_four := 0
; has_three := 0
; has_two := 0
; for n in counts
; if n = 5 then inc has_five
; if n = 4 then inc has_four
; if n = 3 then inc has_three
; if n = 2 then inc has_two
; end
; if has_five then tmp := tmp + 60,000,000
; elif has_four then tmp := tmp + 50,000,000
; elif has_three and has_two then tmp := tmp + 40,000,000
; elif has_three then tmp := tmp + 30,000,000
; elif has_two = 2 then tmp := tmp + 20,000,000
; elif has_two = 1 then tmp := tmp + 10,000,000
; ; store tmp in array
; stosd tmp -> hand_array
; stosd bid -> hand_array
; end
;
; bubble sort hand_array
;
; calc total
; rank := 1
; for (_, bid) in hand_array
; final_value += rank * bid
; rank += 1
; end
;
; done
_start:
mov esi, file
mov edi, hand_array
; for l in lines
; ...
; end
for_in_lines:
; check for end
cmp esi, file.over
jae for_in_lines_end
; score hand
; tmp := 0
xor ebp, ebp ; tmp
; counts[15] := [0; 15]
push edi
mov edi, counts
mov ecx, 15
xor eax, eax
rep stosb
pop edi
get_hand_score:
; do 5 times
; ...
; end
mov ecx, 5
xor ebx, ebx ; char value
.next_char:
lodsb
; if c > '9'
cmp al, '9'
jle .is_num
mov edx, 10
cmp al, 'T'
cmove ebx, edx
mov edx, 11
cmp al, 'J'
cmove ebx, edx
mov edx, 12
cmp al, 'Q'
cmove ebx, edx
mov edx, 13
cmp al, 'K'
cmove ebx, edx
mov edx, 14
cmp al, 'A'
cmove ebx, edx
jmp .add_to_tmp
.is_num:
; else val := c - '0'
sub al, '0'
movzx ebx, al
; end
.add_to_tmp:
; tmp *= 14
; tmp += score
mov eax, ebp
mov edx, 14
mul edx
add eax, ebx
mov ebp, eax
; put in counts
inc byte [counts+ebx]
loop .next_char
; check hand type
mov byte [has_five], 0
mov byte [has_four], 0
mov byte [has_three], 0
mov byte [has_two], 0
; for n in counts
mov ecx, 15
push esi ; save line
mov esi, counts
check_counts:
lodsb
cmp al, 5
jne .check_4
inc byte [has_five]
.check_4:
cmp al, 4
jne .check_3
inc byte [has_four]
.check_3:
cmp al, 3
jne .check_2
inc byte [has_three]
.check_2:
cmp al, 2
jne .check_cont
inc byte [has_two]
.check_cont:
loop check_counts
; end
pop esi ; restore line
cmp byte [has_five], 0
je .maybe_four
add ebp, 60000000
jmp .save
.maybe_four:
cmp byte [has_four], 0
je .maybe_three
add ebp, 50000000
jmp .save
.maybe_three:
cmp byte [has_three], 0
je .maybe_twos
add ebp, 30000000
.maybe_twos:
mov cl, byte [has_two]
cmp cl, 0
je .save
mov eax, 10000000/2
shl eax, cl
add ebp, eax
.save:
; store tmp & bid in array
mov eax, ebp
stosd
inc esi ; skip space
call dec_parse ; bid
stosd
for_in_lines_cont:
jmp for_in_lines
for_in_lines_end:
; bubble sort hand_array
bubble_sort:
; get length (array is null terminated)
mov esi, hand_array
xor eax, eax
get_len:
cmp dword [esi+eax*8], 0
je .done
inc eax
jmp get_len
.done:
mov ebp, eax ; n
do_sort:
xor edx, edx ; newn
mov ecx, 1 ; i
.inner:
mov eax, [esi+ecx*8-8] ; A[i-1]
cmp eax, [esi+ecx*8] ; A[i]
jbe .inner_cont
; swap elements
xchg eax, [esi+ecx*8]
mov [esi+ecx*8-8], eax
mov eax, [esi+ecx*8-4] ; A[i-1] bid
xchg eax, [esi+ecx*8+4] ; A[i] bid
mov [esi+ecx*8-4], eax
mov edx, ecx ; newn
.inner_cont:
inc ecx
cmp ecx, ebp
jb .inner
mov ebp, edx ; n := newn
cmp ebp, 1
ja do_sort ; until n <= 1
done_sort:
; calc total
; rank := 1
mov ebx, 1
mov esi, hand_array
calc_total:
lodsd ; _
lodsd ; bid
test eax, eax
jz calc_total_done
mul ebx
add [final_value], eax
inc ebx
jmp calc_total
calc_total_done:
game_over:
mov eax, [final_value]
call print_dec
jmp exit
[section .data]
final_value: dd 0
counts: times 15 db 0
has_five: db 0
has_four: db 0
has_three: db 0
has_two: db 0
file_lim: dd file.over - file
file: incbin "input"
.over:
[section .bss]
hand_array: resd 4096

146
07/utils.s Normal file
View File

@ -0,0 +1,146 @@
; call # val val2
; int $0x80 eax eax edx -
;
; arg1 arg2 arg3 arg4 arg5 arg6 arg7
; ebx ecx edx esi edi ebp -
exit:
mov eax, 1 ; exit
int 0x80
; filename in EBX
; return handle in EBX
; read only
open_file:
push eax
push ecx
mov eax, 5 ; open
xor ecx, ecx ; read only
int 0x80
mov ebx, eax
pop ecx
pop eax
ret
; file handle in EBX
; buffer in ECX
; count of bytes to read in EDX
; return bytes actually read in EAX
; exits on error
read_file:
mov eax, 3 ; read
int 0x80
test eax, eax
js .err
ret
.err:
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, .err_str
mov edx, 21
int 0x80
jmp exit
.err_str: db `Could not read file.\n`
; string input in ESI
; value in EAX
; CF set if none, clear if some
; ESI set past checked area
dec_parse:
push ebx
push edx
push edi
xor eax, eax
xor edi, edi
mov ebx, 10 ; base
lodsb
sub al, '0'
js .no_input
cmp al, 9
jle .got_char
.no_input:
stc ; set CF
jmp .done
.loop:
xor eax,eax
lodsb
sub al, '0'
js .dec_done
cmp al, 9
jg .dec_done
.got_char:
xchg edi,eax
mul ebx
add edi,eax
jmp .loop
.dec_done:
clc ; clear CF
.done:
mov eax,edi
pop edi
pop edx
pop ebx
ret
; modifies no regs
newline:
pushad
push 10
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, esp ; string
mov edx, 1 ; length
int 0x80
add esp, 4
popad
ret
; modifies no regs
space:
pushad
push 9
mov eax, 4 ; write
mov ebx, 1 ; stdout
mov ecx, esp ; string
mov edx, 1 ; length
int 0x80
add esp, 4
popad
ret
; input in EAX, all regs unmodified
print_dec:
pushad ; save regs
; max 4294967296 is 10 chars
; round to nearest 32-bit boundary
sub esp, 12
; string in ECX, length in EDX
lea ecx, [esp+11] ; last possible byte
; check for 0
test eax, eax
jz .zero
mov ebx, 10 ; base 10
xor esi, esi ; counter
.div_shit:
xor edx, edx
; divide
div ebx
dec ecx ; next char
inc esi
; store
add dl, '0'
mov byte [ecx], dl
; check if done
test eax, eax
jnz .div_shit ; continue
mov edx, esi ; counter in edx
jmp .write
.zero:
mov byte [ecx], '0'
mov edx, 1 ; length
.write:
mov eax, 4 ; write
mov ebx, 1 ; stdout
int 0x80
add esp, 12 ; restore stack
popad ; restore regs
ret