Exemplo n.º 1
0
def purchase(item, image=None, budget=None, quantity=1, **kwargs):
    # Buys a quantity of items from user shops, sticking within a budget.
    # Returns actual amount spent, or None if not successful.
    market = next(iter(item_db.get_market(item, image, **kwargs).values()))

    true_cost = 0
    qty_left = quantity
    buy_nps = []
    for price, stock, link in market:
        np2 = NeoPage()
        np2.get(link)
        buy_link, image, item, in_stock, cost = shop_item_re.search(np2.content).groups()
        in_stock = util.amt(in_stock)
        cost = util.amt(cost)
        if cost <= price:
            to_buy = min(in_stock, qty_left)
            true_cost += cost * to_buy
            qty_left -= to_buy
            buy_nps.append((np2, buy_link, to_buy))
            if qty_left <= 0:
                break

    if budget != None and true_cost > budget:
        return None
    
    ensure_np(true_cost)
    for np2, buy_link, to_buy in buy_nps:
        referer = np2.referer
        for _ in range(to_buy):
            print(f'Buying {item} from {buy_link}')
            np2.set_referer(referer)
            np2.get(f'/{buy_link}')

    return true_cost
Exemplo n.º 2
0
def clean_shop_till():
    log = open(SALES_LOG_FILE, 'a')
    np = NeoPage()

    np.get('/market.phtml', 'type=sales')
    referer = np.referer
    if 'Nobody has bought anything' in np.content:
        print('No new sales.')
    else:
        tbl = re.search(
            '''<table align=center width=530 cellpadding=3 cellspacing=0>(.*?)</table>''',
            np.content)[1]
        rows = util.table_to_tuples(tbl)
        total_sales = 0
        for date, item, buyer, price in rows[1:-1]:
            price = util.amt(price)
            print(f'{date}: {buyer} bought {item} for {price} NP')
            log.write(f'{date},{buyer},{item},{price}\n')
            total_sales += price

        print(f'Total sales cleared: {total_sales} NP')
        print(f'Saved to {SALES_LOG_FILE}. Clearing history.')
        np.post('/market.phtml', 'type=sales', 'clearhistory=true')

    np.set_referer(referer)
    np.get('/market.phtml', 'type=till')
    amt = util.amt(
        re.search(r'''You currently have <b>(.*?)</b> in your till.''',
                  np.content)[1])
    if amt:
        print(f'Withdrawing {amt} NP from shop till.')
        np.post('/process_market.phtml', 'type=withdraw', f'amount={amt}')
    else:
        print(f'Shop till is empty.')
Exemplo n.º 3
0
def clean_shop_till():
    log = open(SALES_LOG_FILE, 'a')
    np = NeoPage()

    np.get('/market.phtml', 'type=sales')
    referer = np.referer
    if 'Nobody has bought anything' in np.content:
        print('No new sales.')
    else:
        tbl = re.search('''<table align=center width=530 cellpadding=3 cellspacing=0>(.*?)</table>''', np.content)[1]
        rows = util.table_to_tuples(tbl)
        total_sales = 0
        for date, item, buyer, price in rows[1:-1]:
            price = util.amt(price)
            print(f'{date}: {buyer} bought {item} for {price} NP')
            log.write(f'{date},{buyer},{item},{price}\n')
            total_sales += price

        print(f'Total sales cleared: {total_sales} NP')
        print(f'Saved to {SALES_LOG_FILE}. Clearing history.')
        np.post('/market.phtml', 'type=sales', 'clearhistory=true')

    np.set_referer(referer)
    np.get('/market.phtml', 'type=till')
    amt = util.amt(re.search(r'''You currently have <b>(.*?)</b> in your till.''', np.content)[1])
    if amt:
        print(f'Withdrawing {amt} NP from shop till.')
        np.post('/process_market.phtml', 'type=withdraw', f'amount={amt}')
    else:
        print(f'Shop till is empty.')
Exemplo n.º 4
0
def purchase(item, image=None, budget=None, quantity=1, **kwargs):
    # Buys a quantity of items from user shops, sticking within a budget.
    # Returns actual amount spent, or None if not successful.
    market = next(iter(item_db.get_market(item, image, **kwargs).values()))

    true_cost = 0
    qty_left = quantity
    buy_nps = []
    for price, stock, link in market:
        np2 = NeoPage()
        np2.get(link)
        buy_link, image, item, in_stock, cost = shop_item_re.search(
            np2.content).groups()
        in_stock = util.amt(in_stock)
        cost = util.amt(cost)
        if cost <= price:
            to_buy = min(in_stock, qty_left)
            true_cost += cost * to_buy
            qty_left -= to_buy
            buy_nps.append((np2, buy_link, to_buy))
            if qty_left <= 0:
                break

    if budget != None and true_cost > budget:
        return None

    ensure_np(true_cost)
    for np2, buy_link, to_buy in buy_nps:
        referer = np2.referer
        for _ in range(to_buy):
            print(f'Buying {item} from {buy_link}')
            np2.set_referer(referer)
            np2.get(f'/{buy_link}')

    return true_cost
Exemplo n.º 5
0
def faerieland_jobs(jobs_to_do):
    np = NeoPage()
    np.get(path, 'type=jobs', 'voucher=basic')
    start = 0
    jobs_by_profit = []
    try:
        while jobs_to_do > 0:
            jobs = job_re.findall(np.content)
            has_more_pages = bool(re.search('<A HREF="employment.phtml.*?">Next 10</A>', np.content))
            for image, job_link, count, name, prize in jobs:
                count = int(count)
                prize = util.amt(prize)
                revenue = prize * 1.25
                if revenue < MIN_PROFIT:
                    print(f'Skipping {name} (can only make {revenue})')
                    continue

                price = item_db.get_price(name, image)
                profit = revenue - count * price
                print(f'Can profit by about {profit} NP: Buy {count}x {name} ({price} NP each), turn in for {revenue}')
                bisect.insort(jobs_by_profit, (profit, name, count, job_link))
                if profit < MIN_PROFIT:
                    continue
                print('Taking the job!')
                
                true_cost = inventory.purchase(name, image=image, budget=revenue - MIN_PROFIT, quantity=count)
                if not true_cost:
                    print(f'Failed to acquire all the items within budget')
                    continue

                # Do the job!
                np.get(f'/faerieland/employ/{job_link}')
                if 'Good job! You got all the items' in np.content:
                    prize = re.search(r'You have been paid <b>(.*?) Neopoints</b>.', np.content)[1]
                    prize = util.amt(prize)
                    print(f'Turned in {count}x {name} for {prize} NP. (Profit: {prize - true_cost})')
                elif 'You got the job!' in np.content:
                    print(f'Job was not completed before applying? TODO')
                    print(np.last_file_path)
                    return
                else:
                    print(f'Error applying for job. TODO')
                    print(np.last_file_path)
                    return
                jobs_to_do -= 1
                if jobs_to_do <= 0:
                    return

            if has_more_pages:
                start += 10
                np.get(path, 'type=jobs', 'voucher=basic', f'start={start}')
            else:
                break
    except item_db.ShopWizardBannedException:
        return

    print(jobs_by_profit)
    print('Did not find enough appropriate jobs.')
Exemplo n.º 6
0
def faerieland_jobs(jobs_to_do):
    np = NeoPage()
    np.get(path, 'type=jobs', 'voucher=basic')
    start = 0
    jobs_by_profit = []
    try:
        while jobs_to_do > 0:
            jobs = job_re.findall(np.content)
            has_more_pages = bool(
                re.search('<A HREF="employment.phtml.*?">Next 10</A>',
                          np.content))
            for image, job_link, count, name, prize in jobs:
                count = int(count)
                prize = util.amt(prize)
                revenue = prize * 1.25
                if revenue < MIN_PROFIT:
                    print(f'Skipping {name} (can only make {revenue})')
                    continue

                price = item_db.get_price(name, image)
                profit = revenue - count * price
                print(
                    f'Can profit by about {profit} NP: Buy {count}x {name} ({price} NP each), turn in for {revenue}'
                )
                bisect.insort(jobs_by_profit, (profit, name, count, job_link))
                if profit < MIN_PROFIT:
                    continue
                print('Taking the job!')

                true_cost = inventory.purchase(name,
                                               image=image,
                                               budget=revenue - MIN_PROFIT,
                                               quantity=count)
                if not true_cost:
                    print(f'Failed to acquire all the items within budget')
                    continue

                # Do the job!
                np.get(f'/faerieland/employ/{job_link}')
                if 'Good job! You got all the items' in np.content:
                    prize = re.search(
                        r'You have been paid <b>(.*?) Neopoints</b>.',
                        np.content)[1]
                    prize = util.amt(prize)
                    print(
                        f'Turned in {count}x {name} for {prize} NP. (Profit: {prize - true_cost})'
                    )
                elif 'You got the job!' in np.content:
                    print(f'Job was not completed before applying? TODO')
                    print(np.last_file_path)
                    return
                else:
                    print(f'Error applying for job. TODO')
                    print(np.last_file_path)
                    return
                jobs_to_do -= 1
                if jobs_to_do <= 0:
                    return

            if has_more_pages:
                start += 10
                np.get(path, 'type=jobs', 'voucher=basic', f'start={start}')
            else:
                break
    except item_db.ShopWizardBannedException:
        return

    print(jobs_by_profit)
    print('Did not find enough appropriate jobs.')
Exemplo n.º 7
0
def food_club():
    np = NeoPage()
    np.get(path, 'type=bet')
    if np.contains('All betting gates are now closed!'):
        print(f"Dangit, we're late.")
        return
    maxbet = util.amt(
        re.search(r'You can only place up to <b>(.*?)</b> NeoPoints per bet',
                  np.content)[1])
    print(f'Max bet is {maxbet}')

    # We compute the current round number because it seems there's no way to
    # find it explicitly unless you actually make a bet.
    day = int(
        re.search(
            r'Next match: <b>.*?</b> the <b>(\d+).*?</b> at <b>02:00 PM NST</b>',
            np.content)[1])
    date = neotime.now_nst().replace(day=day, hour=14, minute=0, second=0)
    epoch = datetime(2018, 10, 7, 14, 0, 0)
    from_epoch = round((date - epoch) / timedelta(days=1))
    cur_round = 7093 + from_epoch
    print(f'Food Club round {cur_round}')

    dl_fc_history(cur_round - 1, cur_round)
    table = stats()
    rnd = get_rounds(table[table['round'] == cur_round])[0]

    for i, arena in enumerate(arena_names):
        participants = ', '.join(pirate_names[p.pirate]
                                 for p in rnd.pirates[i])
        print(f'{arena} Arena: {participants}')

    bets = maxter_strategy(rnd, 1000000 / maxbet)
    total_bet_amt = 0
    total_exp_win = 0
    TER = 0
    for exp_win, spend, bet in bets:
        if exp_win < 1.0:
            print('Not making -EV bet: {bet}')
            continue
        bet_amt = round(spend * maxbet)
        print(f'Bet {bet_amt} NP on {bet}. EV: {exp_win * bet_amt:.1f} NP')
        opts = []
        total_odds = 1
        for i, (ps, b) in enumerate(zip(rnd.pirates, bet)):
            if b == None:
                continue
            ps[b].pirate
            opts.append(f'winner{i+1}={ps[b].pirate}')
            opts.append(f'matches[]={i+1}')
            total_odds *= ps[b].closing_odds
        opts.append(f'bet_amount={bet_amt}')
        opts.append(f'total_odds={total_odds}')
        opts.append(f'winnings={bet_amt * total_odds}')
        opts.append('type=bet')
        np.post('/pirates/process_foodclub.phtml', *opts)
        total_bet_amt += bet_amt
        total_exp_win += bet_amt * exp_win
        TER += exp_win

    print(
        f'Made {total_bet_amt} NP of bets. Expect to win {total_exp_win:.1f} NP. (TER {TER:.2f}; ROI {total_exp_win / total_bet_amt:.3f})'
    )

    np.get('/pirates/foodclub.phtml', 'type=collect')
    if np.contains("<input type='submit' value='Collect Your Winnings!'>"):
        tbl = np.search(r"<table border='0' .*?>(.*?)</table>")[1]
        tuples = util.table_to_tuples(tbl)
        earliest_rnd = int(tuples[2][0])
        total_winnings = tuples[-1][-1]
        print(
            f'Note: We have {total_winnings} winnings dating from round {earliest_rnd}.'
        )
        if cur_round - earliest_rnd >= 7:
            print(f'Should collect winnings before they vanish!')
Exemplo n.º 8
0
def food_club():
    np = NeoPage()
    np.get(path, 'type=bet')
    if np.contains('All betting gates are now closed!'):
        print(f"Dangit, we're late.")
        return
    maxbet = util.amt(re.search(r'You can only place up to <b>(.*?)</b> NeoPoints per bet', np.content)[1])
    print(f'Max bet is {maxbet}')

    # We compute the current round number because it seems there's no way to
    # find it explicitly unless you actually make a bet.
    day = int(re.search(r'Next match: <b>.*?</b> the <b>(\d+).*?</b> at <b>02:00 PM NST</b>', np.content)[1])
    date = neotime.now_nst().replace(day=day, hour=14, minute=0, second=0)
    epoch = datetime(2018, 10, 7, 14, 0, 0)
    from_epoch = round((date - epoch) / timedelta(days=1))
    cur_round = 7093 + from_epoch
    print(f'Food Club round {cur_round}')

    dl_fc_history(cur_round - 1, cur_round)
    table = stats()
    rnd = get_rounds(table[table['round'] == cur_round])[0]

    for i, arena in enumerate(arena_names):
        participants = ', '.join(pirate_names[p.pirate] for p in rnd.pirates[i])
        print(f'{arena} Arena: {participants}')

    bets = maxter_strategy(rnd, 1000000 / maxbet)
    total_bet_amt = 0
    total_exp_win = 0
    TER = 0
    for exp_win, spend, bet in bets:
        if exp_win < 1.0:
            print('Not making -EV bet: {bet}')
            continue
        bet_amt = round(spend * maxbet)
        print(f'Bet {bet_amt} NP on {bet}. EV: {exp_win * bet_amt:.1f} NP')
        opts = []
        total_odds = 1
        for i, (ps, b) in enumerate(zip(rnd.pirates, bet)):
            if b == None:
                continue
            ps[b].pirate
            opts.append(f'winner{i+1}={ps[b].pirate}')
            opts.append(f'matches[]={i+1}')
            total_odds *= ps[b].closing_odds
        opts.append(f'bet_amount={bet_amt}')
        opts.append(f'total_odds={total_odds}')
        opts.append(f'winnings={bet_amt * total_odds}')
        opts.append('type=bet')
        np.post('/pirates/process_foodclub.phtml', *opts)
        total_bet_amt += bet_amt
        total_exp_win += bet_amt * exp_win
        TER += exp_win

    print(f'Made {total_bet_amt} NP of bets. Expect to win {total_exp_win:.1f} NP. (TER {TER:.2f}; ROI {total_exp_win / total_bet_amt:.3f})')

    np.get('/pirates/foodclub.phtml', 'type=collect')
    if np.contains("<input type='submit' value='Collect Your Winnings!'>"):
        tbl = np.search(r"<table border='0' .*?>(.*?)</table>")[1]
        tuples = util.table_to_tuples(tbl)
        earliest_rnd = int(tuples[2][0])
        total_winnings = tuples[-1][-1]
        print(f'Note: We have {total_winnings} winnings dating from round {earliest_rnd}.')
        if cur_round - earliest_rnd >= 7:
            print(f'Should collect winnings before they vanish!')
Exemplo n.º 9
0
def fetch(verbose=False):
    log = open('fetch.log', 'a')
    np = NeoPage()
    # TODO: Figure out how to continue on from existing game.
    np.get(path, 'deletegame=1')

    # Start new game.
    UNKNOWN_COST = random.choice([1,2,3,4,5])

    diffs = re.findall(r'<A HREF="maze.phtml\?create=1&diff=(\d+)">', np.content)
    diff = '4' if '4' in diffs else '3'
    np.get(path, 'create=1', f'diff={diff}')
    maze_size = maze_sizes[diff]

    goal_item_img, goal_item = re.search(r'<IMG SRC="http://images.neopets.com/games/maze/(item_.*?)" WIDTH="80" HEIGHT="80"><br><b>(.*?)</b>', np.content).group(1, 2)
    print(f'Asked to find {goal_item} (img: {goal_item_img})')
    np.post(path)

    # State for a single game.
    maze = {}
    x_start = 0
    y_start = 0
    x_cur = x_start
    y_cur = y_start
    x_lower = -maze_size + 1
    x_upper = maze_size - 1
    y_lower = -maze_size + 1
    y_upper = maze_size - 1
    xy_item = None
    xy_exit = None

    while True:
        # Check end conditions.
        if np.contains('Success! You fetched the item and reached the exit!'):
            prize = util.amt(re.search(r'You have been awarded <b>(.*?)</b> for your efforts!', np.content)[1])
            print(f'Won! Got {prize} NP')
            if np.contains('You have achieved a streak'):
                streak, cumul = re.search(r'You have achieved a streak of <b>(.*?)</b> victories, for a running total of <b>(.*?)</b> points', np.content).group(1, 2)
                print(f'Streak is {streak}, total score {cumul}')

                # Don't get too high of a score!
                if int(cumul) > 0:
                    np.get(path, 'deletegame=1')
                    np.get(path, 'create=1', 'diff=1')
            else:
                streak = 1
                cumul = prize
            log.write(f'{diff},{UNKNOWN_COST},1,{prize},{streak},{cumul}\n')
            return (prize, streak, cumul)
        elif np.contains("Your master is very displeased!"):
            print(f'Ran out of time! :(')
            log.write(f'{diff},{UNKNOWN_COST},0,0,0,0\n')
            return

        moves_remaining = int(re.search(r'Moves Remaining: <b>(.*?)</b>', np.content)[1].split()[0])

        # Update knowledge.
        tbl = re.search(r'<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="400">(.*?)</TABLE>', np.content, flags=re.DOTALL)[1]
        tiles = re.findall(r'<TD BACKGROUND="http://images.neopets.com/games/maze/(.*?).gif" WIDTH="80" HEIGHT="80".*?>(.*?)</TD>', tbl)

        for jitter_x, jitter_y in [(0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)]:
            tiles_iter = iter(tiles)
            good = True
            for dy in range(-2, 3):
                for dx in range(-2, 3):
                    img, content = next(tiles_iter)
                    x = x_cur + jitter_x + dx
                    y = y_cur + jitter_y + dy
                    if (x, y) in maze and maze[x, y] != img_to_dirs[img]:
                        good = False
            if good:
                x_cur += jitter_x
                y_cur += jitter_y
                break

        tiles_iter = iter(tiles)
        for dy in range(-2, 3):
            for dx in range(-2, 3):
                img, content = next(tiles_iter)
                x = x_cur + dx
                y = y_cur + dy

                dirs = img_to_dirs[img]
                maze[x, y] = dirs

                if 'http://images.neopets.com/games/maze/item_' in content:
                    xy_item = (x, y)

                # Update knowledge of bounds
                if dirs == 0:
                    if dx == 0:
                        if dy < 0:
                            y_lower = max(y_lower, y_cur + dy + 1)
                            y_upper = y_lower + maze_size - 1
                        elif dy > 0:
                            y_upper = min(y_upper, y_cur + dy - 1)
                            y_lower = y_upper - maze_size + 1
                    if dy == 0:
                        if dx < 0:
                            x_lower = max(x_lower, x_cur + dx + 1)
                            x_upper = x_lower + maze_size - 1
                        elif dx > 0:
                            x_upper = min(x_upper, x_cur + dx - 1)
                            x_lower = x_upper - maze_size + 1

                # Path leading out of bounds indicates an exit
                if x_lower <= x <= x_upper and y_lower <= y <= y_upper:
                    for d in DIRS:
                        ddx, ddy = dir_to_delta[d]
                        if dirs & d and not (x_lower <= x + ddx <= x_upper and y_lower <= y + ddy <= y_upper):
                            xy_exit = (x, y)

        # Compute the goals.
        got_item = not np.contains('Searching for:')
        goals = []
        if got_item:
            # Find the exit!!
            if xy_exit:
                goals = [xy_exit]
            else:
                # All points on any side opposite the side you started on.
                candidates = []
                if x_lower == 0: candidates.extend((x_upper, y) for y in range(y_lower, y_upper + 1))
                if x_upper == 0: candidates.extend((x_lower, y) for y in range(y_lower, y_upper + 1))
                if y_lower == 0: candidates.extend((x, y_upper) for x in range(x_lower, x_upper + 1))
                if y_upper == 0: candidates.extend((x, y_lower) for x in range(x_lower, x_upper + 1))
                # ... that has not been a confirmed dud
                goals = []
                for x, y in candidates:
                    good = False
                    for d in DIRS:
                        dx, dy = dir_to_delta[d]
                        if not (x_lower <= x + dx <= x_upper and y_lower <= y + dy <= y_upper) and (maze.get((x, y), -1) & d) and (maze.get((x + dx, y + dy), -1) & opp_dir[d]):
                            good = True
                            break
                    if good:
                        goals.append((x, y))
        else:
            if xy_item:
                goals = [xy_item]
            else:
                # Possibilities for item location.
                padding = maze_size // 2 - 1
                goals = [(x, y)
                        for x in range(x_lower + padding, x_upper - padding + 1)
                        for y in range(y_lower + padding, y_upper - padding + 1)
                        if (x, y) not in maze]

        # Dijkstra's to figure out how to best reach a goal.
        # Distance is (# ? tiles, # known steps).
        prevs = {}
        Q = [(0, (x_cur, y_cur), None)]
        reached_goal = None
        while Q:
            c, (x, y), prev = heapq.heappop(Q)
            if (x, y) in prevs: continue
            if (x, y) not in maze and not (x_lower <= x <= x_upper and y_lower <= y <= y_upper): continue
            prevs[x, y] = prev
            if (x, y) in goals:
                reached_goal = (x, y)
                break
            dirs = maze.get((x, y), -1)
            c_ = c + (UNKNOWN_COST if dirs == -1 else 1)
            for d in DIRS:
                dx, dy = dir_to_delta[d]
                dirs_ = maze.get((x + dx, y + dy), -1)
                if dirs & d and dirs_ & opp_dir[d]:
                    heapq.heappush(Q, (c_, (x + dx, y + dy), (x, y)))

        if not reached_goal:
            print(f'Ended up in a bad aimless state.')
            log.write(f'{diff},{UNKNOWN_COST},0,0,0,0,ERROR\n')
            return
        
        # Backtrace route to find which direction to walk in.
        cur = reached_goal
        route = []
        while cur:
            route.append(cur)
            cur = prevs[cur]
        route = route[::-1]

        x_nxt, y_nxt = route[1]
        dxdy = (x_nxt - x_cur, y_nxt - y_cur)
        movedir = None
        if dxdy == (-1, 0): movedir = 2
        elif dxdy == (1, 0): movedir = 3
        elif dxdy == (0, -1): movedir = 0
        elif dxdy == (0, 1): movedir = 1

        # Print the maze.
        movechar = "↑↓←→"[movedir]
        if verbose:
            coords = list(maze.keys()) + goals
            min_x = max(x_lower - 2, min(xs(coords)))
            max_x = min(x_upper + 2, max(xs(coords)))
            min_y = max(y_lower - 2, min(ys(coords)))
            max_y = min(y_upper + 2, max(ys(coords)))
            for y in range(min_y - 1, max_y + 2):
                for x in range(min_x - 1, max_x + 2):
                    c = dirs_to_unicode[maze.get((x, y), -1)]
                    if (x, y) == (x_cur, y_cur):
                        c = '@'
                    if (x, y) in goals:
                        c = C_YELLOW + c + C_ENDC
                    elif (x, y) in route:
                        c = (C_GREEN if got_item else C_RED) + c + C_ENDC
                    elif abs(x - x_cur) <= 2 and abs(y - y_cur) <= 2:
                        c = C_CYAN + c + C_ENDC
                    if c == '?':
                        c = C_GREY + c + C_ENDC
                    print(c, end='')
                print()
            print(f'Moves left: {moves_remaining}')
            print(f'Min distance to goal: {len(route)}')
            print(f'Moving {movechar}')
            print()
        else:
            print(f'\r[{moves_remaining} {movechar}] ', end='')

        if len(route) > moves_remaining:
            print(f'No hope of winning. Giving up.')
            log.write(f'{diff},{UNKNOWN_COST},0,0,0,0\n')
            return

        s = re.search(r'<AREA SHAPE="poly" COORDS="57,57,57,0,91,0,91,57" HREF="maze.phtml\?action=move&movedir=0&s=(\d+)"', np.content)[1]
        np.get(path, 'action=move', f'movedir={movedir}', f's={s}')
        x_cur, y_cur = x_nxt, y_nxt