示例#1
0
def write_workplan(service,
                   spid,
                   a,
                   workplan,
                   stats,
                   faction,
                   travelmode='walking',
                   nosave=False):
    from pprint import pformat

    if spid.find('/') > 0:
        chunks = spid.split('/')
        spid = chunks[5]
    # Use for spreadsheet rows
    planrows = []
    travelmoji = {
        'walking': u"\U0001F6B6",
        'bicycling': u"\U0001F6B2",
        'transit': u"\U0001F68D",
        'driving': u"\U0001F697",
    }

    n = a.order()
    logger.info('portals:')
    for p in range(n):
        logger.info('    %d: %s', p, a.node[p]['name'])
    logger.info('orig_workplan:\n%s', pformat(a.orig_workplan))
    logger.info('fixes:\n%s', pformat(a.fixes))
    logger.info('workplan:\n%s', pformat(workplan))
    logger.info('stats:\n%s', pformat(stats))

    # Track which portals we've already captured
    # (easier than going through the list backwards)
    prev_p = None
    plan_at = 0
    n_waypoints = 0

    for p, q, f in workplan:
        plan_at += 1

        # Are we at a different location than the previous portal?
        if p != prev_p:
            # How many keys do we need if/until we come back?
            ensurekeys = 0
            totalkeys = 0
            # Track when we leave this portal
            lastvisit = True
            same_p = True
            for fp, fq, ff in workplan[plan_at:]:
                if fp == p:
                    # Are we still at the same portal?
                    if same_p:
                        continue
                    if lastvisit:
                        lastvisit = False
                        ensurekeys = totalkeys
                else:
                    # we're at a different portal
                    same_p = False
                if fq == p:
                    # Future link to this portal
                    totalkeys += 1

            mapurl = 'https://www.google.com/maps/dir/?api=1&destination=%s&travelmode=%s' % (
                a.node[p]['pll'], travelmode)
            if 'special' in a.node[p]:
                special = a.node[p]['special']
            else:
                special = None

            if prev_p is not None:
                dist = maxfield.get_portal_distance(prev_p, p)
                duration = maxfield.get_portal_time(prev_p, p)

                if dist > 40:
                    if dist >= 500:
                        nicedist = '%0.1f km (%s min)' % (
                            (dist / float(1000)), duration)
                    else:
                        nicedist = '%d m' % dist
                    hyperlink = '=HYPERLINK("%s"; "%s")' % (mapurl, nicedist)
                    planrows.append((u'▼', ))
                    planrows.append((travelmoji[travelmode], hyperlink))
                    logger.info('-->Move to %s [%s]', a.node[p]['name'],
                                nicedist)
                else:
                    planrows.append((u'▼', ))
            else:
                hyperlink = '=HYPERLINK("%s"; "map")' % mapurl
                planrows.append((travelmoji[travelmode], hyperlink))
                logger.info('-->Start at %s', a.node[p]['name'])

            logger.info('--|At %s', a.node[p]['name'])
            # Are we at a waypoint?
            if special in ('_w_start', '_w_end'):
                planrows.append(('W', a.node[p]['name']))
                # Nothing else here
                prev_p = p
                n_waypoints += 1
                continue

            planrows.append(('P', a.node[p]['name']))

            # Are we at a blocker?
            if special == '_w_blocker':
                planrows.append(('X', 'destroy blocker'))
                logger.info('--|X: destroy blocker')
                # Nothing else here
                prev_p = p
                n_waypoints += 1
                continue

            if totalkeys:
                if lastvisit:
                    logger.info('--|H: ensure %d keys', totalkeys)
                    planrows.append(('H', 'ensure %d keys' % totalkeys))
                elif ensurekeys:
                    logger.info('--|H: ensure %d keys (%d max)', ensurekeys,
                                totalkeys)
                    planrows.append(
                        ('H',
                         'ensure %d keys (%d max)' % (ensurekeys, totalkeys)))
                else:
                    logger.info('--|H: %d max keys needed', totalkeys)
                    planrows.append(('H', '%d max keys needed' % totalkeys))

            if lastvisit:
                totallinks = a.out_degree(p) + a.in_degree(p)
                planrows.append(('S', 'shields on (%d links)' % totallinks))
                logger.info('--|S: shields on (%d out, %d in)',
                            a.out_degree(p), a.in_degree(p))

            prev_p = p

        if q is not None:
            # Add links/fields
            if f > 1:
                action = 'D'
            elif f == 1:
                action = 'F'
            else:
                action = 'L'

            planrows.append((action, u'▶%s' % a.node[q]['name']))
            logger.info('  \\%s--> %s', action, a.node[q]['name'])

    totalkm = stats['dist'] / float(1000)
    logger.info('Total workplan distance: %0.2f km', totalkm)
    logger.info('Total workplan play time: %s (%s %s)', stats['nicetime'],
                stats['nicetraveltime'], travelmode)
    logger.info('Total AP: %s (%s without capturing)', stats['ap'],
                stats['ap'] - (a.order() * maxfield.CAPTUREAP))
    if nosave:
        logger.info('Not saving spreadsheet per request.')
        return

    # title = 'Ingress: around %s (%s AP)' % (a.node[0]['name'], '{:,}'.format(totalap))
    # logger.info('Setting spreadsheet title: %s', title)

    requests = list()
    # requests.append({
    #    'updateSpreadsheetProperties': {
    #        'properties': {
    #            'title': title,
    #            'locale': 'en_US',
    #        },
    #        'fields': 'title',
    #    }
    # })

    dtitle = '%s %s (%0.2fkm/%dP/%sAP)' % (
        travelmoji[travelmode], stats['nicetime'], totalkm,
        a.order() - n_waypoints, '{:,}'.format(stats['ap']))
    logger.info('Adding "%s" sheet with %d actions', dtitle, len(workplan))
    requests.append({'addSheet': {
        'properties': {
            'title': dtitle,
        }
    }})

    body = {
        'requests': requests,
    }
    res = service.spreadsheets().batchUpdate(spreadsheetId=spid,
                                             body=body).execute()
    sheet_ids = []
    for blurb in res['replies']:
        if 'addSheet' in blurb:
            sheet_ids.append(blurb['addSheet']['properties']['sheetId'])

    # Now we generate a values update request
    updates = list()

    updates.append({
        'range': '%s!A1:B%d' % (dtitle, len(planrows)),
        'majorDimension': 'ROWS',
        'values': planrows,
    })

    body = {
        'valueInputOption': 'USER_ENTERED',
        'data': updates,
    }

    service.spreadsheets().values().batchUpdate(spreadsheetId=spid,
                                                body=body).execute()

    logger.info('Resizing columns and adding colours')
    # now auto-resize all columns
    requests = []
    colors = [
        ('H', 1.0, 0.6, 0.4),  # Hack
        ('S', 0.9, 0.7, 0.9),  # Shield
        ('T', 0.9, 0.9, 0.9),  # Travel
        ('P', 0.6, 0.6, 0.6),  # Portal
        ('W', 0.6, 0.6, 0.6),  # Waypoint
        ('X', 1.0, 0.6, 0.6),  # Blocker
    ]
    if faction == 'res':
        colors += [
            ('L', 0.6, 0.8, 1.0),  # Link
            ('F', 0.3, 0.5, 1.0),  # Field
            ('D', 0.2, 0.3, 0.8),  # Double Field
        ]
    else:
        colors += [
            ('L', 0.8, 1.0, 0.8),  # Link
            ('F', 0.5, 1.0, 0.5),  # Field
            ('D', 0.3, 0.8, 0.3),  # Double Field
        ]

    for sid in sheet_ids:
        requests.append({
            'autoResizeDimensions': {
                'dimensions': {
                    'sheetId': sid,
                    'dimension': 'COLUMNS',
                    'startIndex': 0,
                    'endIndex': 3,
                }
            }
        })

        # set conditional formatting on the Workplan sheet
        my_range = {
            'sheetId': sid,
            'startRowIndex': 0,
            'endRowIndex': len(planrows),
            'startColumnIndex': 0,
            'endColumnIndex': 1,
        }
        for text, red, green, blue in colors:
            requests.append({
                'addConditionalFormatRule': {
                    'rule': {
                        'ranges': [my_range],
                        'booleanRule': {
                            'condition': {
                                'type': 'TEXT_EQ',
                                'values': [{
                                    'userEnteredValue': text
                                }]
                            },
                            'format': {
                                'backgroundColor': {
                                    'red': red,
                                    'green': green,
                                    'blue': blue
                                }
                            }
                        }
                    },
                    'index': 0
                }
            })

    body = {
        'requests': requests,
    }
    service.spreadsheets().batchUpdate(spreadsheetId=spid, body=body).execute()
    logger.info('Spreadsheet generation done')
示例#2
0
def make_png_steps(workplan, outdir, faction, plotdpi=96):
    logger.info('Generating step-by-step pngs of the workplan')
    if not os.path.isdir(outdir):
        os.mkdir(outdir)

    a = maxfield.active_graph
    ap = maxfield.portal_graph

    c_grn = (0.0, 1.0, 0.0, 0.3)
    c_blu = (0.0, 0.0, 1.0, 0.3)
    c_red = (1.0, 0.0, 0.0, 0.5)
    c_inv = (0.0, 0.0, 0.0, 0.0)

    portals = np.array([ap.nodes[i]['xy'] for i in ap.nodes()]).T

    fig = plt.figure(figsize=(11, 8), dpi=plotdpi)
    frames = list()
    ax = fig.add_subplot(1, 1, 1)
    ax.axis('off')

    ax.plot(portals[0], portals[1], 'ko')
    ax.set_title('Portals before capture', ha='center')

    filen = os.path.join(outdir, 'step_{0:03d}.png'.format(len(frames)))
    fig.savefig(filen)
    frames.append(filen)

    p = prev_p = prev_special = None
    seen_p = list()
    for p, q, f in workplan:
        if p != prev_p:
            torm = list()
            special = a.nodes[p]['special']
            if special is None:
                # Colour this nodes captured
                p_coords = np.array(a.nodes[p]['xy']).T
                if faction == 'res':
                    ax.plot(p_coords[0], p_coords[1], 'bo')
                else:
                    ax.plot(p_coords[0], p_coords[1], 'go')

            if prev_p is not None:
                # Show travel edge
                if special == '_w_blocker':
                    action = 'Destroy blocker'
                elif special in ('_w_start', '_w_end'):
                    action = 'Travel to waypoint'
                else:
                    if prev_special is None:
                        torm = draw_edge(a,
                                         prev_p,
                                         p,
                                         ax,
                                         'm:',
                                         directional=True)
                    action = 'Capture'

                dist = maxfield.get_portal_distance(prev_p, p)
                if p not in seen_p:
                    if dist > 40:
                        ax.set_title('%s %s (%s m)' %
                                     (action, a.nodes[p]['name'], dist),
                                     ha='center')
                    else:
                        ax.set_title('%s %s' % (action, a.nodes[p]['name']),
                                     ha='center')
                else:
                    if dist > 40:
                        ax.set_title('Travel to %s (%s m)' %
                                     (a.nodes[p]['name'], dist),
                                     ha='center')
                    else:
                        ax.set_title('Move to %s' % a.nodes[p]['name'],
                                     ha='center')
            else:
                ax.set_title('Start at %s' % a.nodes[p]['name'], ha='center')

            filen = os.path.join(outdir,
                                 'step_{0:03d}.png'.format(len(frames)))
            fig.savefig(filen)
            frames.append(filen)
            for art in torm:
                art.remove()

        prev_p = p
        prev_special = special
        if p not in seen_p:
            seen_p.append(p)

        if q is None:
            continue

        ax.set_title('Link to %s' % a.nodes[q]['name'], ha='center')

        # Draw the link edge
        torm = draw_edge(a, p, q, ax, 'k-', directional=True)

        fields = list()
        if f:
            # We'll display the new fields in red
            for tri in a.edges[p, q]['fields']:
                coords = np.array([a.nodes[v]['xy'] for v in tri])
                fields.append(
                    Polygon(shrink(coords.T).T,
                            facecolor=c_red,
                            edgecolor=c_inv))

            for field in fields:
                torm.append(ax.add_patch(field))

        filen = os.path.join(outdir, 'step_{0:03d}.png'.format(len(frames)))
        fig.savefig(filen)
        frames.append(filen)

        # remove the newly added edges and triangles from the graph
        for art in torm:
            art.remove()
        # redraw the new edges and fields in the final colour
        if faction == 'res':
            draw_edge(a, p, q, ax, 'b-')
        else:
            draw_edge(a, p, q, ax, 'g-')

        if f:
            # reset fields to faction color
            for field in fields:
                if faction == 'res':
                    field.set_facecolor(c_blu)
                else:
                    field.set_facecolor(c_grn)
                ax.add_patch(field)

    # Save final frame with all completed fields
    ax.set_title('Finish at %s' % a.nodes[p]['name'], ha='center')
    filen = os.path.join(outdir, 'step_{0:03d}.png'.format(len(frames)))
    fig.savefig(filen)
    frames.append(filen)

    logger.info('Saved step-by-step pngs into %s', outdir)