class SorterBase

Attributes

player_position_map[R]

todo:remove for avoid sync errors (can't add key during iteration)

players_ids[R]
players_locker[R]
players_resources_map[R]
sort_criteria_non_players[RW]
top_size[RW]

properties

Public Class Methods

new() click to toggle source

methods

# File lib/mrpin/core/utils/sorter_base.rb, line 46
def initialize
  @top_size = 100

  @sort_criteria_non_players = 0

  # ordered player_ids
  @players_ids               = []
  # key player_id, value - position
  @player_position_map       = {}
  # key - player_id, value - player specify resource count
  @players_resources_map     = {}

  @players_locker = Mutex.new
end

Public Instance Methods

add_player(player, sort_criteria_value = 0) click to toggle source

manager players

# File lib/mrpin/core/utils/sorter_base.rb, line 287
def add_player(player, sort_criteria_value = 0)
  @players_locker.synchronize do
    add_player_unsafe(player, sort_criteria_value)
  end
end
delete_player(player) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 320
def delete_player(player)
  @players_locker.synchronize do
    player_id = player.id

    position_old = @player_position_map[player.id]

    return if position_old.nil?

    @players_ids.delete_at(position_old - 1)
    @players_resources_map.delete(player_id)
    @player_position_map.delete(player_id)

    update_player_positions(position_old, @players_ids.size)

    if position_old <= @top_size
      position_new       = [@players_ids.size + 1, @top_size + 1].max
      resource_count_new = 0

      on_player_left_from_top(player, position_old, position_new, resource_count_new)
    end
  end
end
get_player_info(player_id) click to toggle source

return {

player_id:
sort_criteria:
position:

}

# File lib/mrpin/core/utils/sorter_base.rb, line 226
def get_player_info(player_id)
  result = nil

  @players_locker.synchronize do
    return result unless @player_position_map.key?(player_id)

    result = get_player_info_unsafe(player_id)
  end

  result
end
get_player_position_total(player) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 208
def get_player_position_total(player)
  result = 0

  @players_locker.synchronize do
    result = @player_position_map[player.id]
  end

  result
end
get_players_ids(position_start = 0, position_end = nil) click to toggle source

methods for get info

# File lib/mrpin/core/utils/sorter_base.rb, line 197
def get_players_ids(position_start = 0, position_end = nil)
  result = nil

  @players_locker.synchronize do
    result = get_players_ids_unsafe(position_start, position_end)
  end

  result
end
get_players_infos(position_start = 0, position_end = nil) click to toggle source

return array of {

player_id:
sort_criteria:
position:

}

# File lib/mrpin/core/utils/sorter_base.rb, line 263
def get_players_infos(position_start = 0, position_end = nil)

  result = []

  @players_locker.synchronize do

    players_ids = get_players_ids_unsafe(position_start, position_end)

    players_ids.each do |player_id|
      player_info = get_player_info_unsafe(player_id)

      result << player_info
    end

  end

  result
end
init_sorter(sort_criteria_map) click to toggle source

init sorter with start data sort_criteria_map - map with key - player_id, value - sort criteria

# File lib/mrpin/core/utils/sorter_base.rb, line 64
def init_sorter(sort_criteria_map)
  @players_ids = sort_criteria_map.keys.dup

  @players_ids.sort_by! do |id|
    sort_criteria_map[id]
  end

  @players_ids.reverse!

  @player_position_map = Hash[@players_ids.map.with_index(index_offset = 1).to_a]

  @players_resources_map = sort_criteria_map.dup
end
try_update_position(player, sort_criteria_value) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 115
def try_update_position(player, sort_criteria_value)
  player_came_to_top   = false
  player_left_from_top = false

  player_id = player.id

  if player.respond_to?(:is_player?) && !player.is_player?
    sort_criteria_value = @sort_criteria_non_players
  end

  @players_locker.synchronize do

    #add player if he doesn't exist
    if @player_position_map[player_id].nil?
      add_player_unsafe(player, sort_criteria_value)
      return
    end

    sort_criteria_old = @players_resources_map[player_id]

    return if sort_criteria_value == sort_criteria_old

    find_position_up = sort_criteria_value > sort_criteria_old

    position_old = @player_position_map[player_id]
    position_new = find_new_position(sort_criteria_value, position_old, find_position_up)

    if position_new > position_old
      # need because player already in top
      position_new -= 1
    end

    @players_resources_map[player_id] = sort_criteria_value

    player_in_top = position_new <= @top_size

    if position_new != position_old

      player_came_to_top   = position_old > @top_size && position_new <= @top_size
      player_left_from_top = position_old <= @top_size && position_new > @top_size

      @players_ids.delete_at(position_old - 1)
      @players_ids.insert(position_new - 1, player_id)

      update_player_positions(position_new, position_old)
    end

    if player_came_to_top
      on_player_came_to_top(player, position_old, position_new, sort_criteria_value)
    elsif player_left_from_top
      on_player_left_from_top(player, position_old, position_new, sort_criteria_value)
    elsif player_in_top #invalidate top player
      on_player_top_updated(player, position_old, position_new, sort_criteria_value)
    else #usual player, just invalidate online friends
      on_player_updated(player, position_old, position_new, sort_criteria_value)
    end

  end

  nil
end

Protected Instance Methods

add_player_unsafe(player, sort_criteria_value = 0) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 294
def add_player_unsafe(player, sort_criteria_value = 0)
  player_id           = player.id

  sort_criteria_value = 0 if sort_criteria_value.nil?

  return if @players_resources_map.empty?
  return unless @player_position_map[player_id].nil?

  index_position = @players_ids.size

  while index_position > 0 && sort_criteria_value > @players_resources_map[@players_ids[index_position - 1]]
    index_position -= 1
  end

  @players_ids.insert(index_position, player_id)
  @players_resources_map[player_id] = sort_criteria_value
  @player_position_map[player_id]   = index_position + 1

  update_player_positions(index_position + 1, @players_ids.size)

  if index_position < @top_size
    on_player_came_to_top(player, nil, index_position + 1, sort_criteria_value)
  end
end
find_new_position(resource_count, player_position_old, find_up) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 79
def find_new_position(resource_count, player_position_old, find_up)

  if find_up
    index_left  = 0
    index_right = player_position_old - 1
  else
    index_left  = player_position_old - 1
    index_right = @players_ids.size - 1
  end

  while index_left <= index_right
    median_index = (index_right + index_left) / 2

    player_median_resources = @players_resources_map[@players_ids[median_index]]

    if resource_count > player_median_resources
      index_right = median_index - 1
    elsif resource_count == player_median_resources

      index_left = median_index

      while resource_count == player_median_resources
        index_left              = index_left + 1
        player_median_resources = @players_resources_map[@players_ids[index_left]]
      end

      break
    else
      index_left = median_index + 1
    end
  end

  index_left + 1
end
on_player_came_to_top(player, position_old, position_new, resource_count_new) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 27
def on_player_came_to_top(player, position_old, position_new, resource_count_new)
  #do nothing
end
on_player_left_from_top(player, position_old, position_new, resource_count_new) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 32
def on_player_left_from_top(player, position_old, position_new, resource_count_new)
  #do nothing
end
on_player_top_updated(player, position_old, position_new, resource_count_new) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 37
def on_player_top_updated(player, position_old, position_new, resource_count_new)
  #do nothing
end
on_player_updated(player, position_old, position_new, resource_count_new) click to toggle source

events

# File lib/mrpin/core/utils/sorter_base.rb, line 22
def on_player_updated(player, position_old, position_new, resource_count_new)
  #do nothing
end
update_player_positions(position_new, position_old) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 178
def update_player_positions(position_new, position_old)

  position_start = [position_new, position_old].min
  position_end   = [position_new, position_old].max

  (position_start..position_end).each do |position|

    player_id = @players_ids[position - 1]

    @player_position_map[player_id] = position

  end
end

Private Instance Methods

get_player_info_unsafe(player_id) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 239
def get_player_info_unsafe(player_id)
  {
      player_id:     player_id,
      position:      @player_position_map[player_id],
      sort_criteria: @players_resources_map[player_id]
  }
end
get_players_ids_unsafe(position_start, position_end) click to toggle source
# File lib/mrpin/core/utils/sorter_base.rb, line 248
def get_players_ids_unsafe(position_start, position_end)
  position_end = position_end || (@top_size - 1)

  position_end = @players_ids.size if position_end < 0

  result = @players_ids[position_start..position_end]
end