tipc21/synchrod/synchrod.py

296 lines
9.3 KiB
Python

from polycal4 import get_infos, KEY_NONE, KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_ENTER, KEY_ESC
screen_w, screen_h, poly_has_color, poly_set_pixel, draw_line, fill_rect, show_screen, init_clean_screen, wait_key, wait_release, esc_key, HAS_KEYS, poly_pause, sleep = get_infos(["w","h","hc","sp","dl","fr","sh","cli","wk","wr","ek","hk","p","s"], 256, 128, 4)
get_infos = None
SCALE = min(screen_w // 128, screen_h // 64)
YELLOW, RED, BLUE, GREEN, ALL = 0, 1, 2, 3, 4
VOID, WALL, SPIKES, MONSTER, TRAP, EXIT = 100, 101, 102, 107, 112, 117
GO_UP, GO_RIGHT, GO_DOWN, GO_LEFT, ATTACK, QUIT = 10, 11, 12, 13, 14, 15
NEW_GAME, TRAP_APPEARED, SPIKES_APPEARED = 20, 21, 22
JAUNE, ROUGE, BLEU, VERT, TOUS = 0, 1, 2, 3, 4
VIDE, MUR, PICS, MONSTRE, PIEGE, SORTIE = 100, 101, 102, 107, 112, 117
ALLER_HAUT, ALLER_DROITE, ALLER_BAS, ALLER_GAUCHE, ATTAQUER, QUITTER = 10, 11, 12, 13, 14, 15
NOUVELLE_PARTIE, PIEGE_APPARU, PICS_APPARUS = 20, 21, 22
def ri(rs,a,b):
rs[0] = (rs[0] * 214013 + 2531011) % 4294967296
r = (rs[0] // 65536) & 0x7fff
return r % (b-a) + a
### Rendering
def px(x, y, c):
for sx in range(SCALE):
for sy in range(SCALE):
poly_set_pixel(x*SCALE+sx, y*SCALE+sy, c)
if poly_has_color:
colors = [(77,71,63), (210,217,217), (241,233,103), (234,96,88), (97,156,236), (111,226,126), (178,126,206)]
s=0x002a2a55005454aa00
m=0x00005ae7bd18000000
t=0x00182c4a5234180000
e=0xf080e0c080e0c0f000
f=0x0f0107030107030f00
p=0x386565396dd7ff7d00
tiles = [0,0xff818181818181ff01,s+2,s+3,s+4,s+5,s+6,m+2,m+3,m+4,m+5,m+6,t+2,t+3,t+4,t+5,t+6,f+2,e+3,f+4,e+5]
sprites = [p+2,p+3,p+4,p+5]
def render_image(tile, x0, y0):
fg, bg = colors[tile & 0xff], colors[0]
tile >>= 8
if tile:
for y in range(8):
for x in range(8):
px(x0*8+7-x, y0*8+7-y, fg if tile & 1 else bg)
tile >>= 1
else:
fill_rect(x0*8*SCALE, y0*8*SCALE, 8*SCALE, 8*SCALE, colors[0])
else:
colors = [(255,255,255),(0,0,0)]
p1=0x040a00<<40
p2=0x040a06<<40
p3=0x040a0e<<40
p4=0x040e04<<40
s=0x5454aa00
m=0x00005ae7bd18
t=0x1028542810
e=0xe080e0c080e0c0f0
tiles = [0,0xff818181818181ff,s+p1,s+p2,s+p3,s+p4,(s<<31)+s,m+p1,m+p2,m+p3,m+p4,m<<16,t+p1,t+p2,t+p3,t+p4,t<<8,0x275107030107030f,e+p2,0x275177030107030f,e+p4]
sprites = [0x386565396dd7ff7d,0x386565396dd7e77d,0x386565396dd7c77d,0x386565396dc7ef7d]
def render_image(tile, x0, y0):
if tile:
for y in range(8):
for x in range(8):
px(x0*8+7-x, y0*8+7-y, colors[tile & 1])
tile >>= 1
else:
fill_rect(x0*8*SCALE, y0*8*SCALE, 8*SCALE, 8*SCALE, colors[0])
def render_game(board, players, old_players, update):
for xy in update:
if xy == -1:
for y in range(8):
for x in range(16):
render_image(tiles[board[16*y+x]-VOID], x, y)
else:
render_image(tiles[board[xy]-VOID], xy%16, xy//16)
for xy in old_players:
render_image(tiles[board[xy]-VOID], xy%16, xy//16)
for i in range(4):
render_image(sprites[i], players[i]%16, players[i]//16)
### API for submissions
if HAS_KEYS:
interactive_actions = {KEY_UP:GO_UP, KEY_RIGHT:GO_RIGHT, KEY_DOWN:GO_DOWN, KEY_LEFT:GO_LEFT, KEY_ENTER:ATTACK, KEY_ESC:QUIT}
else:
interactive_actions = {"8":GO_UP, "6":GO_RIGHT, "2":GO_DOWN, "4":GO_LEFT, "5":ATTACK, "9":QUIT}
def input_action():
if HAS_KEYS:
wait_release()
i = KEY_NONE
while not i in interactive_actions.keys():
i = wait_key()
else:
print("Déplacement:")
print(" 8")
print(" 4 6")
print(" 2")
print("Attaquer: 5")
print("Voir plateau: 0")
print("Quitter: 9")
i = input("Que faire ?> ")
return interactive_actions.get(i)
def is_a(obj, kind):
if kind == VOID or kind == WALL:
return obj == kind
return kind <= obj <= kind + 4
def affects(obj, player):
return (is_a(obj, SPIKES) or is_a(obj, MONSTER) or is_a(obj, TRAP)) and obj != SPIKES+player and obj != MONSTER+player and obj != TRAP+player
pathfind_d = [-16, +16, -1, +1, GO_UP, GO_DOWN, GO_LEFT, GO_RIGHT]
def pathfind(board, start, end):
n = len(board)
parent = [-1]*n
directions = [-1]*n
queue = [start]
parent[start] = start
cell = -1
while queue:
cell = queue.pop(0)
if cell == end:
break
for i in range(4):
d = cell+pathfind_d[i]
if board[d] != WALL and parent[d] < 0:
parent[d] = cell
directions[d] = pathfind_d[i+4]
queue.append(d)
if cell == end:
path = []
while cell != start:
path = [directions[cell]] + path
cell = parent[cell]
return path
demander_action, est_un, affecte, calculer_chemin = input_action, is_a, affects, pathfind
### Board generator
def ufc():
return [i for i in range(128)]
def ufr(uf,i):
if uf[i] == i:
return i
rep = ufr(uf, uf[i])
uf[i] = rep
return rep
def ufm(uf,i,j):
uf[ufr(uf,i)]=ufr(uf,j)
def gb(rs):
board = [WALL] * 128
pp = [17,30,97,110]
pe = [47,80,95,32]
for i in range(4):
board[pp[i]] = VOID
board[pe[i]] = EXIT+i
uf = [i for i in range(128)]
while any(ufr(uf,pp[i]) != ufr(uf,pe[i]) for i in range(4)):
i = ri(rs,1,7)*16 + ri(rs,1,15)
if board[i] == WALL and any(board[n] != VOID for n in (i-16,i+16,i-1,i+1)):
board[i] = VOID
for n in (i-16,i+16,i-1,i+1):
if board[n] != WALL:
ufm(uf,i,n)
for i in range(128):
if board[i] == VOID and ri(rs,0,16)<2:
board[i]=[MONSTER, MONSTER, SPIKES, TRAP][ri(rs,0,4)]+ri(rs,0,5)
return board
### Game logic
def play_board(rs, turn_function, blind):
board = gb(rs)
players = [17,30,97,110]
old_players = []
ev = [(-1,-1,NEW_GAME,-1)]
update = [-1]
turns = 0
penalty = 0
while True:
if not blind:
render_game(board, players, old_players, update)
show_screen()
if not HAS_KEYS:
poly_pause()
action = turn_function(board, players, ev)
ev = []
update = []
old_players = players[:]
if action is None:
continue
if action == QUIT:
return None
turns += 1
traps_activated = 0
for p in range(4):
coord = players[p]
if coord < 0:
continue
if action == ATTACK:
for direction in range(4):
dx = (direction == 1) - (direction == 3)
dy = (direction == 2) - (direction == 0)
i = coord + dx + 16*dy
dest = board[i]
if is_a(dest, MONSTER):
board[i] = VOID
update.append(i)
elif is_a(dest, TRAP) and affects(dest, p):
traps_activated += 1
board[i] = VOID
update.append(i)
else:
dx = (action == GO_RIGHT) - (action == GO_LEFT)
dy = (action == GO_DOWN) - (action == GO_UP)
i = coord + dx + 16*dy
dest = board[i]
if dest == EXIT+p:
players[p] = -1
continue
if dest == WALL or is_a(dest, EXIT):
continue
players[p] = i
if not affects(dest, p):
continue
if is_a(dest, SPIKES):
penalty += 10
elif is_a(dest, MONSTER):
penalty += 10
board[i] = VOID
update.append(i)
elif is_a(dest, TRAP):
traps_activated += 1
board[i] = VOID
update.append(i)
while traps_activated > 0:
effect = ri(rs,0,3)
if effect == 0:
penalty += 10
x = ri(rs,1,15)
y = ri(rs,1,7)
if board[y*16+x] == VOID and y*16+x not in players:
board[y*16+x] = (TRAP if effect==1 else SPIKES) + ri(rs,0,4)
ev.append((x, y, TRAP_APPEARED if effect==1 else SPIKES_APPEARED, p))
update.append(y*16+x)
traps_activated -= 1
if all(p < 0 for p in players):
score = 150 - penalty - turns
print("Bravo! "+str(turns)+"T "+str(penalty)+"D -> "+str(score))
return score
def play_game(turn_function, blind=False, seed=0xc0ffee, maxgames=100):
if not blind:
init_clean_screen()
rs = [seed]
games = 0
score = 0
while games != maxgames:
print("#"+str(games)+": "+str(rs[0]))
board_score = play_board(rs, turn_function, blind)
if board_score is None:
print("")
print("Quit!")
return
else:
score += max(board_score, 0)
games += 1
print("Games solved:", games)
print("Score:", score)
if __name__ == "__main__":
def turn(board, player, ev):
return input_action()
play_game(turn)