Ejemplo n.º 1
0
 def __init__(self, transitions=None):
     self.segment = Segment()
     self.transitions = transitions or []
     self.time = SegmentTime(gametime=FrameCount(0),
                             realtime=FrameCount(0),
                             roomlag=FrameCount(0),
                             door=FrameCount(0),
                             realtime_door=FrameCount(0))
Ejemplo n.º 2
0
    def render(self):
        table = Table()

        underline = 4
        header = [
            Cell(s, underline)
            for s in ('Room', '#', 'Time', '±Median', '±Best')
        ]
        table.append(header)

        stats = self.tracker.current_attempt_stats

        for transition_stats in stats.transitions:
            transition = transition_stats.transition

            time_color = color_for_time(
                transition.time.totalrealtime,
                transition_stats.attempts.totalrealtimes)

            time_color = '38;5;%s' % time_color
            cell_color = None

            table.append([
                Cell(transition.id.room, color=cell_color, max_width=28),
                Cell(transition_stats.num_attempts,
                     color=cell_color,
                     justify='right'),
                Cell(transition.time.totalrealtime,
                     color=time_color,
                     justify='right'),
                Cell(
                    ('+' if transition_stats.p50_delta > FrameCount(0) else '')
                    + str(transition_stats.p50_delta),
                    color=cell_color,
                    justify='right'),
                Cell(('+' if transition_stats.p0_delta > FrameCount(0) else '')
                     + str(transition_stats.p0_delta),
                     color=cell_color,
                     justify='right'),
            ])

        color = color_for_time(self.tracker.current_attempt.time.totalrealtime,
                               stats.seg_attempts.totalrealtimes)
        table.append([
            Cell('Segment'),
            Cell(stats.num_attempts, justify='right'),
            Cell(self.tracker.current_attempt.time.totalrealtime,
                 '38;5;%s' % color,
                 justify='right'),
            Cell(('+' if stats.p50_delta > FrameCount(0) else '') +
                 str(stats.p50_delta),
                 justify='right'),
            Cell(('+' if stats.p0_delta > FrameCount(0) else '') +
                 str(stats.p0_delta),
                 justify='right'),
        ])

        return table.render()
Ejemplo n.º 3
0
  def __init__(self, history, segments):
    self.segments = [ ]
    self.total_p50 = FrameCount(0)
    self.total_p0 = FrameCount(0)
    self.total_sob = FrameCount(0)

    for segment in segments:
      stats = SingleSegmentStats(segment, history)
      self.segments.append(stats)

      self.total_p50 += stats.p50
      self.total_p0 += stats.p0
      self.total_sob += stats.sob
Ejemplo n.º 4
0
    def append(self, transition, current_attempt):
        self.transitions.append(
            SegmentTransitionAttemptStats(transition, self.history))

        self.seg_attempts = find_segment_in_history(current_attempt.segment,
                                                    self.history)

        attempt_time = current_attempt.time.totalrealtime
        historical_times = self.seg_attempts.totalrealtimes

        self.num_attempts = len(self.seg_attempts)
        self.p50 = historical_times.median() if len(
            historical_times.values()) > 0 else FrameCount(0)
        self.p0 = historical_times.best() if len(
            historical_times.values()) > 0 else FrameCount(0)
        self.p50_delta = attempt_time - self.p50
        self.p0_delta = attempt_time - self.p0
Ejemplo n.º 5
0
def door_stats(num_rooms, iqr):
    n = num_rooms

    # TODO: this number is probably wrong, but it's the number that got me
    # closest to the actual time shown on the screen in my most recent
    # run.
    t = n * 120
    best = FrameCount(t)
    p25 = FrameCount(t)
    p50 = FrameCount(t)
    p75 = FrameCount(t)
    p90 = FrameCount(t)
    save = p75 - p25 if iqr else p50 - best
    most_recent = FrameCount(t)
    save_most_recent = max(most_recent - p50, FrameCount(0))
    return TransitionStats(room=Room(None, 'Uncounted door time'),
                           n='',
                           best=best,
                           p25=p25,
                           p50=p50,
                           p75=p75,
                           p90=p90,
                           save=save,
                           most_recent=most_recent,
                           save_most_recent=save_most_recent,
                           items='',
                           beams='')
Ejemplo n.º 6
0
 def handle_reached_ship(self, state):
     ts = datetime.datetime.now()
     transition_id = TransitionId(state.room, state.door, NullDoor,
                                  state.items, state.beams)
     transition_time = TransitionTime(state.last_gametime_room,
                                      state.last_realtime_room,
                                      state.last_room_lag, FrameCount(0),
                                      state.last_realtime_door)
     transition = Transition(ts, transition_id, transition_time)
     self.on_transitioned(transition)
Ejemplo n.º 7
0
  def __init__(self, segment, history):
    self.segment = segment

    successful_attempts = find_segment_in_history(segment, history)
    # The number of segment attempts is the number of times we attempted
    # the first three rooms in the segment in succession.
    all_attempts = find_segment_in_history(segment[0:2], history)
    self.segment_attempt_count = len(all_attempts)

    self.segment_success_count = len(successful_attempts)
    self.rate = self.segment_success_count / self.segment_attempt_count if self.segment_attempt_count > 0 else 0

    self.p50 = successful_attempts.totalrealtimes.median()
    self.p0 = successful_attempts.totalrealtimes.best()
    self.sob = sum_of_best(segment, history)

    if any(( is_ceres_escape(tid) for tid in segment )):
      self.p50 += FrameCount(2591)
      self.p0 += FrameCount(2591)
      self.sob += FrameCount(2591)
Ejemplo n.º 8
0
 def handle_escaped_ceres(self, state):
     ts = datetime.datetime.now()
     transition_id = TransitionId(state.room, state.door,
                                  self.state_reader.ceres_elevator,
                                  state.items, state.beams)
     transition_time = TransitionTime(state.last_gametime_room,
                                      state.last_realtime_room,
                                      state.last_room_lag, FrameCount(0),
                                      state.last_realtime_door)
     transition = Transition(ts, transition_id, transition_time)
     self.on_transitioned(transition)
Ejemplo n.º 9
0
    def __init__(self, transition, history):
        self.transition = transition

        attempts = history.history.get(transition.id, None)

        if attempts is not None:
            self.attempts = attempts
            self.num_attempts = len(attempts)
            self.time = transition.time.totalrealtime
            self.p50 = attempts.totalrealtimes.median()
            self.p0 = attempts.totalrealtimes.best()
            self.p50_delta = self.time - self.p50
            self.p0_delta = self.time - self.p0
        else:
            self.attempts = Attempts()
            self.num_attempts = 0
            self.time = FrameCount(0)
            self.p50 = FrameCount(0)
            self.p0 = FrameCount(0)
            self.p50_delta = FrameCount(0)
            self.p0_delta = FrameCount(0)
Ejemplo n.º 10
0
def transition_stats(id, attempts, iqr, exclude_doors, doors_only):
    n = len(attempts.attempts)

    values = []
    if not doors_only: values.append(attempts.realtimes.values())
    if not exclude_doors: values.append(attempts.doortimes.values())

    times = [sum(v) for v in zip(*values)]

    best = FrameCount(stats.scoreatpercentile(times, 0))
    p25 = FrameCount(stats.scoreatpercentile(times, 25))
    p50 = FrameCount(stats.scoreatpercentile(times, 50))
    p75 = FrameCount(stats.scoreatpercentile(times, 75))
    p90 = FrameCount(stats.scoreatpercentile(times, 90))
    save = p75 - p25 if iqr else p50 - best
    most_recent = attempts.realtimes.most_recent(
    ) + attempts.doortimes.most_recent()
    save_most_recent = max(most_recent - p50, FrameCount(0))
    items = id.items
    beams = id.beams
    return TransitionStats(room=id.room,
                           n=n,
                           best=best,
                           p25=p25,
                           p50=p50,
                           p75=p75,
                           p90=p90,
                           save=save,
                           most_recent=most_recent,
                           save_most_recent=save_most_recent,
                           items=items,
                           beams=beams)
Ejemplo n.º 11
0
    def validate_transition(self, state):
        if state.seg_rt < self.prev_state.seg_rt:
            self.log(
                "Ignoring transition from %s to %s (segment timer went backward from %s to %s)"
                % (self.last_room, state.room, self.prev_state.seg_rt,
                   state.seg_rt))
            return False

        if state.last_door_lag_frames == FrameCount(0):
            self.log("Transition not yet finished? (door time is 0.00)")
            return False

        if self.last_room is not self.last_most_recent_door.exit_room:
            self.log("Ignoring transition (entry door leads to %s, not %s)" %
                     (self.last_most_recent_door.exit_room, self.last_room))
            return False

        if self.last_room is not self.most_recent_door.entry_room:
            self.log(
                "Ignoring transition (exit door is located in room %s, not %s)"
                % (self.most_recent_door.entry_room, self.last_room))
            return False

        return True
Ejemplo n.º 12
0
def ceres_cutscene_stats(id, attempts, iqr):
    n = len(attempts.attempts)
    best = FrameCount(2951)
    p25 = FrameCount(2951)
    p50 = FrameCount(2951)
    p75 = FrameCount(2951)
    p90 = FrameCount(2951)
    save = p75 - p25 if iqr else p50 - best
    most_recent = FrameCount(2951)
    save_most_recent = max(most_recent - p50, FrameCount(0))
    items = id.items
    beams = id.beams
    return TransitionStats(room=Room(None, 'Ceres Cutscene'),
                           n=n,
                           best=best,
                           p25=p25,
                           p50=p50,
                           p75=p75,
                           p90=p90,
                           save=save,
                           most_recent=most_recent,
                           save_most_recent=save_most_recent,
                           items=items,
                           beams=beams)
Ejemplo n.º 13
0
    def from_csv_row(self, rooms, doors, row):
        room = rooms.from_id(int(row['room_id'], 16))

        entry_door_id = int(row.get('entry_door', '0'), 16)
        if entry_door_id == 0:
            entry_room = rooms.from_id(int(row['entry_id'], 16))
            entry_door = doors.from_terminals(entry_room, room)
        else:
            entry_door = doors.from_id(entry_door_id)

        exit_door_id = int(row.get('exit_door', '0'), 16)
        if exit_door_id == 0:
            exit_room = rooms.from_id(int(row['exit_id'], 16))
            exit_door = doors.from_terminals(room, exit_room)
        else:
            exit_door = doors.from_id(exit_door_id)

        ts = row.get('timestamp', None)
        if ts is not None:
            ts = datetime.datetime.fromisoformat(ts)
        else:
            ts = datetime.datetime.fromtimestamp(0)

        transition_id = TransitionId(room=room,
                                     entry_door=entry_door,
                                     exit_door=exit_door,
                                     items=row['items'],
                                     beams=row['beams'])
        if 'lagtime' in row and not 'roomlagtime' in row:
            row['roomlagtime'] = row['lagtime']
        transition_time = TransitionTime(
            FrameCount.from_seconds(float(row['gametime'])),
            FrameCount.from_seconds(float(row['realtime'])),
            FrameCount.from_seconds(float(row['roomlagtime']))
            if 'roomlagtime' in row else None,
            FrameCount.from_seconds(float(row['doortime'])),
            FrameCount(120) + FrameCount.from_seconds(float(row['doortime'])))
        return Transition(ts, transition_id, transition_time)
Ejemplo n.º 14
0
    def read_from(sock, rooms, doors, read_ship_state=False):
        addresses = [
            (0x078D, 0x10),  # 0x78D to 0x79C
            (0x0998, 0x02),  # 0x998 to 0x999
            (0x09A4, 0x06),  # 0x9A4 to 0x9A9
            (0x09DA, 0x07),  # 0x9DA to 0x9E0
            (0xFB00, 0x20),  # 0xFB00 to 0xFB19
        ]

        if read_ship_state:
            addresses.extend([
                (0xD821, 0x01),
                (0x0FB2, 0x02),
            ])

        mem = SparseMemory.read_from(sock, *addresses)
        if mem is None:
            return None

        door_id = mem.short(0x78D)
        room_id = mem.short(0x79B)
        door = doors.from_id(door_id)
        room = rooms.from_id(room_id)

        game_state_id = mem.short(0x998)
        game_state = GameStates.get(game_state_id, hex(game_state_id))

        collected_items_bitmask = mem.short(0x9A4)
        collected_beams_bitmask = mem.short(0x9A8)

        igt_frames = mem.short(0x9DA)
        igt_seconds = mem[0x9DC]
        igt_minutes = mem[0x9DE]
        igt_hours = mem[0x9E0]
        fps = 60.0  # TODO
        igt = FrameCount(216000 * igt_hours + 3600 * igt_minutes +
                         60 * igt_seconds + igt_frames)

        if read_ship_state:
            event_flags = mem[0xD821]
            ship_ai = mem.short(0xFB2)
            reached_ship = (event_flags & 0x40) > 0 and ship_ai == 0xaa4f
        else:
            reached_ship = False

        # Practice hack
        ram_load_preset = mem.short(0x0FB00)
        gametime_room = FrameCount(mem.short(0x0FB02))
        last_gametime_room = FrameCount(mem.short(0x0FB04))
        realtime_room = FrameCount(mem.short(0x0FB06))
        last_realtime_room = FrameCount(mem.short(0x0FB08))
        last_room_lag = FrameCount(mem.short(0x0FB0A))
        last_door_lag_frames = FrameCount(mem.short(0x0FB0C))
        transition_counter = FrameCount(mem.short(0x0FB0E))
        last_realtime_door = FrameCount(mem.short(0x0FB12))
        seg_rt_frames = mem.short(0x0FB14)
        seg_rt_seconds = mem.short(0x0FB16)
        seg_rt_minutes = mem.short(0x0FB18)
        seg_rt = FrameCount(3600 * seg_rt_minutes + 60 * seg_rt_seconds +
                            seg_rt_frames)

        return State(
            door=door,
            room=room,
            game_state_id=game_state_id,
            game_state=game_state,
            igt=igt,
            seg_rt=seg_rt,
            gametime_room=gametime_room,
            last_gametime_room=last_gametime_room,
            realtime_room=realtime_room,
            last_realtime_room=last_realtime_room,
            last_realtime_door=last_realtime_door,
            last_room_lag=last_room_lag,
            last_door_lag_frames=last_door_lag_frames,
            transition_counter=transition_counter,
            ram_load_preset=ram_load_preset,
            items_bitmask='%x' % collected_items_bitmask,
            beams_bitmask='%x' % collected_beams_bitmask,
            items=items_string(imask=collected_items_bitmask),
            beams=beams_string(imask=collected_items_bitmask,
                               bmask=collected_beams_bitmask),
            reached_ship=reached_ship,
        )
Ejemplo n.º 15
0
            items_bitmask='%x' % collected_items_bitmask,
            beams_bitmask='%x' % collected_beams_bitmask,
            items=items_string(imask=collected_items_bitmask),
            beams=beams_string(imask=collected_items_bitmask,
                               bmask=collected_beams_bitmask),
            reached_ship=reached_ship,
        )


NullState = State(
    door=NullDoor,
    room=NullRoom,
    game_state=None,
    event_flags=0,
    ship_ai=0,
    igt=FrameCount(0),
    seg_rt=FrameCount(0),
    gametime_room=None,
    last_gametime_room=None,
    realtime_room=None,
    last_realtime_room=None,
    last_door_lag_frames=None,
    transition_counter=None,
    last_room_lag=None,
    ram_load_preset=None,
    items_bitmask=0,
    beams_bitmask=0,
    items=None,
    beams=None,
    reached_ship=False,
)
Ejemplo n.º 16
0
  parser.add_argument('--doors-only', action='store_true')
  args = parser.parse_args()

  rooms = Rooms.read(args.rooms_filename)
  doors = Doors.read(args.doors_filename, rooms)

  history = read_transition_log(args.filename, rooms, doors)
  route = Route()
  ids = build_route(history)
  all_stats = { }

  print('Timestamp,Room,Route Sum of Best,Route Sum of P25,Route Sum of P50,Route Sum of P75,Route Sum of P90')

  for transition, all_stats in progression_stats(args.filename, route,
      rooms, doors, start_room=args.start_room, end_room=args.end_room):

    p0 = FrameCount(sum([ s.best.count for s in all_stats.values() ]))
    p25 = FrameCount(sum([ s.p25.count for s in all_stats.values() ]))
    p50 = FrameCount(sum([ s.p50.count for s in all_stats.values() ]))
    p75 = FrameCount(sum([ s.p75.count for s in all_stats.values() ]))
    p90 = FrameCount(sum([ s.p90.count for s in all_stats.values() ]))

    print('%s,%s,%s,%s,%s,%s,%s' % (
      transition.ts,
      transition.id.room,
      round(p0.to_seconds(), 3),
      round(p25.to_seconds(), 3),
      round(p50.to_seconds(), 3),
      round(p75.to_seconds(), 3),
      round(p90.to_seconds(), 3)))
Ejemplo n.º 17
0
def print_room_stats(history, segment_history, segments):
  for segment in segments:
    print("Segment: \033[1m%s\033[m" % segment)

    table = Table()

    underline = 4
    header = [ Cell(s, underline) for s in ( 'Room', '#', '%', 'Median',
      'Best', 'Seg Median', 'Seg Best', 'Delta Median', 'Delta Best' ) ]
    table.append(header)

    total_p50 = FrameCount(0)
    total_p0 = FrameCount(0)
    total_p50_seg = FrameCount(0)
    total_p0_seg = FrameCount(0)

    for idx, tid in enumerate(segment):
      if not tid in segment_history:
        print("BUG? Could not find any attempts for %s in segment %s" % (tid, segment))
        continue

      if idx <= 1: segment_attempt_count = len(segment_history[tid])
      room_attempt_count = len(segment_history[tid])
      rate = room_attempt_count / segment_attempt_count

      p50 = history[tid].totalrealtimes.median()
      p0 = history[tid].totalrealtimes.best()
      seg_p50 = segment_history[tid].totalrealtimes.median()
      seg_p0 = segment_history[tid].totalrealtimes.best()

      total_p50 += p50
      total_p0 += p0
      total_p50_seg += seg_p50
      total_p0_seg += seg_p0

      table.append([
        Cell(tid.room.name),
        Cell(len(segment_history[tid]), justify='right'),
        Cell('%d%%' % (100 * rate), justify='right'),
        Cell(p50, justify='right'),
        Cell(p0, justify='right'),
        Cell(seg_p50, justify='right'),
        Cell(seg_p0, justify='right'),
        Cell(seg_p50 - p50, justify='right'),
        Cell(seg_p0 - p0, justify='right'),
      ])

    table.append([
      Cell('Total'),
      Cell('', justify='right'),
      Cell(''),
      Cell(total_p50, justify='right'),
      Cell(total_p0, justify='right'),
      Cell(total_p50_seg, justify='right'),
      Cell(total_p0_seg, justify='right'),
      Cell(total_p50_seg - total_p50, justify='right'),
      Cell(total_p0_seg - total_p0, justify='right'),
    ])

    print(table.render())
    print('')
Ejemplo n.º 18
0
def sum_of_best(segment, history):
  total = FrameCount(0)
  for tid in segment:
    total += history[tid].totalrealtimes.best()
  return total
Ejemplo n.º 19
0
        all_stats.append(
            transition_stats(id,
                             attempts,
                             iqr=args.iqr,
                             exclude_doors=args.exclude_doors,
                             doors_only=args.doors_only))

        if is_ceres_escape(id) and not args.doors_only:
            all_stats.append(ceres_cutscene_stats(id, attempts, args.iqr))

    if not args.exclude_doors:
        all_stats.append(door_stats(num_rooms, args.iqr))

    saves = [s.save.count for s in all_stats]
    p75_save = FrameCount(stats.scoreatpercentile(saves, 75))
    p90_save = FrameCount(stats.scoreatpercentile(saves, 90))

    table = Table()
    underline = '4'
    header = [
        Cell('Room', underline),
        Cell('N', underline),
        Cell('Best', underline),
        *([Cell('P25', underline)] if args.iqr else []),
        Cell('P50', underline),
        Cell('P75', underline),
        Cell('P90', underline),
        Cell('P75-P25' if args.iqr else 'P50-Best', underline),
        *([Cell('Most Recent', underline)] if args.most_recent else []),
        *([Cell('Most Recent-P50', underline)] if args.most_recent else []),
Ejemplo n.º 20
0
 def __init__(self, prev_state, state, current_room):
     self.prev_state = prev_state
     self.state = state
     self.is_room_change = state.game_state == 'NormalGameplay' and current_room is not state.room
     self.is_program_start = self.is_room_change and current_room is NullRoom
     self.transition_finished = state.game_state == 'NormalGameplay' and prev_state.game_state == 'DoorTransition'
     self.escaped_ceres = state.game_state == 'StartOfCeresCutscene' and prev_state.game_state == 'NormalGameplay' and state.room.name == 'Ceres Elevator'
     self.reached_ship = state.reached_ship and not prev_state.reached_ship
     self.is_reset = state.igt < prev_state.igt
     self.is_preset = state.game_state == 'NormalGameplay' and state.last_realtime_room == FrameCount(
         0) and state.room.name != 'Ceres Elevator'
     self.is_loading_preset = prev_state.ram_load_preset != state.ram_load_preset and state.ram_load_preset != 0
     self.door_changed = prev_state.door != state.door
     self.game_state_changed = prev_state.game_state != state.game_state
     self.is_playing = state.game_state_id >= 0x08 and state.game_state_id <= 0x18