#!/usr/bin/python # -*- coding: utf-8 -*- ''' Help the user achieve a high score in a real game of 2048 by using a move searcher. ''' from __future__ import print_function import time from ailib import ailib, to_c_board, from_c_index # Enable multithreading? MULTITHREAD = True def print_board(m): for row in m: for c in row: print('%8d' % c, end=' ') print() def to_val(m): return [[from_c_index(c) for c in row] for row in m] def _to_score(c): if c <= 1: return 0 return (c-1) * (2**c) def to_score(m): return [[_to_score(c) for c in row] for row in m] if MULTITHREAD: from multiprocessing.pool import ThreadPool pool = ThreadPool(4) def score_toplevel_move(args): return ailib.score_toplevel_move(*args) def find_best_move(m): board = to_c_board(m) print_board(to_val(m)) scores = pool.map(score_toplevel_move, [(board, move) for move in range(4)]) bestmove, bestscore = max(enumerate(scores), key=lambda x:x[1]) if bestscore == 0: return -1 return bestmove else: def find_best_move(m): board = to_c_board(m) return ailib.find_best_move(board) def movename(move): return ['up', 'down', 'left', 'right'][move] def play_game(gamectrl): moveno = 0 start = time.time() while 1: state = gamectrl.get_status() if state == 'ended': break elif state == 'won': time.sleep(0.75) gamectrl.continue_game() moveno += 1 board = gamectrl.get_board() move = find_best_move(board) if move < 0: break print("%010.6f: Score %d, Move %d: %s" % (time.time() - start, gamectrl.get_score(), moveno, movename(move))) gamectrl.execute_move(move) score = gamectrl.get_score() board = gamectrl.get_board() maxval = max(max(row) for row in to_val(board)) print("Game over. Final score %d; highest tile %d." % (score, maxval)) def parse_args(argv): import argparse parser = argparse.ArgumentParser(description="Use the AI to play 2048 via browser control") parser.add_argument('-p', '--port', help="Port number to control on (default: 32000 for Firefox, 9222 for Chrome)", type=int) parser.add_argument('-b', '--browser', help="Browser you're using. Only Firefox with remote debugging, Firefox with the Remote Control extension (deprecated), and Chrome with remote debugging, are supported right now.", default='firefox', choices=('firefox', 'firefox-rc', 'chrome', 'manual')) parser.add_argument('-k', '--ctrlmode', help="Control mode to use. If the browser control doesn't seem to work, try changing this.", default='hybrid', choices=('keyboard', 'fast', 'hybrid', 'play2048co')) return parser.parse_args(argv) def main(argv): args = parse_args(argv) if args.browser == 'firefox': from ffctrl import FirefoxDebuggerControl if args.port is None: args.port = 32000 ctrl = FirefoxDebuggerControl(args.port) elif args.browser == 'firefox-rc': from ffctrl import FirefoxRemoteControl if args.port is None: args.port = 32000 ctrl = FirefoxRemoteControl(args.port) elif args.browser == 'chrome': from chromectrl import ChromeDebuggerControl if args.port is None: args.port = 9222 ctrl = ChromeDebuggerControl(args.port) if args.browser == 'manual': from manualctrl import ManualControl gamectrl = ManualControl() elif args.ctrlmode == 'keyboard': from gamectrl import Keyboard2048Control gamectrl = Keyboard2048Control(ctrl) elif args.ctrlmode == 'fast': from gamectrl import Fast2048Control gamectrl = Fast2048Control(ctrl) elif args.ctrlmode == 'hybrid': from gamectrl import Hybrid2048Control gamectrl = Hybrid2048Control(ctrl) elif args.ctrlmode == 'play2048co': from gamectrl import Play2048CoControl gamectrl = Play2048CoControl(ctrl) if gamectrl.get_status() == 'ended': gamectrl.restart_game() play_game(gamectrl) if __name__ == '__main__': import sys exit(main(sys.argv[1:]))