def anchor_management(): np = NeoPage(path) if np.contains('form-fire-cannon'): action = np.search('<input name="action" type="hidden" value="(.*?)">')[1] np.post(path, action=action) if np.contains('prize-item-name'): prize = np.search('<span class="prize-item-name">(.*?)</span>')[1] print(f'Blasted krawken; got {prize}') else: print('Blasted krawken; got unknown prize') elif np.contains('safe from sea monsters for one day'): print('Already did anchor management.') else: print("Couldn't find anchor management.")
def anchor_management(): np = NeoPage(path) if np.contains('form-fire-cannon'): action = np.search( '<input name="action" type="hidden" value="(.*?)">')[1] np.post(path, action=action) if np.contains('prize-item-name'): prize = np.search('<span class="prize-item-name">(.*?)</span>')[1] print(f'Blasted krawken; got {prize}') else: print('Blasted krawken; got unknown prize') elif np.contains('safe from sea monsters for one day'): print('Already did anchor management.') else: print("Couldn't find anchor management.")
def scorchy_slots(): np = NeoPage() np.get(path) _ref_ck = np.search(r"<input type='hidden' name='_ref_ck' value='(.*?)'>")[1] np.post(path, f'_ref_ck={_ref_ck}', 'play=yes') while True:
def bank_interest(): path = '/bank.phtml' np = NeoPage(path) if np.contains('You have already collected your interest today.'): print('Already collected interest today.') elif np.contains('Collect Interest ('): amount = np.search(r'Collect Interest \((.*?)\)')[1] print(f"Collecting {amount} interest.") np.post('/process_bank.phtml', 'type=interest') else: print("Error collecting bank interest.")
def apple_bobbing(): np = NeoPage(path) if np.contains('Give it a shot!'): np.get(path, bobbing=1) message = np.search("<div id='bob_middle'>(.*?)</div>")[1].strip() message = strip_tags(message) print(message) elif np.contains('blind underneath this hat'): print('Already apple bobbed today.') else: print("Couldn't find apple bobbing.")
def stats(): np = NeoPage() np.get(path) tbl = np.search(r'<table align=center cellpadding=3 cellspacing=0 border=0>(.*?)</table>')[0] rows = util.table_to_tuples(tbl) freqs = {i: 0 for i in range(1, 31)} for date, prize, winners, share, matches_needed, numbers in rows[1:]: nums = map(int, numbers.split(',')) for n in nums: freqs[n] += 1 for n, freq in sorted(freqs.items()): print(f'{n}, {freq}')
def ensure_np(amount): # Withdraws from the bank to get up at least [amount] NP. np = NeoPage() np.get('/bank.phtml') if np.contains('Collect Interest ('): bank_interest.bank_interest() nps = np.search( r'''<a id='npanchor' href="/inventory.phtml">(.*?)</a>''')[1] nps = int(nps.replace(',', '')) if nps >= amount: return need = amount - nps denom = 10**max(len(str(need)), len(str(amount))) need = (need // denom + 1) * denom np.post('/process_bank.phtml', 'type=withdraw', f'amount={need}') print(f'Withdrawing {need} NP')
def shapeshifter(timeout=10 * 60): np = NeoPage() np.get(path_index) starting_np = np.current_np() if np.contains('Continue Game!'): np.get(path_game) elif np.contains('Start Game!'): np.post(path_process, f'type=init') # Just in case we won but left it in the completed state if np.contains('You Won!') or np.contains('You Lost!'): np.post(path_process + '?type=init') tbl = np.search(r'''<table border=1 bordercolor='gray'>(.*?)</table>''')[1] imgs = re.findall( r'''<img src='(.*?)' border=0 name='i_'>(<br><b><small>GOAL</small></b></td>)?''', tbl) imgs = imgs[:-1] N = len(imgs) goal_idx = next(i for i, (_, goal) in enumerate(imgs) if goal) to_idx = {img: i for i, (img, _) in enumerate(imgs)} tbl = np.search( r'''<table align=center cellpadding=0 cellspacing=0 border=0>(.*?)</table>''' )[1] goal_grid = [] for row in re.findall(r'''<tr>(.*?)</tr>''', tbl, flags=re.DOTALL): imgs = re.findall(r'''<img src='(.*?)' .*?>''', row) goal_row = [to_idx[img] for img in imgs] goal_grid.append(goal_row) tbl = np.search( r'''<center><b><big>ACTIVE SHAPE</big></b><p>(.*?)</table>\n''')[1] shape_grids = [] for shape_info in re.findall(r'''<table.*?>(.*?)</table>''', tbl): grid = [] for row_info in re.findall(r'''<tr>(.*?)</tr>''', shape_info): tiles = re.findall(r'''<td.*?>(.*?)</td>''', row_info) grid.append( [int('square.gif' in tile_info) for tile_info in tiles]) shape_grids.append(grid) # Compute kvho difficulty. R = len(goal_grid) C = len(goal_grid[0]) min_shifts_needed = R * C * (N - 1) - sum(map(sum, goal_grid)) shifts_available = sum( sum(sum(rows) for rows in grid) for grid in shape_grids) num_overshifts = shifts_available - min_shifts_needed num_flips = num_overshifts // N print(f'Puzzle permits {num_flips} flips ({num_overshifts} overshifts)') kvho_input = make_kvho_input(goal_grid, shape_grids, goal_idx) print(f'Waiting for kvho.') start_time = datetime.now() positions = [] try: proc = subprocess.run(['c/ss'], input=kvho_input, encoding='utf-8', capture_output=True, timeout=timeout) for line in proc.stdout.splitlines(): if 'x' in line and '=' in line: x = list( map( int, line.replace('x', ' ').replace('=', ' ').strip().split())) for c, r, _ in zip(x[::3], x[1::3], x[2::3]): positions.append((r, c)) print(f'Solution found in {datetime.now() - start_time}: {positions}') except subprocess.TimeoutExpired: print( f'Solution not found in time. Throwing this puzzle to get a new one.' ) for _ in shape_grids: positions.append((0, 0)) for i, (shape, (r, c)) in enumerate(zip(shape_grids, positions)): print(f'\rPlacing piece {i+1}/{len(positions)}', end='') np.set_referer_path(path_game) np.get(path_process, 'type=action', f'posx={c}', f'posy={r}') time.sleep(0.5) print() if np.contains('You Won!'): np.set_referer_path(path_game) np.post(path_process + '?type=init') ending_np = np.current_np() print(f'Done level, earned {ending_np - starting_np} NP') return 1 elif np.contains('reached your max neopoints'): print('Done for today.') return 2 else: print('Did not solve level??') return 0
def update_prices(item_name, laxness=1): char_groups = 'an0 bo1 cp2 dq3 er4 fs5 gt6 hu7 iv8 jw9 kx_ ly mz'.split() c2g = dict(sum(([(c, i) for c in cs] for i, cs in enumerate(char_groups)), [])) markets = defaultdict(dict) ub_count = 0 search_count = 0 np = NeoPage('/market.phtml?type=wizard') opts = [] opts.append('type=process_wizard') opts.append('feedset=0') opts.append(f'shopwizard={item_name}') opts.append('table=shop') opts.append('criteria=exact') opts.append('min_price=0') opts.append('max_price=999999') # Repeatedly search the shop wizard, collecting all results seen. while not markets or any(len(market_data) < len(char_groups) - laxness for market_data in markets.values()): print(f'\r({sum(len(md) for md in markets.values())}/{len(markets) * len(char_groups)}) ', end='') np.post('/market.phtml', *opts) tbl = np.search(r'<table width="600".*?>(.*?)</table>') if not tbl: if np.contains('Whoa there, too many'): print('Shop wizard banned.') raise ShopWizardBannedException ub_count += 1 if ub_count >= 5: break continue tbl = tbl[1] rows = lib.table_to_tuples(tbl, raw=True)[1:] search_count += 1 if search_count >= 50: break market_data = [] obj_info_id = None for owner, item, stock, price in rows: result = re.search(r'<a href="(.*?)"><b>(.*?)</b></a>', owner) link = result[1] owner = result[2] result = re.search(r'/browseshop.phtml\?owner=(.*?)&buy_obj_info_id=(.*?)&buy_cost_neopoints=(\d+)', link) obj_info_id = int(result[2]) price = lib.amt(lib.strip_tags(price)) stock = lib.amt(stock) market_data.append((price, stock, link)) g = c2g[lib.strip_tags(rows[0][0])[0]] markets[obj_info_id][g] = market_data level2_by_item = {} # Consolidate results for each item into a quote. if markets: for obj_info_id, market_data in markets.items(): # TODO: Check suspiciously cheap prices to see if owners are frozen. level2 = sorted(sum(market_data.values(), [])) level2_by_item[obj_info_id] = level2 # The price of an item for our purposes is the price of the 2nd # cheapest item in the market. cur_amt = 0 cur_price = UNBUYABLE_PRICE for price, stock, link in level2: cur_price = price cur_amt += stock if cur_amt >= 2: break print(f'The price of {item_name} (id {obj_info_id}) is {cur_price} NP.') cur_amt = 0 for price, stock, link in level2: cur_amt += stock if cur_amt >= 30: break c = conn.cursor() c.execute(''' SELECT name FROM items WHERE obj_info_id=? ''', (obj_info_id,)) result = c.fetchone() if not result or result[0][0] != item_name: for market_data in level2: # Visit the shop and populate a bunch of fields np.get(market_data[2]) res = np.search(r'''<A href=".*?" onClick=".*?"><img src="http://images.neopets.com/items/(.*?)" .*? title="(.*?)" border="1"></a> <br> <b>(.*?)</b>''') if not res: print(f'{market_data[2]} is froze?') continue image = res[1] desc = res[2] name = res[3] c.execute(''' INSERT INTO items (name, image, desc, obj_info_id, last_updated) VALUES (?, ?, ?, ?, datetime('now')) ON CONFLICT (name, image) DO UPDATE SET desc=?, obj_info_id=?, last_updated=datetime('now') ''', (name, image, desc, obj_info_id, desc, obj_info_id)) print(f'The object id of {name} is {obj_info_id}') break else: print('Unable to find legit seller for {obj_info_id}. Will not store it in itemdb.') continue c.execute(''' UPDATE items SET price=?, price_last_updated=datetime('now') WHERE obj_info_id=? ''', (cur_price, obj_info_id)) else: print(f'It seems {item_name} is unbuyable.') # Item could not be found; assume it's unbuyable. # We use a cheap price estimate of 1,000,001 NP. # TODO: Items inserted in this way will have a wonky image property. c = conn.cursor() c.execute(''' INSERT INTO items (name, image, last_updated, price, price_last_updated) VALUES (?, NULL, datetime('now'), 1000001, datetime('now')) ON CONFLICT (name, image) DO UPDATE SET last_updated=datetime('now'), price=1000001, price_last_updated=datetime('now') ''', (item_name,)) conn.commit() return level2_by_item
def shapeshifter(timeout=10*60): np = NeoPage() np.get(path_index) starting_np = np.current_np() if np.contains('Continue Game!'): np.get(path_game) elif np.contains('Start Game!'): np.post(path_process, f'type=init') # Just in case we won but left it in the completed state if np.contains('You Won!') or np.contains('You Lost!'): np.post(path_process + '?type=init') tbl = np.search(r'''<table border=1 bordercolor='gray'>(.*?)</table>''')[1] imgs = re.findall(r'''<img src='(.*?)' border=0 name='i_'>(<br><b><small>GOAL</small></b></td>)?''', tbl) imgs = imgs[:-1] N = len(imgs) goal_idx = next(i for i, (_, goal) in enumerate(imgs) if goal) to_idx = {img: i for i, (img, _) in enumerate(imgs)} tbl = np.search(r'''<table align=center cellpadding=0 cellspacing=0 border=0>(.*?)</table>''')[1] goal_grid = [] for row in re.findall(r'''<tr>(.*?)</tr>''', tbl, flags=re.DOTALL): imgs = re.findall(r'''<img src='(.*?)' .*?>''', row) goal_row = [to_idx[img] for img in imgs] goal_grid.append(goal_row) tbl = np.search(r'''<center><b><big>ACTIVE SHAPE</big></b><p>(.*?)</table>\n''')[1] shape_grids = [] for shape_info in re.findall(r'''<table.*?>(.*?)</table>''', tbl): grid = [] for row_info in re.findall(r'''<tr>(.*?)</tr>''', shape_info): tiles = re.findall(r'''<td.*?>(.*?)</td>''', row_info) grid.append([int('square.gif' in tile_info) for tile_info in tiles]) shape_grids.append(grid) # Compute kvho difficulty. R = len(goal_grid) C = len(goal_grid[0]) min_shifts_needed = R * C * (N - 1) - sum(map(sum, goal_grid)) shifts_available = sum(sum(sum(rows) for rows in grid) for grid in shape_grids) num_overshifts = shifts_available - min_shifts_needed num_flips = num_overshifts // N print(f'Puzzle permits {num_flips} flips ({num_overshifts} overshifts)') kvho_input = make_kvho_input(goal_grid, shape_grids, goal_idx) print(f'Waiting for kvho.') start_time = datetime.now() positions = [] try: proc = subprocess.run(['c/ss'], input=kvho_input, encoding='utf-8', capture_output=True, timeout=timeout) for line in proc.stdout.splitlines(): if 'x' in line and '=' in line: x = list(map(int, line.replace('x', ' ').replace('=', ' ').strip().split())) for c, r, _ in zip(x[::3], x[1::3], x[2::3]): positions.append((r, c)) print(f'Solution found in {datetime.now() - start_time}: {positions}') except subprocess.TimeoutExpired: print(f'Solution not found in time. Throwing this puzzle to get a new one.') for _ in shape_grids: positions.append((0, 0)) for i, (shape, (r, c)) in enumerate(zip(shape_grids, positions)): print(f'\rPlacing piece {i+1}/{len(positions)}', end='') np.set_referer_path(path_game) np.get(path_process, 'type=action', f'posx={c}', f'posy={r}') time.sleep(0.5) print() if np.contains('You Won!'): np.set_referer_path(path_game) np.post(path_process + '?type=init') ending_np = np.current_np() print(f'Done level, earned {ending_np - starting_np} NP') return 1 elif np.contains('reached your max neopoints'): print('Done for today.') return 2 else: print('Did not solve level??') return 0
def battledome(forever=False): np = NeoPage(path) np.get(path_arena) neopoints_left = True prizes_left = True while prizes_left or forever: battle_id = None if np.contains('battleid:'): print('Battledome: Already in fight.') battle_id = np.search(r"battleid:'(\d+)',")[1] else: print('Battledome: Starting fight.') np.post(path_start_fight, 'type=2', f'pet={PET_NAME}', f'npcId={npc_id}', f'toughness={toughness}') battle = json.loads(np.content) if not battle['success']: print('Battledome: Error.') return battle_id = battle['battle']['id'] time.sleep(2) np.set_referer_path(path) np.get(path_arena) ts = int(time.time() * 1000) for step in itertools.count(): intro = 1 if step == 0 else 0 np.set_referer_path(path_arena) np.post(path_arena_ajax, f'battleid={battle_id}', f'step={step}', f'intro={intro}', 'status=1') resp = json.loads(np.content) abils = resp['p1']['abils'] chosen_abil = '' for abil in ['21', '2', '14', '17', '1']: if abil in abils and not abils[abil]['hasCooldown']: chosen_abil = abil break items = re.findall( r'<li><img.*?id="(\d+)".*?title="(.*?)".*?/></li>', resp['p1']['items']) item1id = items[0][0] item2id = items[1][0] opts = [] opts.append(f'p1s=') opts.append(f'eq1={item1id}') opts.append(f'eq2={item2id}') opts.append(f'p1a={chosen_abil}') opts.append(f'chat=') opts.append('action=attack') opts.append(f'ts={ts}') opts.append(f'battleid={battle_id}') opts.append(f'step={step}') opts.append(f'intro=0') opts.append('status=1') print( f'Battledome: Attacking with {items[0][1]} and {items[1][1]}') np.set_referer_path(path_arena) np.post(path_arena_ajax, *opts) resp = json.loads(np.content) if resp['battle']['prizes'] or 'prize_messages' in resp['battle']: prizes = ', '.join( x['name'] for x in resp['battle']['prizes']) or "nothing" print(f'Battledome: Won {prizes}') if 'prize_messages' in resp['battle']: prize_messages = resp['battle']['prize_messages'] if any('reached the item limit' in m for m in prize_messages): prizes_left = False if any('reached the NP limit' in m for m in prize_messages): neopoints_left = False print(f'Battledome: {prize_messages}') break # TODO: Detect defeat. elif step > 5: print( f'Battledome: Took more than 5 steps. Something went wrong.' )
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!')
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!')