Compare commits
No commits in common. "master" and "0ac65464902ff2e2076a19b1ef879fef8f5ac961" have entirely different histories.
master
...
0ac6546490
20
Makefile
20
Makefile
|
@ -1,30 +1,20 @@
|
|||
NASM ?= nasm
|
||||
PYTHON ?= python
|
||||
|
||||
# 'murky' is the rarest target word we'll use
|
||||
# https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/Game.tsx#L34
|
||||
RAREST_WORD = murky
|
||||
|
||||
all: dosdl.com
|
||||
|
||||
dosdl.com: dosdl.asm dictionary.inc targets.inc license.inc
|
||||
dosdl.com: dosdl.asm dictionary.inc targets.inc
|
||||
$(NASM) -fbin -o $@ $<
|
||||
|
||||
dictionary.inc: dictionary.json targets.json compress-dict.py
|
||||
$(PYTHON) compress-dict.py $< targets.json $(RAREST_WORD) $@
|
||||
dictionary.inc: dictionary.json compress-dict.py
|
||||
$(PYTHON) compress-dict.py $< $@
|
||||
|
||||
targets.inc: targets.json compress-targets.py
|
||||
$(PYTHON) compress-targets.py $< $(RAREST_WORD) $@
|
||||
|
||||
license.inc: LICENSE embed-textfile.py
|
||||
$(PYTHON) embed-textfile.py $< license_str $@
|
||||
$(PYTHON) compress-targets.py $< $@
|
||||
|
||||
clean:
|
||||
rm -f *.inc *.com
|
||||
|
||||
distclean: clean
|
||||
|
||||
run: dosdl.com
|
||||
dosbox dosdl.com
|
||||
|
||||
.PHONY: all clean distclean run
|
||||
.PHONY: all clean distclean
|
||||
|
|
23
README.md
23
README.md
|
@ -1,27 +1,14 @@
|
|||
hello DOSdl
|
||||
===========
|
||||
Hello DOSdl is a variant of Wordle / hello wordl for MS-DOS.
|
||||
|
||||
System requirements
|
||||
-------------------
|
||||
|
||||
- MS-DOS 1.25 or later, or PC-DOS 1.1 or later
|
||||
- 64KiB of RAM
|
||||
|
||||
Notably, hello DOSdl has been written to only use the DOS APIs, meaning it
|
||||
should work on non-PC DOS platforms as well.
|
||||
|
||||
Gameplay
|
||||
--------
|
||||
Gameplay is as in hello wordl's default daily mode. `x` under a letter marks it
|
||||
as incorrect and `^` marks it as being in the wrong place.
|
||||
Hello DOSdl is a variant of Wordle / hello wordl for MS-DOS running on IBM PC
|
||||
compatible systems.
|
||||
|
||||
Word lists
|
||||
----------
|
||||
The words lists are taken from
|
||||
[hello wordl](https://github.com/lynn/hello-wordl#where-are-the-words-coming-from)
|
||||
and are identical as of 2023-03-20, to allow cross-play between hello DOSdl and
|
||||
hello wordl. See the link for further details.
|
||||
[hello wordl](https://github.com/lynn/hello-wordl) and are identical as of
|
||||
2022-02-02, to allow cross-play between hello DOSdl and hello wordl. See the
|
||||
link for further details.
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
|
|
@ -5,27 +5,13 @@ import sys
|
|||
alphabet = 'abcdefghijklmnopqrstuvwxyz'
|
||||
|
||||
srcpath = sys.argv[1]
|
||||
excludepath = sys.argv[2]
|
||||
rarestword = sys.argv[3]
|
||||
targetpath = sys.argv[4]
|
||||
targetpath = sys.argv[2]
|
||||
|
||||
with open(srcpath, 'r') as f:
|
||||
words = json.load(f)
|
||||
|
||||
with open(excludepath, 'r') as f:
|
||||
exclude_all = json.load(f)
|
||||
|
||||
# We only care about 5-letter words
|
||||
words = [word for word in words if len(word) == 5]
|
||||
exclude_all = [word for word in exclude_all if len(word) == 5]
|
||||
|
||||
exclude = set()
|
||||
for word in exclude_all:
|
||||
exclude.add(word)
|
||||
if word == rarestword: break
|
||||
|
||||
# Don't include words in the exclude list
|
||||
words = [word for word in words if word not in exclude]
|
||||
|
||||
# Split dictionary into per-startletter arrays
|
||||
arrays = {letter: [] for letter in alphabet}
|
||||
|
|
|
@ -5,16 +5,10 @@ import sys
|
|||
alphabet = 'abcdefghijklmnopqrstuvwxyz*'
|
||||
|
||||
srcpath = sys.argv[1]
|
||||
rarestword = sys.argv[2]
|
||||
targetpath = sys.argv[3]
|
||||
targetpath = sys.argv[2]
|
||||
|
||||
with open(srcpath, 'r') as f:
|
||||
all_words = json.load(f)
|
||||
|
||||
words = []
|
||||
for word in all_words:
|
||||
words.append(word)
|
||||
if word == rarestword: break
|
||||
words = json.load(f)
|
||||
|
||||
# We only care about 5-letter words
|
||||
words = [word for word in words if len(word) == 5]
|
||||
|
@ -28,7 +22,6 @@ for word in words:
|
|||
array.append(packed)
|
||||
|
||||
with open(targetpath, 'w') as f:
|
||||
f.write(f'targets_len equ {len(array)}\n')
|
||||
f.write('targets:\n')
|
||||
for packed in array:
|
||||
f.write(f'\tdb {", ".join(str(byte) for byte in packed)}\n')
|
||||
|
|
|
@ -1882,7 +1882,6 @@
|
|||
"admeasures",
|
||||
"admeasuring",
|
||||
"admen",
|
||||
"admin",
|
||||
"administer",
|
||||
"administered",
|
||||
"administering",
|
||||
|
@ -147270,7 +147269,6 @@
|
|||
"sirupy",
|
||||
"sirvente",
|
||||
"sirventes",
|
||||
"sirwal",
|
||||
"sis",
|
||||
"sisal",
|
||||
"sisals",
|
||||
|
|
791
dosdl.asm
791
dosdl.asm
|
@ -3,206 +3,46 @@ cpu 8086
|
|||
|
||||
org 0x100
|
||||
|
||||
args_length equ 0x80
|
||||
args_area equ 0x81
|
||||
|
||||
section .code
|
||||
|
||||
parse_arguments:
|
||||
xor ch, ch
|
||||
mov cl, [args_length]
|
||||
mov si, args_area
|
||||
|
||||
; Skip leading spaces
|
||||
.skip_leading_space:
|
||||
test cx, cx
|
||||
jz .leading_spaces_skipped
|
||||
cmp byte [si], ' '
|
||||
jne .leading_spaces_skipped
|
||||
dec cx
|
||||
inc si
|
||||
jmp .skip_leading_space
|
||||
|
||||
.leading_spaces_skipped:
|
||||
|
||||
; See whether we have /h, /u, /l, or /?
|
||||
cmp cx, 2
|
||||
jb .not_mode_option
|
||||
cmp byte [si], '/'
|
||||
jne .not_mode_option
|
||||
|
||||
cmp byte [si + 1], 'h'
|
||||
je .hard_mode
|
||||
cmp byte [si + 1], 'H'
|
||||
jne .not_hard_mode
|
||||
|
||||
.hard_mode:
|
||||
mov byte [hard_mode], 1
|
||||
add si, 2
|
||||
sub cx, 2
|
||||
jmp .after_option_space
|
||||
|
||||
.not_hard_mode:
|
||||
cmp byte [si + 1], 'u'
|
||||
je .ultra_hard_mode
|
||||
cmp byte [si + 1], 'U'
|
||||
jne .not_ultra_hard_mode
|
||||
|
||||
.ultra_hard_mode:
|
||||
mov byte [hard_mode], 1
|
||||
mov byte [ultra_hard_mode], 1
|
||||
add si, 2
|
||||
sub cx, 2
|
||||
|
||||
.after_option_space:
|
||||
test cx, cx
|
||||
jz .option_done
|
||||
cmp byte [si], ' '
|
||||
jne .option_done
|
||||
dec cx
|
||||
inc si
|
||||
jmp .after_option_space
|
||||
|
||||
.option_done:
|
||||
|
||||
.not_ultra_hard_mode:
|
||||
cmp byte [si + 1], 'l'
|
||||
je print_license
|
||||
cmp byte [si + 1], 'L'
|
||||
je print_license
|
||||
|
||||
cmp byte [si + 2], '?'
|
||||
je print_help
|
||||
|
||||
.not_mode_option:
|
||||
|
||||
test cx, cx
|
||||
jz seed_rng_date
|
||||
|
||||
seed_rng_argument:
|
||||
xor ax, ax
|
||||
xor dx, dx
|
||||
mov bp, mull32
|
||||
call store32
|
||||
|
||||
.loop:
|
||||
xor dx, dx
|
||||
mov ax, 10
|
||||
mov bp, mulr32
|
||||
call store32
|
||||
call mul32
|
||||
mov bp, addl32
|
||||
call store32
|
||||
|
||||
lodsb
|
||||
cmp al, '0'
|
||||
jb print_help
|
||||
cmp al, '9'
|
||||
ja print_help
|
||||
|
||||
sub al, '0'
|
||||
|
||||
xor ah, ah
|
||||
xor dx, dx
|
||||
mov bp, addr32
|
||||
call store32
|
||||
|
||||
call add32
|
||||
mov bp, mull32
|
||||
call store32
|
||||
|
||||
loop .loop
|
||||
|
||||
mov bp, rng_seed
|
||||
call store32
|
||||
jmp select_target
|
||||
|
||||
print_help:
|
||||
mov ah, 9
|
||||
mov dx, help_str
|
||||
int 0x21
|
||||
|
||||
ret
|
||||
|
||||
print_license:
|
||||
mov ah, 9
|
||||
mov dx, license_str
|
||||
int 0x21
|
||||
|
||||
ret
|
||||
|
||||
seed_rng_date:
|
||||
; Get date
|
||||
mov ah, 0x2a
|
||||
int 0x21
|
||||
mov [year], cx
|
||||
mov [month], dh
|
||||
%ifdef DEBUG
|
||||
mov cx, 2022
|
||||
mov dh, 2
|
||||
mov dl, 24
|
||||
%endif
|
||||
mov [day], dl
|
||||
|
||||
; addl32 = year * 10000
|
||||
mov ax, 10000
|
||||
mul word [year]
|
||||
mov bp, addl32
|
||||
call store32
|
||||
|
||||
; addr32 = month * 100 + day
|
||||
mov ax, 100
|
||||
mul word [month]
|
||||
add ax, [day]
|
||||
mov bp, addr32
|
||||
call store32
|
||||
|
||||
; rng_seed = addl32 + addr32 = year * 10000 + month * 100 + day
|
||||
call add32
|
||||
mov bp, rng_seed
|
||||
call store32
|
||||
|
||||
select_target:
|
||||
; Call rng to get a number
|
||||
call rng
|
||||
mov bp, rng_output
|
||||
call store32
|
||||
; TODO: Implement target word selection
|
||||
mov si, 1
|
||||
|
||||
; Multiply rng output by number of target words
|
||||
xor si, si
|
||||
xor dx, dx
|
||||
xor ax, ax
|
||||
mov cx, targets_len
|
||||
.multiply_loop:
|
||||
add ax, [rng_output + 0]
|
||||
adc dx, [rng_output + 2]
|
||||
adc si, 0
|
||||
loop .multiply_loop
|
||||
|
||||
mov ax, si
|
||||
%ifdef DEBUG
|
||||
call hexprint16
|
||||
call newline
|
||||
%endif
|
||||
|
||||
load_target:
|
||||
extract_target:
|
||||
shl si, 1
|
||||
shl si, 1
|
||||
add si, targets
|
||||
|
||||
mov di, target
|
||||
|
||||
call unpack_target
|
||||
; Target word is stored packed 5 bits per letter into 32 bits
|
||||
; 2221_1111 4333_3322 5555_4444 0000_0005
|
||||
; Load 4333_3322_2221_1111 into dx and extracts first three letters
|
||||
mov dx, [si]
|
||||
add si, 2
|
||||
mov cl, 5
|
||||
%rep 3
|
||||
mov al, dl
|
||||
and al, 0x1f
|
||||
add al, 'a'
|
||||
stosb
|
||||
shr dx, cl
|
||||
%endrep
|
||||
|
||||
; Figure out whether this is a removed word
|
||||
; If so, reroll target word
|
||||
cmp byte [target], '{'
|
||||
je select_target
|
||||
|
||||
print_greeting:
|
||||
mov ah, 9
|
||||
mov dx, greeting_str
|
||||
int 0x21
|
||||
; Load 0000_0005_5555_4444 into ax, shift over by one, combine into dx
|
||||
; which has 0000_0000_0000_0004, and extract last two letters
|
||||
mov ax, [si]
|
||||
add si, 2
|
||||
shl ax, 1
|
||||
or dx, ax
|
||||
%rep 2
|
||||
mov al, dl
|
||||
and al, 0x1f
|
||||
add al, 'a'
|
||||
stosb
|
||||
shr dx, cl
|
||||
%endrep
|
||||
|
||||
read_guess:
|
||||
; Number of thus far guessed letters stored in bx
|
||||
|
@ -212,9 +52,6 @@ read_guess:
|
|||
mov ah, 8
|
||||
int 0x21
|
||||
|
||||
cmp al, 3
|
||||
je .ctrl_c
|
||||
|
||||
cmp al, 8
|
||||
je .backspace
|
||||
|
||||
|
@ -274,146 +111,6 @@ read_guess:
|
|||
|
||||
jmp .loop
|
||||
|
||||
.ctrl_c:
|
||||
ret
|
||||
|
||||
.done:
|
||||
|
||||
check_hard_mode:
|
||||
cmp byte [hard_mode], 1
|
||||
jne .done
|
||||
|
||||
; See whether exact hits are reused
|
||||
xor bp, bp
|
||||
mov cx, 5
|
||||
.exact_hits:
|
||||
mov al, [exact_hits + bp]
|
||||
test al, al
|
||||
jz .not_exact_hit
|
||||
|
||||
cmp al, [guess + bp]
|
||||
je .exact_hit_match
|
||||
|
||||
mov dx, bp
|
||||
add dl, '1'
|
||||
mov [exact_hit_error_str.position], dl
|
||||
mov [exact_hit_error_str.letter], al
|
||||
mov si, exact_hit_error_str
|
||||
jmp print_error
|
||||
|
||||
.exact_hit_match:
|
||||
.not_exact_hit:
|
||||
inc bp
|
||||
loop .exact_hits
|
||||
|
||||
; See whether wrongly placed letters are reused
|
||||
xor bp, bp
|
||||
.wrong_places:
|
||||
cmp bp, 5
|
||||
je .done
|
||||
|
||||
mov dl, [wrong_places + bp]
|
||||
test dl, dl
|
||||
jz .not_wrong_place
|
||||
|
||||
; Count how many times letter is used in exact_hits + wrong_places
|
||||
xor bx, bx
|
||||
mov cx, 5
|
||||
mov si, exact_hits
|
||||
.count_exact_hits:
|
||||
lodsb
|
||||
cmp al, dl
|
||||
jne .not_count_exact_hit
|
||||
inc bh
|
||||
.not_count_exact_hit:
|
||||
loop .count_exact_hits
|
||||
mov cx, 5
|
||||
mov si, wrong_places
|
||||
.count_wrong_places:
|
||||
lodsb
|
||||
cmp al, dl
|
||||
jne .not_count_wrong_places
|
||||
inc bh
|
||||
.not_count_wrong_places:
|
||||
loop .count_wrong_places
|
||||
|
||||
; Count how many times letter is used in guess
|
||||
mov cx, 5
|
||||
mov si, guess
|
||||
.count_guess:
|
||||
lodsb
|
||||
cmp al, dl
|
||||
jne .not_count_guess
|
||||
inc bl
|
||||
.not_count_guess:
|
||||
loop .count_guess
|
||||
|
||||
cmp bl, bh
|
||||
jae .used_enough
|
||||
|
||||
mov [wrong_place_error_str.letter], dl
|
||||
mov ax, bp
|
||||
add ax, '1'
|
||||
mov [wrong_place_error_str.position], al
|
||||
mov si, wrong_place_error_str
|
||||
jmp print_error
|
||||
|
||||
.used_enough:
|
||||
.not_wrong_place:
|
||||
inc bp
|
||||
jmp .wrong_places
|
||||
|
||||
.done:
|
||||
|
||||
check_ultra_hard_mode:
|
||||
cmp byte [ultra_hard_mode], 1
|
||||
jne .done
|
||||
|
||||
; See whether any ruled-out letters were used
|
||||
xor bp, bp
|
||||
mov cx, 5
|
||||
.ruled_out:
|
||||
xor bh, bh
|
||||
mov bl, [guess + bp]
|
||||
mov ax, bx
|
||||
mov al, [alphabet + bx - 'a']
|
||||
cmp al, ' '
|
||||
jne .not_ruled_out
|
||||
|
||||
mov [ruled_out_error_str.letter], bl
|
||||
mov ax, bp
|
||||
add al, '1'
|
||||
mov [ruled_out_error_str.position], al
|
||||
mov si, ruled_out_error_str
|
||||
jmp print_error
|
||||
|
||||
.not_ruled_out:
|
||||
inc bp
|
||||
loop .ruled_out
|
||||
|
||||
; See whether wrongly places letters were moved
|
||||
xor bp, bp
|
||||
mov cx, 5
|
||||
.wrong_places:
|
||||
mov al, [wrong_places + bp]
|
||||
test al, al
|
||||
jz .not_wrong_place
|
||||
|
||||
cmp al, [guess + bp]
|
||||
jne .moved
|
||||
|
||||
mov [not_moved_error_str.letter], al
|
||||
mov ax, bp
|
||||
add ax, '1'
|
||||
mov [not_moved_error_str.position], al
|
||||
mov si, not_moved_error_str
|
||||
jmp print_error
|
||||
|
||||
.moved:
|
||||
.not_wrong_place:
|
||||
inc bp
|
||||
loop .wrong_places
|
||||
|
||||
.done:
|
||||
|
||||
check_dictionary:
|
||||
|
@ -473,37 +170,11 @@ check_dictionary:
|
|||
loop .dictionary_loop
|
||||
|
||||
check_targets:
|
||||
mov cx, targets_len
|
||||
mov si, targets
|
||||
|
||||
.targets_loop:
|
||||
mov di, dictionary_entry
|
||||
call unpack_target
|
||||
|
||||
xor bp, bp
|
||||
.compare_loop:
|
||||
cmp bp, 5
|
||||
je .match
|
||||
|
||||
mov al, [di + bp]
|
||||
cmp al, [guess + bp]
|
||||
jne .not_match
|
||||
|
||||
inc bp
|
||||
jmp .compare_loop
|
||||
|
||||
.match:
|
||||
jmp word_found
|
||||
|
||||
.not_match:
|
||||
loop .targets_loop
|
||||
; TODO: Check whether word is in the list of target words
|
||||
|
||||
word_not_found:
|
||||
mov si, not_found_str
|
||||
|
||||
print_error:
|
||||
mov ah, 9
|
||||
mov dx, si
|
||||
mov dx, not_found_str
|
||||
int 0x21
|
||||
|
||||
; Wait for a keypress
|
||||
|
@ -519,6 +190,7 @@ print_error:
|
|||
mov dx, erase_word_str
|
||||
int 0x21
|
||||
|
||||
mov si, not_found_str
|
||||
.clear_loop:
|
||||
lodsb
|
||||
cmp al, '$'
|
||||
|
@ -530,7 +202,7 @@ print_error:
|
|||
|
||||
jmp .clear_loop
|
||||
|
||||
.done:
|
||||
.done:
|
||||
|
||||
mov ah, 2
|
||||
mov dl, 13
|
||||
|
@ -558,6 +230,7 @@ find_exact_hits:
|
|||
|
||||
find_wrong_places:
|
||||
; Zero out first
|
||||
mov di, wrong_places
|
||||
mov cx, 5
|
||||
xor al, al
|
||||
rep stosb
|
||||
|
@ -614,15 +287,6 @@ find_wrong_places:
|
|||
.not_found_in_wrong_places:
|
||||
loop .count_wrong_places
|
||||
|
||||
; If not used in target at all, remove from list of possible letters
|
||||
test bh, bh
|
||||
jnz .used_in_target
|
||||
|
||||
xor dh, dh
|
||||
mov di, dx
|
||||
mov byte [alphabet + di - 'a'], ' '
|
||||
|
||||
.used_in_target:
|
||||
; If in target more than in feedback → wrong place
|
||||
cmp bh, bl ; target <= feedback
|
||||
jbe .loop
|
||||
|
@ -663,20 +327,6 @@ print_feedback:
|
|||
|
||||
inc bp
|
||||
loop .loop
|
||||
|
||||
mov ah, 9
|
||||
mov dx, space_dash_space_str
|
||||
int 0x21
|
||||
|
||||
mov cx, 26
|
||||
mov si, alphabet
|
||||
.alphabet_loop:
|
||||
lodsb
|
||||
mov dl, al
|
||||
mov ah, 2
|
||||
int 0x21
|
||||
loop .alphabet_loop
|
||||
|
||||
call newline
|
||||
|
||||
is_finished:
|
||||
|
@ -716,19 +366,9 @@ victory:
|
|||
mov ah, 2
|
||||
int 0x21
|
||||
|
||||
cmp byte [guesses], 1
|
||||
je .singular
|
||||
|
||||
.plural:
|
||||
mov dx, guesses_str
|
||||
jmp .print
|
||||
|
||||
.singular:
|
||||
mov dx, guess_str
|
||||
|
||||
.print:
|
||||
mov ah, 9
|
||||
int 0x21
|
||||
mov dx, guesses_str
|
||||
mov ah, 9
|
||||
int 0x21
|
||||
|
||||
exit:
|
||||
ret
|
||||
|
@ -745,287 +385,7 @@ newline:
|
|||
pop ax
|
||||
ret
|
||||
|
||||
; in:
|
||||
; si = packed target word
|
||||
; di = 5 byte buffer for unpacking the target
|
||||
; out:
|
||||
; si = first byte after the packed target word
|
||||
unpack_target:
|
||||
push ax
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
|
||||
; Target word is stored packed 5 bits per letter into 32 bits
|
||||
; 2221_1111 4333_3322 5555_4444 0000_0005
|
||||
; Load 4333_3322_2221_1111 into dx and extracts first three letters
|
||||
mov dx, [si]
|
||||
add si, 2
|
||||
mov cl, 5
|
||||
%rep 3
|
||||
mov al, dl
|
||||
and al, 0x1f
|
||||
add al, 'a'
|
||||
stosb
|
||||
shr dx, cl
|
||||
%endrep
|
||||
|
||||
; Load 0000_0005_5555_4444 into ax, shift over by one, combine into dx
|
||||
; which has 0000_0000_0000_0004, and extract last two letters
|
||||
mov ax, [si]
|
||||
add si, 2
|
||||
shl ax, 1
|
||||
or dx, ax
|
||||
%rep 2
|
||||
mov al, dl
|
||||
and al, 0x1f
|
||||
add al, 'a'
|
||||
stosb
|
||||
shr dx, cl
|
||||
%endrep
|
||||
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
|
||||
ret
|
||||
|
||||
; out:
|
||||
; dx:ax = result
|
||||
rng:
|
||||
; https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/util.ts#L14
|
||||
|
||||
; rng_t = rng_seed += rng_seed + 0x6d2b79f5
|
||||
mov bp, rng_seed
|
||||
call load32
|
||||
add ax, 0x79f5
|
||||
adc dx, 0x6d2b
|
||||
call store32
|
||||
mov bp, rng_t
|
||||
call store32
|
||||
|
||||
; xorl32 = rng_t
|
||||
mov bp, xorl32
|
||||
call store32
|
||||
|
||||
; xorr32 = rng_t >> 15
|
||||
mov cx, 15
|
||||
call rshift32
|
||||
mov bp, xorr32
|
||||
call store32
|
||||
|
||||
; mull32 = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 15)
|
||||
call xor32
|
||||
mov bp, mull32
|
||||
call store32
|
||||
|
||||
; mulr32 = rng_t | 1
|
||||
mov bp, rng_t
|
||||
call load32
|
||||
or ax, 1
|
||||
mov bp, mulr32
|
||||
call store32
|
||||
|
||||
; rng_t = mull32 * mulr32 = (rng_t ^ (rng_t >> 15)) * (rng_t | 1)
|
||||
call mul32
|
||||
mov bp, rng_t
|
||||
call store32
|
||||
|
||||
; xorl32 = rng_t
|
||||
mov bp, xorl32
|
||||
call store32
|
||||
|
||||
; xorr32 = rng_t >> 7
|
||||
mov cx, 7
|
||||
call rshift32
|
||||
mov bp, xorr32
|
||||
call store32
|
||||
|
||||
; mull32 = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 7)
|
||||
call xor32
|
||||
mov bp, mull32
|
||||
call store32
|
||||
|
||||
; mulr32 = rng_t | 61
|
||||
mov bp, rng_t
|
||||
call load32
|
||||
or ax, 61
|
||||
mov bp, mulr32
|
||||
call store32
|
||||
|
||||
; addl32 = rng_t
|
||||
mov bp, rng_t
|
||||
call load32
|
||||
mov bp, addl32
|
||||
call store32
|
||||
|
||||
; addr32 = mull32 * mulr32 = (rng_t ^ (rng_t >> 7)) * (rng_t | 61)
|
||||
call mul32
|
||||
mov bp, addr32
|
||||
call store32
|
||||
|
||||
; xorl32 = rng_t
|
||||
mov bp, rng_t
|
||||
call load32
|
||||
mov bp, xorl32
|
||||
call store32
|
||||
|
||||
; xorr32 = addl32 + addr32 = rng_t + (rng_t ^ (rng_t >> 7)) * (rng_t | 61)
|
||||
call add32
|
||||
mov bp, xorr32
|
||||
call store32
|
||||
|
||||
; rng_t = xorl32 ^ xorr32 = rng_t ^ (rng_t + (rng_t ^ (rng_t >> 7)) * (rng_t | 61))
|
||||
call xor32
|
||||
mov bp, rng_t
|
||||
call store32
|
||||
|
||||
; xorl32 = rng_t
|
||||
mov bp, xorl32
|
||||
call store32
|
||||
|
||||
; xorr32 = rng_t >> 14
|
||||
mov cx, 14
|
||||
call rshift32
|
||||
mov bp, xorr32
|
||||
call store32
|
||||
|
||||
; result = xorl32 ^ xorr32 = rng_t ^ (rng_t >> 14)
|
||||
call xor32
|
||||
|
||||
ret
|
||||
|
||||
; in:
|
||||
; bp = address of uint32
|
||||
; out:
|
||||
; dx = high 16 bits
|
||||
; ax = low 16 bits
|
||||
load32:
|
||||
mov ax, [bp + 0]
|
||||
mov dx, [bp + 2]
|
||||
ret
|
||||
|
||||
; in:
|
||||
; bp = address of uint32
|
||||
; dx = high 16 bits
|
||||
; ax = low 16 bits
|
||||
store32:
|
||||
mov [bp + 0], ax
|
||||
mov [bp + 2], dx
|
||||
ret
|
||||
|
||||
; in:
|
||||
; dx:ax = uint32 to be shifted
|
||||
; cx = shift amount (must not be 0)
|
||||
; out:
|
||||
; dx:ax = result
|
||||
rshift32:
|
||||
push cx
|
||||
.loop:
|
||||
shr dx, 1
|
||||
rcr ax, 1
|
||||
loop .loop
|
||||
pop cx
|
||||
ret
|
||||
|
||||
; in:
|
||||
; [xorl32], [xorr32] = operands
|
||||
; out:
|
||||
; dx:ax = result
|
||||
xor32:
|
||||
mov ax, [xorl32 + 0]
|
||||
xor ax, [xorr32 + 0]
|
||||
mov dx, [xorl32 + 2]
|
||||
xor dx, [xorr32 + 2]
|
||||
ret
|
||||
|
||||
; in:
|
||||
; [mull32], [mulr32] = operands
|
||||
; out:
|
||||
; dx:ax = result
|
||||
mul32:
|
||||
push bx
|
||||
push cx
|
||||
; c = 1<<16
|
||||
; l = l₁<<16 + l₀
|
||||
; r = r₁<<16 + r₀
|
||||
; l·r = (l₁<<16 + l₀)·(r₁<<16 + r₀)
|
||||
; = l₁<<16·r₁<<16 + l₁<<16·r₀ + l₀·r₁<<16 + l₀·r₀
|
||||
; = l₁·r₁<<32 + l₁·r₀<<16 + l₀·r₁<<16 + l₀·r₀ ||1<<32 = 0 (mod 1<<32)
|
||||
; = l₁·r₀<<16 + l₀·r₁<<16 + l₀·r₀
|
||||
|
||||
; l₀·r₀
|
||||
mov ax, [mull32 + 0]
|
||||
mul word [mulr32 + 0]
|
||||
mov bx, ax
|
||||
mov cx, dx
|
||||
|
||||
; l₀·r₁<<16
|
||||
mov ax, [mull32 + 0]
|
||||
mul word [mulr32 + 2]
|
||||
add cx, ax
|
||||
|
||||
; l₁·r₀<<16
|
||||
mov ax, [mull32 + 2]
|
||||
mul word [mulr32 + 0]
|
||||
add cx, ax
|
||||
|
||||
mov dx, cx
|
||||
mov ax, bx
|
||||
|
||||
pop cx
|
||||
pop bx
|
||||
|
||||
ret
|
||||
|
||||
; in:
|
||||
; [addl32], [addr32] = operands
|
||||
; out:
|
||||
; dx:ax = result
|
||||
add32:
|
||||
mov ax, [addl32 + 0]
|
||||
mov dx, [addl32 + 2]
|
||||
add ax, [addr32 + 0]
|
||||
adc dx, [addr32 + 2]
|
||||
ret
|
||||
|
||||
%ifdef DEBUG
|
||||
hexprint32:
|
||||
xchg ax, dx
|
||||
call hexprint16
|
||||
xchg ax, dx
|
||||
hexprint16:
|
||||
xchg ah, al
|
||||
call hexprint8
|
||||
xchg ah, al
|
||||
hexprint8:
|
||||
%rep 4
|
||||
rol al, 1
|
||||
%endrep
|
||||
call hexprint4
|
||||
%rep 4
|
||||
rol al, 1
|
||||
%endrep
|
||||
hexprint4:
|
||||
push ax
|
||||
and al, 0xf
|
||||
cmp al, 10
|
||||
jb .digit09
|
||||
|
||||
add al, 'a' - 10 - '0'
|
||||
|
||||
.digit09:
|
||||
add al, '0'
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
|
||||
pop ax
|
||||
ret
|
||||
%endif
|
||||
|
||||
section .data
|
||||
alphabet db 'abcdefghijklmnopqrstuvwxyz'
|
||||
target times 5 db 0
|
||||
guess times 5 db 0
|
||||
|
||||
|
@ -1034,90 +394,15 @@ wrong_places times 5 db 0
|
|||
|
||||
guesses db 0
|
||||
|
||||
dictionary_entry times 5 db 0
|
||||
|
||||
hard_mode db 0
|
||||
ultra_hard_mode db 0
|
||||
|
||||
rng_seed dd 0
|
||||
rng_t dd 0
|
||||
|
||||
rng_output dd 0
|
||||
|
||||
xorl32 dd 0
|
||||
xorr32 dd 0
|
||||
mull32 dd 0
|
||||
mulr32 dd 0
|
||||
addl32 dd 0
|
||||
addr32 dd 0
|
||||
|
||||
year dw 0
|
||||
month dw 0
|
||||
day dw 0
|
||||
|
||||
exact_hit_error_str:
|
||||
db ' - letter at position '
|
||||
.position db '#'
|
||||
db " must be '"
|
||||
.letter db '#'
|
||||
db "'$"
|
||||
|
||||
wrong_place_error_str:
|
||||
db " - letter '"
|
||||
.letter db '#'
|
||||
db "' from position "
|
||||
.position db '#'
|
||||
db ' must be reused$'
|
||||
|
||||
not_moved_error_str:
|
||||
db " - letter '"
|
||||
.letter db '#'
|
||||
db "' in position "
|
||||
.position db '#'
|
||||
db ' must be moved$'
|
||||
|
||||
ruled_out_error_str:
|
||||
db " - letter '"
|
||||
.letter db '#'
|
||||
db "' in position "
|
||||
.position db '#'
|
||||
db ' has been ruled out$'
|
||||
dictionary_entry times 4 db 0
|
||||
|
||||
section .rodata
|
||||
|
||||
greeting_str db 'Welcome to hello DOSdl. Press Ctrl+C to exit. Run `dosdl /?` for help.', 13, 10, '$'
|
||||
|
||||
space_dash_space_str db ' - $'
|
||||
not_found_str db ' - word not found$'
|
||||
erase_word_str db ' $'
|
||||
word_was_str db 'The word was: $'
|
||||
correct_in_str db 'Correct in $'
|
||||
guesses_str db ' guesses.$'
|
||||
guess_str db ' guess.$'
|
||||
|
||||
help_str:
|
||||
db 'Usage: dosdl [/h | /u | /l | /?] [seed]', 13, 10
|
||||
db '/h Enable hard mode.', 13, 10
|
||||
db '/u Enable ultra hard mode.', 13, 10
|
||||
db '/l Display license info.', 13, 10
|
||||
db '/? Display this help.', 13, 10
|
||||
db 13, 10
|
||||
db 'Hello DOSdl is a word guessing game. You have six tries to guess the correct', 13, 10
|
||||
db 'English word. After a guess the game displays feedback under each letter:', 13, 10
|
||||
db 13, 10
|
||||
db "' ' Letter is in the correct place.", 13, 10
|
||||
db "'^' Letter is in the wrong place.", 13, 10
|
||||
db "'x' Letter is not in used in the word, or its uses are already covered by the", 13, 10
|
||||
db ' above cases.', 13, 10
|
||||
db 13, 10
|
||||
db 'After the feedback, the game shows a list of letters that have not yet been', 13, 10
|
||||
db 'ruled out.', 13, 10
|
||||
db 13, 10
|
||||
db 'In hard mode all letters marked as being in the correct place must stay fixed', 13, 10
|
||||
db 'and those marked as being in the wrong place must be reused. In ultra hard mode', 13, 10
|
||||
db 'letters marked as being in the wrong place must also be moved and letters that', 13, 10
|
||||
db 'have been ruled out must not be played again.$'
|
||||
|
||||
%include "dictionary.inc"
|
||||
%include "targets.inc"
|
||||
%include "license.inc"
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
srcpath = sys.argv[1]
|
||||
name = sys.argv[2]
|
||||
targetpath = sys.argv[3]
|
||||
|
||||
with open(srcpath, 'r') as f:
|
||||
lines = [line.rstrip() for line in f]
|
||||
|
||||
with open(targetpath, 'w') as f:
|
||||
f.write(f'{name}:\n')
|
||||
for line in lines:
|
||||
encoded = line.encode('cp437')
|
||||
if len(encoded) > 0:
|
||||
f.write(f'\tdb {", ".join(str(char) for char in encoded)}, 13, 10\n')
|
||||
else:
|
||||
f.write('\tdb 13, 10\n')
|
||||
f.write("\tdb '$'\n")
|
22
targets.json
22
targets.json
|
@ -4134,7 +4134,7 @@
|
|||
"casting",
|
||||
"dominion",
|
||||
"angular",
|
||||
"*****",
|
||||
"nancy",
|
||||
"intend",
|
||||
"monarchy",
|
||||
"hurry",
|
||||
|
@ -4386,7 +4386,7 @@
|
|||
"compatible",
|
||||
"obstruction",
|
||||
"upright",
|
||||
"*****",
|
||||
"fatty",
|
||||
"facial",
|
||||
"minimize",
|
||||
"transit",
|
||||
|
@ -5464,12 +5464,12 @@
|
|||
"journalism",
|
||||
"inverse",
|
||||
"bailey",
|
||||
"****",
|
||||
"nous",
|
||||
"pathological",
|
||||
"downtown",
|
||||
"anticipate",
|
||||
"collateral",
|
||||
"****",
|
||||
"quod",
|
||||
"foliage",
|
||||
"locus",
|
||||
"moss",
|
||||
|
@ -5514,8 +5514,8 @@
|
|||
"gambling",
|
||||
"decorative",
|
||||
"sometime",
|
||||
"****",
|
||||
"****",
|
||||
"anal",
|
||||
"holt",
|
||||
"assimilation",
|
||||
"gamma",
|
||||
"contend",
|
||||
|
@ -5740,7 +5740,7 @@
|
|||
"hymn",
|
||||
"slain",
|
||||
"tolerate",
|
||||
"*****",
|
||||
"sperm",
|
||||
"dispose",
|
||||
"steamer",
|
||||
"abandonment",
|
||||
|
@ -5749,7 +5749,7 @@
|
|||
"disagree",
|
||||
"brightness",
|
||||
"suburban",
|
||||
"******",
|
||||
"insane",
|
||||
"superstition",
|
||||
"recollection",
|
||||
"reactive",
|
||||
|
@ -5849,7 +5849,7 @@
|
|||
"cultivate",
|
||||
"spontaneously",
|
||||
"certification",
|
||||
"********",
|
||||
"cortical",
|
||||
"polarization",
|
||||
"everlasting",
|
||||
"clement",
|
||||
|
@ -18322,7 +18322,7 @@
|
|||
"mesentery",
|
||||
"adrenalin",
|
||||
"scrip",
|
||||
"*****",
|
||||
"auxin",
|
||||
"distantly",
|
||||
"vagal",
|
||||
"brag",
|
||||
|
@ -37946,4 +37946,4 @@
|
|||
"fullerene",
|
||||
"doppelganger",
|
||||
"alloxan"
|
||||
]
|
||||
]
|
|
@ -1,28 +0,0 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
# https://github.com/lynn/hello-wordl/blob/7da40c1f067eb1ec157d4c5b7a9bd8257ed39342/src/util.ts#L14
|
||||
def rshift(n, a): return (n & 0xffff_ffff) >> a
|
||||
|
||||
def mulberry32(rng_state):
|
||||
def worker():
|
||||
nonlocal rng_state
|
||||
rng_state += 0x6d2b79f5;
|
||||
t = rng_state
|
||||
t = (t ^ rshift(t, 15)) * (t | 1) & 0xffff_ffff
|
||||
t ^= t + (t ^ rshift(t, 7)) * (t | 61) & 0xffff_ffff
|
||||
return (t ^ (t >> 14))
|
||||
return worker
|
||||
|
||||
with open('targets.json', 'r') as f:
|
||||
targets = json.load(f)
|
||||
|
||||
targets = targets[:targets.index('murky') + 1]
|
||||
targets = [i for i in targets if len(i) == 5]
|
||||
|
||||
rng = mulberry32(int(sys.argv[1]))
|
||||
while True:
|
||||
num = rng()
|
||||
index = num * len(targets) >> 32
|
||||
print(f'{num:08x}', index, targets[index])
|
||||
if targets[index] != '*****': break
|
Loading…
Reference in New Issue