Skip to content

Instantly share code, notes, and snippets.

@turtleDev
Last active August 19, 2016 11:41
Show Gist options
  • Select an option

  • Save turtleDev/3e1096c987989b6ea81d8e346ed8b0db to your computer and use it in GitHub Desktop.

Select an option

Save turtleDev/3e1096c987989b6ea81d8e346ed8b0db to your computer and use it in GitHub Desktop.

Revisions

  1. turtleDev revised this gist Aug 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 2kb.py
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4
    TARGET = 512
    TARGET = 2048


    def generate_board():
  2. turtleDev revised this gist Aug 19, 2016. 1 changed file with 94 additions and 8 deletions.
    102 changes: 94 additions & 8 deletions 2kb.py
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,11 @@
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    # License: public domain
    # Author: Saravjeet 'Aman' Singh <[email protected]>

    import json
    import argparse
    import time
    import sys
    import re
    @@ -13,11 +16,20 @@
    print >> sys.stderr, "unable to import curses, logging is diabled"

    # stub interface to curses, in case it is unavailable.
    # notice the lack of self parameter.
    class _dumdum(object):
    def __getattribute__(self, *args, **kwargs):
    def dummy(*args, **kwargs):
    pass
    return dummy

    def dummy(*args, **kwargs):
    pass

    def wrapper(func, *args, **kwargs):
    return func(_dumdum(), *args, **kwargs)

    def __getattribute__(self, attr):
    try:
    return _dumdum.__dict__[attr]
    except KeyError:
    return _dumdum.__dict__['dummy']

    curses = _dumdum()

    @@ -31,7 +43,7 @@ class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4
    TARGET = 2048
    TARGET = 512


    def generate_board():
    @@ -70,7 +82,7 @@ def board_state(page):

    board = generate_board()
    for x, y, val in positions:
    board[x][y] = val
    board[y][x] = val

    return board

    @@ -98,21 +110,47 @@ def game_won(board):
    ''' determines if the winning condition has been reached '''
    return board_has(board, config.TARGET)

    def generate_dump(page, hist):

    send = page.find_element_by_tag_name('body').send_keys
    n = len(hist)
    result = []
    for i in range(n, 0, -1):
    state = board_state(page)
    send(config.UNDO)
    result.append({
    'step': i,
    'state': state,
    'move': hist.pop()})
    result.reverse()
    return result


    def find(stdscr, page):

    moves = [Keys.ARROW_UP, Keys.ARROW_RIGHT,
    Keys.ARROW_DOWN, Keys.ARROW_LEFT]

    move_map = {
    Keys.ARROW_UP: 'up',
    Keys.ARROW_RIGHT: 'right',
    Keys.ARROW_DOWN: 'down',
    Keys.ARROW_LEFT: 'left'}

    send = page.find_element_by_tag_name('body').send_keys

    hist = []
    stack = []
    stack.append(list(moves))
    ops = 0
    start_t = time.time()

    while len(stack) != 0:

    if start_t - time.time() > 30:
    ops = 0
    start_t = time.time()

    ops += 1
    rate = 'rate: {} ops/second'.format(
    ops / (time.time() - start_t))
    @@ -129,28 +167,76 @@ def find(stdscr, page):
    current_frame = stack.pop()
    if len(current_frame) == 0:
    send(config.UNDO)
    hist.pop()
    continue

    move = current_frame.pop()

    # push the rest of the moves back onto stack
    stack.append(current_frame)

    # add th current move to the history
    hist.append(move_map[move])

    old_board = board_state(page)
    send(move)
    new_board = board_state(page)

    if game_won(new_board):
    break

    stats = (
    "stats: \n"
    " stack depth: {}\n"
    " operation count: {}\n"
    .format(len(stack), ops))

    return stats, hist

    if board_changed(old_board, new_board):
    stack.append(list(moves))
    else:
    hist.pop()



    def main():
    parser = argparse.ArgumentParser(
    description='this little program finds the solution '
    'to the 2048 puzzle using a backtracking '
    'algorithm. You can ask it to dump the '
    'solution once it is done '
    'note that this program assumes we\'re using '
    'the original version with some kind of mod for '
    'the undo')
    parser.add_argument('-g', '--game-url', type=str, metavar='uri',
    help='the game url')
    parser.add_argument('-t', '--target', type=int, metavar='n',
    help='the target tile')
    parser.add_argument('-o', '--out', metavar='file',
    help='save the result/solution to a file')

    args = parser.parse_args()
    if args.target:
    config.TARGET = args.target

    if args.game_url:
    config.GAME_URL = args.game_url

    page = selenium.webdriver.Firefox()
    page.get(config.GAME_URL)
    curses.wrapper(find, page)

    try:
    stats, hist = curses.wrapper(find, page)

    print stats

    if args.out:
    dump = generate_dump(page, hist)
    json.dump(dump, open(args.out, 'w'))

    except KeyboardInterrupt:
    print "exiting"


    if __name__ == '__main__':
    main()
  3. turtleDev revised this gist Aug 18, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 2kb.py
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4
    TARGET = 128
    TARGET = 2048


    def generate_board():
  4. turtleDev revised this gist Aug 14, 2016. 1 changed file with 3 additions and 9 deletions.
    12 changes: 3 additions & 9 deletions 2kb.py
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4
    TARGET = 2048
    TARGET = 128


    def generate_board():
    @@ -87,6 +87,7 @@ def compare(result, current):

    return reduce(compare, composite, False)


    def board_has(board, value):
    # convert the 2d matrix into a 1d matrix
    all_values = [v for val in board for v in val]
    @@ -103,12 +104,6 @@ def find(stdscr, page):
    moves = [Keys.ARROW_UP, Keys.ARROW_RIGHT,
    Keys.ARROW_DOWN, Keys.ARROW_LEFT]

    move_map = {
    Keys.ARROW_UP: 'up',
    Keys.ARROW_RIGHT: 'right',
    Keys.ARROW_DOWN: 'down',
    Keys.ARROW_LEFT: 'left'}

    send = page.find_element_by_tag_name('body').send_keys

    stack = []
    @@ -120,7 +115,7 @@ def find(stdscr, page):

    ops += 1
    rate = 'rate: {} ops/second'.format(
    ops / ( time.time() - start_t ))
    ops / (time.time() - start_t))

    stdscr.addstr(0, 0, 'running ...')
    stdscr.addstr(1, 0, '<ctrl-c to exit>')
    @@ -145,7 +140,6 @@ def find(stdscr, page):
    send(move)
    new_board = board_state(page)


    if game_won(new_board):
    break

  5. turtleDev revised this gist Aug 14, 2016. 1 changed file with 13 additions and 10 deletions.
    23 changes: 13 additions & 10 deletions 2kb.py
    Original file line number Diff line number Diff line change
    @@ -19,7 +19,7 @@ def dummy(*args, **kwargs):
    pass
    return dummy

    curses = _dumdum
    curses = _dumdum()

    import selenium
    import selenium.webdriver
    @@ -31,6 +31,7 @@ class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4
    TARGET = 2048


    def generate_board():
    @@ -86,10 +87,15 @@ def compare(result, current):

    return reduce(compare, composite, False)

    def board_has(board, value):
    # convert the 2d matrix into a 1d matrix
    all_values = [v for val in board for v in val]
    return reduce(lambda result, v: result or v == value, all_values, False)

    def game_won():
    ''' stub '''
    return False

    def game_won(board):
    ''' determines if the winning condition has been reached '''
    return board_has(board, config.TARGET)


    def find(stdscr, page):
    @@ -140,8 +146,8 @@ def find(stdscr, page):
    new_board = board_state(page)


    if game_won():
    sys.exit(0)
    if game_won(new_board):
    break

    if board_changed(old_board, new_board):
    stack.append(list(moves))
    @@ -150,10 +156,7 @@ def find(stdscr, page):
    def main():
    page = selenium.webdriver.Firefox()
    page.get(config.GAME_URL)
    try:
    curses.wrapper(find, page)
    except KeyboardInterrupt:
    print "bye"
    curses.wrapper(find, page)

    if __name__ == '__main__':
    main()
  6. turtleDev created this gist Aug 14, 2016.
    159 changes: 159 additions & 0 deletions 2kb.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,159 @@
    # -*- coding: utf-8 -*-

    # License: public domain
    # Author: Saravjeet 'Aman' Singh <[email protected]>

    import time
    import sys
    import re

    try:
    import curses
    except ImportError:
    print >> sys.stderr, "unable to import curses, logging is diabled"

    # stub interface to curses, in case it is unavailable.
    class _dumdum(object):
    def __getattribute__(self, *args, **kwargs):
    def dummy(*args, **kwargs):
    pass
    return dummy

    curses = _dumdum

    import selenium
    import selenium.webdriver
    from selenium.webdriver.common.keys import Keys
    from selenium.common.exceptions import StaleElementReferenceException


    class config:
    GAME_URL = 'https://quaxio.com/2048/'
    UNDO = 'z'
    TILES_PER_AXIS = 4


    def generate_board():
    '''generate an empty board'''
    outer = []
    for i in range(config.TILES_PER_AXIS):
    inner = []
    for j in range(config.TILES_PER_AXIS):
    inner.append(0)
    outer.append(inner)
    return outer


    def board_state(page):
    '''get the current board's status'''
    while True:
    # savage
    try:
    elements = page.find_elements_by_class_name('tile')
    positions = [el.get_attribute('class') for el in elements]
    break
    except StaleElementReferenceException:
    continue

    x = re.compile('tile-position-(\d+)-')
    y = re.compile('tile-position-\d+-(\d+)')
    v = re.compile('tile-(\d+)')

    positions = zip(
    # make the coordinates 0-indexed
    map(lambda v: int(v) - 1, [x.search(p).groups()[0]
    for p in positions]),
    map(lambda v: int(v) - 1, [y.search(p).groups()[0]
    for p in positions]),
    map(int, [v.search(p).groups()[0] for p in positions]))

    board = generate_board()
    for x, y, val in positions:
    board[x][y] = val

    return board


    def board_changed(this, that):
    '''determine if there is a difference between two boards'''
    composite = zip(this, that)

    def compare(result, current):
    for i in range(len(current[0])):
    if current[0][i] != current[1][i]:
    return True
    return result

    return reduce(compare, composite, False)


    def game_won():
    ''' stub '''
    return False


    def find(stdscr, page):

    moves = [Keys.ARROW_UP, Keys.ARROW_RIGHT,
    Keys.ARROW_DOWN, Keys.ARROW_LEFT]

    move_map = {
    Keys.ARROW_UP: 'up',
    Keys.ARROW_RIGHT: 'right',
    Keys.ARROW_DOWN: 'down',
    Keys.ARROW_LEFT: 'left'}

    send = page.find_element_by_tag_name('body').send_keys

    stack = []
    stack.append(list(moves))
    ops = 0
    start_t = time.time()

    while len(stack) != 0:

    ops += 1
    rate = 'rate: {} ops/second'.format(
    ops / ( time.time() - start_t ))

    stdscr.addstr(0, 0, 'running ...')
    stdscr.addstr(1, 0, '<ctrl-c to exit>')
    stdscr.addstr(2, 0, 'stats: ')
    stdscr.addstr(3, 4, 'stack depth: {}'.format(len(stack)))
    stdscr.addstr(4, 4, 'operation count: {}'.format(ops))
    stdscr.addstr(5, 4, rate)
    stdscr.refresh()

    # get the current frame
    current_frame = stack.pop()
    if len(current_frame) == 0:
    send(config.UNDO)
    continue

    move = current_frame.pop()

    # push the rest of the moves back onto stack
    stack.append(current_frame)

    old_board = board_state(page)
    send(move)
    new_board = board_state(page)


    if game_won():
    sys.exit(0)

    if board_changed(old_board, new_board):
    stack.append(list(moves))


    def main():
    page = selenium.webdriver.Firefox()
    page.get(config.GAME_URL)
    try:
    curses.wrapper(find, page)
    except KeyboardInterrupt:
    print "bye"

    if __name__ == '__main__':
    main()