module Z80::Utils::Shuffle::Macros
Z80::Utils::Shuffle
Macros
¶ ↑
for i from 0 to length − 1 do j ← random integer such that 0 ≤ j ≤ i if j ≠ i target[i] ← target[j] target[j] ← source[i]
Shuffle
macros require:
macro_import MathInt
Public Instance Methods
Creates a routine to shuffle an array of bytes.
After the shuffle is performed hl
points to the memory address immediately following the shuffled table.
Modifies: af
, bc
, de
, hl
. Stack depth: 6 bytes or 8 if next_rng
is used.
next_rng
-
An address of a random number generator routine. The routine should return an 8-bit random number in the
accumulator
. Ifnext_rng
isnil
the block of code with the RNG routine is expected instead.
Options:
target
-
An address of the target array as a label, a pointer or
hl
.
length
-
An 8-bit length of an array in the range of 1..256 (0 is 256) as a label, pointer or a register.
source
-
A
source
function. Ifnil
then identity is assumed:source[i] => i
, otherwise it should be an address of a source function routine which expects an argumenti
in the registerc
and MUST PRESERVE registers:hl
andde
. Function is expected to return the source value in theaccumulator
.
# File lib/z80/utils/shuffle.rb, line 44 def shuffle_bytes_source_max256(next_rng=nil, target:hl, length:a, source:nil, &next_rng_blk) unless source.nil? or (address?(source) and !pointer?(source)) raise ArgumentError, "source should be nil or an address" end unless next_rng.nil? or (address?(next_rng) and !pointer?(next_rng)) raise ArgumentError, "next_rng should be an address" end unless next_rng or block_given? raise ArgumentError, "next_rng is not specified and there is no block given" end i = d mask = e j = b t = c isolate do ld hl, target unless target == hl unless length == a if immediate?(length) && (length.to_i & 0xFF).zero? xor a else ld a, length end end ld i|mask, 0 loop0 push af # save length ld a, mask ora i # make mask from i ld mask, a push hl repeat_rand push i|mask if next_rng call next_rng # a = random else ns(&next_rng_blk) end pop i|mask # i|mask anda mask ld j, a # j = random & mask ld a, i sub j # i - j jr C, repeat_rand # j > i pop hl # restore target push i|mask # save i|mask ld t, i # t = i ld16 de, hl # de: hl jr Z, skip_mov # j == i ld j, a # if j ≠ i sub_from j, d, e # de: hl - (i - j) ld a, [de] # target[j] ld [hl], a # target[i] = target[j] skip_mov label if source.nil? ld a, t else call source end ld [de], a # target[j] = source[i] pop i|mask # restore i|mask pop af # length inc hl # target++ inc i cp i jr NZ, loop0 end end