Skip to content

Instantly share code, notes, and snippets.

@taotao54321
Last active August 6, 2018 23:43
Show Gist options
  • Save taotao54321/37509aaa72422be3294107218bc4340b to your computer and use it in GitHub Desktop.
Save taotao54321/37509aaa72422be3294107218bc4340b to your computer and use it in GitHub Desktop.
NES Dr.Mario virus placement simulator
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""ドクターマリオ (FC) 初期配置シミュレータ
使い方:
$ virus_place.py <level> <rand_idx>
level には 0..20 の値を指定します。
rand_idx は乱数インデックス(0始まり)です。TASでリセットを併用して最速
で開始した場合129になります。
"""
import sys
def BIT(x, i):
return (x>>i) & 1
def rand_update(r):
bit = BIT(r,1) ^ BIT(r,9)
r >>= 1
r |= bit << 15
return r
def rand_at(n):
r = 0x8988
for _ in range(n):
r = rand_update(r)
return r
def virus_put(level, r, c, field):
H_MAX = (
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 10, 10, 11, 11, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12,
)
COLORS = (
0, 1, 2, 2, 1, 0, 0, 1,
2, 2, 1, 0, 0, 1, 2, 1,
)
MASKS = ( 1, 2, 4, 0 )
while True:
r = rand_update(r)
h = (r>>8) & 0xF
if h <= H_MAX[level]: break
x = (r&0xFF) & 7
y = 15 - h
off = 8*y + x
color = c & 3
if color == 3:
r = rand_update(r)
color = COLORS[(r&0xFF) & 0xF]
#print(x, y, off, color)
while True:
while field[off] != 0xFF:
off += 1
if off >= 128: return r, False
mask = 0
# 2段上のマス
# 高さ制限があるので境界チェック不要
mask |= MASKS[field[off-16] & 3]
# 2段下のマス
if off < 112:
mask |= MASKS[field[off+16] & 3]
# 2つ左のマス
if off % 8 >= 2:
mask |= MASKS[field[off-2] & 3]
# 2つ右のマス
if off % 8 < 6:
mask |= MASKS[field[off+2] & 3]
if mask == 7:
off += 1
if off >= 128: return r, False
continue
while MASKS[color] & mask != 0:
color -= 1
if color < 0: color = 2
field[off] = 0xD0 | color
return r, True
def virus_place(level, r):
field = [0xFF] * 128
count = 4 * (level+1)
while count > 0:
r, success = virus_put(level, r, count, field)
if success: count -= 1
return field
def print_field(field):
CELL_CHR = {
0xD0 : "Y",
0xD1 : "R",
0xD2 : "B",
0xFF : ".",
}
for y in range(16):
for x in range(8):
off = 8*y + x
print(CELL_CHR[field[off]], end="")
print()
def usage():
print("Usage: virus_place <level> <rand_idx>")
sys.exit(1)
def main():
if len(sys.argv) != 3: usage()
level = int(sys.argv[1])
rand_idx = int(sys.argv[2])
assert 0 <= level <= 20
assert 0 <= rand_idx <= 32766
r = rand_at(rand_idx)
#print(f"rand: 0x{r:04X}")
field = virus_place(level, r)
print_field(field)
if __name__ == "__main__": main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment