from kandinsky import set_pixel as poly_set_pixel, fill_rect from ion import keydown as poly_test_key, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_EXE as KEY_ENTER, KEY_BACK as KEY_ESC screen_w, screen_h = 320, 222 def wait_key(): while 1: for k in (KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ENTER, KEY_ESC): if poly_test_key(k): return k 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) 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, bg) 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 def input_action(): interactive_actions = {KEY_UP:GO_UP, KEY_RIGHT:GO_RIGHT, KEY_DOWN:GO_DOWN, KEY_LEFT:GO_LEFT, KEY_ENTER:ATTACK, KEY_ESC:QUIT} i = -1 while not i in interactive_actions.keys(): i = wait_key() 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) 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): 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) def tour_ask(plateau, joueurs, evenements): # Demander une action avec input() return demander_action() def tour_path(plateau, joueurs, evenements): global joueur_courant, chemin # Réinitialisation en début de partie for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant = 0 chemin = [] # Si le joueur est arrivé à sa destination, on passe au suivant. # Il arrive que plusieurs joueurs sortent en un seul tour, si ça se produit # on continue de passer au joueur suivant (il en reste forcément un qui # n'est pas sorti sinon la partie serait finie). while joueurs[joueur_courant] == -1: joueur_courant += 1 chemin = [] # Chemin du joueur actuel vers sa sortie if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) # Prochaine étape mouvement = chemin[0] chemin = chemin[1:] return mouvement # Ordre des joueurs à sortir ordre_de_sortie = [0, 2, 1, 3] # Position du joueur qu'on veut sortir dans ordre_de_sortie joueur_courant_id = 0 # Chemin pour le sortir chemin = [] def tour_greedy(plateau, joueurs, evenements): global joueur_courant_id, chemin for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant_id = 0 chemin = [] # Si le joueur est arrivé à sa destination, on passe au suivant while joueurs[ordre_de_sortie[joueur_courant_id]] == -1: joueur_courant_id += 1 chemin = [] joueur_courant = ordre_de_sortie[joueur_courant_id] # Chemin du joueur actuel vers sa sortie if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) # S'il y a des monstres autour mais pas de piège, attaquer monstres_autour = False pieges_autour = False for joueur in joueurs: # On ne compte pas les joueurs qui ont déjà sortis if joueur != -1: if est_un(plateau[joueur-1], MONSTRE) or \ est_un(plateau[joueur+1], MONSTRE) or \ est_un(plateau[joueur-16], MONSTRE) or \ est_un(plateau[joueur+16], MONSTRE): monstres_autour = True if est_un(plateau[joueur-1], PIEGE) or \ est_un(plateau[joueur+1], PIEGE) or \ est_un(plateau[joueur-16], PIEGE) or \ est_un(plateau[joueur+16], PIEGE): pieges_autour = True # if monstres_autour and not pieges_autour: # return ATTAQUER # Prochaine étape mouvement = chemin[0] chemin = chemin[1:] return mouvement print("play_game(tour_ask, blind=False)") print("play_game(tour_path, blind=True)") print("play_game(tour_greedy, blind=True)")