def find_phase_number_between_ball_and_wheel(
         time_of_ball_in_front_of_mark, time_of_wheel_in_front_of_mark,
         wheel_revolution_time, way):
     diff_time = np.abs(time_of_ball_in_front_of_mark -
                        time_of_wheel_in_front_of_mark)
     numbers_count = len(Wheel.NUMBERS)
     idx_phase = int(
         np.round((diff_time / wheel_revolution_time * numbers_count)))
     idx_zero = Wheel.find_index_of_number(0)  # Should be always 0
     if time_of_ball_in_front_of_mark > time_of_wheel_in_front_of_mark:
         #  t(Wheel) < t(Ball) Wheel is ahead of phase
         #  The question is: what is the value of the wheel when the ball
         #  is in front of the mark?
         if way == Wheel.WheelWay.CLOCKWISE:
             idx = idx_zero - idx_phase
         elif way == Wheel.WheelWay.ANTICLOCKWISE:
             idx = idx_zero + idx_phase
         else:
             raise Exception('Unknown type.')
     else:
         #  t(Wheel) > t(Ball) Ball is ahead of phase
         #  The question is what is the value of the ball when the wheel
         #  is in front of the wheel?
         if way == Wheel.WheelWay.CLOCKWISE:
             idx = idx_zero + idx_phase
         elif way == Wheel.WheelWay.ANTICLOCKWISE:
             idx = idx_zero - idx_phase
         else:
             raise Exception('Unknown type.')
     return Wheel.NUMBERS[Wheel.get_index(idx)]
def next_batch(debug=True):
    circ = 0.85 * np.pi
    cutoff_speed = 1.0
    rev_time = 3  # units of time.
    init_max_time_value_first_ball_time = 1.0

    # BALL PART
    abs_ball_times, abs_cutoff_time = generate_abs_times(
        circ, cutoff_speed, init_max_time_value_first_ball_time)
    Wheel.find_index_of_number(0)
    abs_ball_times -= abs_ball_times[0]

    # WHEEL PART
    initial_number = np.random.choice(Wheel.NUMBERS)  # at time = 0
    abs_wheel_times = generate_wheel_abs_times(rev_time,
                                               initial_number,
                                               max_len=len(abs_ball_times))
    numbers = []
    for abs_ball_time in np.append(abs_ball_times, abs_cutoff_time):
        abs_wheel_time = Helper.get_last_time_wheel_is_in_front_of_ref(
            abs_wheel_times, abs_ball_time)
        if abs_wheel_time is None:
            numbers.append(None)
        else:
            num = get_real_number(abs_ball_time, abs_wheel_time, rev_time)
            assert num == get_number(abs_ball_time - abs_wheel_time, 0,
                                     rev_time)
            numbers.append(num)
    number_landmark_number_cutoff = numbers[-1]
    ball_distance_travelled = distance_travelled(abs_ball_times[-1],
                                                 abs_cutoff_time, neg_exp)
    ball_cutoff_shift = (ball_distance_travelled % circ) / circ * len(
        Wheel.NUMBERS)
    number_cutoff = Wheel.get_number_with_shift(number_landmark_number_cutoff,
                                                ball_cutoff_shift,
                                                Wheel.WheelWay.CLOCKWISE)

    numbers = np.array(numbers)[:-1]
    # ball_lap_times = np.diff(abs_ball_times)
    # wheel_lap_times = np.diff(abs_wheel_times)
    # cutoff_lap_time = abs_cutoff_time - abs_ball_times[-1]
    # number_cutoff = get_number(abs_cutoff_time, initial_number, rev_time)
    if debug:
        print('-' * 80)
        print('ABSOLUTE BALL TIMES    =', abs_ball_times)
        print('ABSOLUTE WHEEL TIMES   =', abs_wheel_times)
        print('ABS CUTOFF TIME        =', abs_cutoff_time)
        print('NUMBERS                =', numbers)
        print('NUMBER CUTOFF          =', number_cutoff)
    # plot_a(ball_diff_times)
    # sleep(0.1)
    return {
        'abs_ball_times': abs_ball_times,
        'abs_wheel_times': abs_wheel_times,
        'abs_cutoff_time': abs_cutoff_time,
        'numbers': np.array(numbers),
        'number_cutoff': number_cutoff
    }
def next_batch(debug=True):
    circ = 0.85 * np.pi
    rev_time = 3  # units of time.
    init_max_time_value_first_ball_time = 2.0  # 1 second max after t = 0.

    # BALL PART
    abs_ball_times, abs_cutoff_time = generate_abs_times(
        circ, init_max_time_value_first_ball_time)
    Wheel.find_index_of_number(0)
    abs_ball_times -= abs_ball_times[0]

    # WHEEL PART
    initial_number = np.random.choice(Wheel.NUMBERS)  # at time = 0
    abs_wheel_times = generate_wheel_abs_times(rev_time,
                                               initial_number,
                                               max_len=len(abs_ball_times))
    numbers = []
    for abs_ball_time in np.append(abs_ball_times, abs_cutoff_time):
        abs_wheel_time = Helper.get_last_time_wheel_is_in_front_of_ref(
            abs_wheel_times, abs_ball_time)
        if abs_wheel_time is None:
            numbers.append(None)
        else:
            numbers.append(
                get_real_number(abs_ball_time, abs_wheel_time, rev_time))
    number_cutoff = numbers[-1]
    numbers = np.array(numbers)
    # ball_lap_times = np.diff(abs_ball_times)
    # wheel_lap_times = np.diff(abs_wheel_times)
    # cutoff_lap_time = abs_cutoff_time - abs_ball_times[-1]
    # number_cutoff = get_number(abs_cutoff_time, initial_number, rev_time)
    if debug:
        print('-' * 80)
        print('ABSOLUTE BALL TIMES    =', abs_ball_times)
        # print('BALL LAP TIMES         =', ball_lap_times)
        print('ABSOLUTE WHEEL TIMES   =', abs_wheel_times)
        # print('BALL WHEEL TIMES       =', wheel_lap_times)
        # print('CUTOFF DIFF TIME       =', cutoff_lap_time)
        print('ABS CUTOFF TIME        =', abs_cutoff_time)
        print('NUMBERS                =', numbers)
        print('NUMBER CUTOFF          =', number_cutoff)
    # plot_a(ball_diff_times)
    # sleep(0.1)
    return {
        'abs_ball_times': abs_ball_times,
        # 'ball_lap_times': ball_lap_times,
        'abs_wheel_times': abs_wheel_times,
        # 'wheel_lap_times': wheel_lap_times,
        # 'cutoff_lap_time': cutoff_lap_time,
        'abs_cutoff_time': abs_cutoff_time,
        'numbers': np.array(numbers),
        'number_cutoff': number_cutoff
    }
예제 #4
0
def generate_wheel_abs_times(rev_time, initial_number, max_len):
    # initial number already reflects the position of the wheel at the t=0 for the ball.
    cur_time = 0
    abs_times = []
    shift = -1
    for ii in range(len(Wheel.NUMBERS)):
        number = Wheel.get_number_with_shift(initial_number, ii, Wheel.WheelWay.CLOCKWISE)
        if number == 0:
            shift = ii
            break
    assert shift != -1
    cur_time += (shift / len(Wheel.NUMBERS)) * rev_time
    abs_times.append(cur_time)
    for jj in range(max_len):
        cur_time += rev_time
        abs_times.append(cur_time)
    return np.array(abs_times)
def get_number(t, initial_number, rev_time):
    res_t = t % rev_time
    shift_to_add = res_t * len(Wheel.NUMBERS)
    return Wheel.get_number_with_shift(initial_number, shift_to_add,
                                       Wheel.WheelWay.CLOCKWISE)
예제 #6
0
    def predict(ball_recorded_times, wheel_recorded_times, debug=True):
        # Last measurement is when the ball hits the diamond ring.
        ts_list = np.array(PredictorPhysics.LAP_TIMES_ALL_GAMES_LIST.copy())
        dr_list = np.array(PredictorPhysics.DIAMOND_RING_ALL_GAMES_LIST.copy())

        if ts_list is None or dr_list is None:
            raise CriticalException(
                'Cache is not initialized. Call load_cache().')

        ts_list = TimeSeriesMerger.merge(ts_list)
        ts_mean = np.nanmean(ts_list, axis=0)

        last_time_ball_passes_in_front_of_ref = ball_recorded_times[-1]
        last_wheel_lap_time_in_front_of_ref = Helper.get_last_time_wheel_is_in_front_of_ref(
            wheel_recorded_times, last_time_ball_passes_in_front_of_ref)
        log(
            'ref time of the prediction = {0:.2f}s'.format(
                last_time_ball_passes_in_front_of_ref), debug)
        ball_lap_times = np.diff(ball_recorded_times)
        wheel_lap_times = np.diff(wheel_recorded_times)
        ball_loop_count = len(ball_lap_times)

        index_of_rev_start = Helper.find_abs_start_index(
            ball_lap_times, ts_mean)
        log('index_of_rev_start = {}'.format(index_of_rev_start), debug)
        index_of_last_recorded_time = ball_loop_count + index_of_rev_start

        matched_game_indices = TimeSeriesMerger.find_nearest_neighbors(
            ball_lap_times,
            ts_list,
            index_of_rev_start,
            neighbors_count=Constants.NEAREST_NEIGHBORS_COUNT)
        log('matched_game_indices = {}'.format(matched_game_indices), debug)

        estimated_time_left = np.mean(
            np.sum(ts_list[matched_game_indices, index_of_last_recorded_time:],
                   axis=1))
        estimated_time_left += np.mean(dr_list[matched_game_indices], axis=0)
        log('estimated_time_left = {0:.2f}s'.format(estimated_time_left),
            debug)

        if estimated_time_left <= 0:
            raise PositiveValueExpectedException(
                'estimated_time_left must be positive.')

        # biased estimator but still it should work here.
        max_residual_time = np.max(dr_list)

        # if we have [0, 0, 1, 2, 3, 0, 0], index_of_rev_start = 2
        # rem_loops is actually useless to compute :)
        rem_loops = ts_list[matched_game_indices,
                            index_of_last_recorded_time:].shape[1]

        rem_res_loop = np.mean(
            dr_list[matched_game_indices] /
            max_residual_time)  # we should calibrate it more.
        number_of_revolutions_left_ball = rem_loops + rem_res_loop

        # TODO: for later.
        # we need to have a better approximation of:
        # We can maybe fit an ARIMA on the Abs Ball times
        # or get rem_res_loop accurate.

        if number_of_revolutions_left_ball <= 0:
            error_msg = 'rem_loops = {0:.2f}, rem_res_loop = {0:.2f}.'.format(
                rem_loops, rem_res_loop)
            raise PositiveValueExpectedException(
                'number_of_revolutions_left_ball must be positive.' +
                error_msg)

        log(
            'number_of_revolutions_left_ball = {0:.2f}'.format(
                number_of_revolutions_left_ball), debug)

        # the time values are always taken at the same diamond.
        diamond = Diamonds.detect_diamonds(number_of_revolutions_left_ball)
        log('diamond to be hit = {}'.format(diamond), debug)

        if diamond == Diamonds.DiamondType.BLOCKER:
            expected_bouncing_shift = Constants.EXPECTED_BOUNCING_SHIFT_BLOCKER_DIAMOND
        else:
            expected_bouncing_shift = Constants.EXPECTED_BOUNCING_SHIFT_FORWARD_DIAMOND

        shift_ball_cutoff = (number_of_revolutions_left_ball % 1) * len(
            Wheel.NUMBERS)
        time_at_cutoff_ball = last_time_ball_passes_in_front_of_ref + estimated_time_left

        if time_at_cutoff_ball < last_time_ball_passes_in_front_of_ref + Constants.SECONDS_NEEDED_TO_PLACE_BETS:
            raise PositiveValueExpectedException()

        wheel_last_revolution_time = wheel_lap_times[-1]
        # We want to find the number of the wheel where the ball passes in front of the mark.
        initial_number = Phase.find_phase_number_between_ball_and_wheel(
            last_time_ball_passes_in_front_of_ref,
            last_wheel_lap_time_in_front_of_ref, wheel_last_revolution_time,
            Constants.DEFAULT_WHEEL_WAY)

        shift_between_initial_time_and_cutoff = (
            (estimated_time_left / wheel_last_revolution_time) % 1) * len(
                Wheel.NUMBERS)

        # Explanation:
        # shift_between_initial_time_and_cutoff - let's not focus on the ball. What is the configuration of the wheel
        # at the cutoff time, i.e. estimated_time_left seconds later.
        # shift_ball_cutoff - the ball is also moving during this time. Let's not focus on the wheel. Where is the ball
        # compared to the wheel at the cutoff time. We imagine that the wheel is fixed.
        # We then add the two quantities (composition of the kinetics) to know about the real shift.
        shift_to_add = shift_ball_cutoff + shift_between_initial_time_and_cutoff
        predicted_number_cutoff = Wheel.get_number_with_shift(
            initial_number, shift_to_add, Constants.DEFAULT_WHEEL_WAY)
        log(
            'shift_between_initial_time_and_cutoff = {0:.2f}'.format(
                shift_between_initial_time_and_cutoff), debug)
        log('shift_ball_cutoff = {0:.2f}'.format(shift_ball_cutoff), debug)
        log('predicted_number_cutoff = {}'.format(predicted_number_cutoff),
            debug)
        log('expected_bouncing_shift = {}'.format(expected_bouncing_shift),
            debug)
        shift_to_add += expected_bouncing_shift
        predicted_number = Wheel.get_number_with_shift(
            initial_number, shift_to_add, Constants.DEFAULT_WHEEL_WAY)
        log('predicted_number is = {}'.format(predicted_number), debug)
        return predicted_number_cutoff, predicted_number