class JustGo::PointSet

PointSet

A collection of Points with useful filtering functions

Attributes

points[R]

Public Class Methods

new(points: []) click to toggle source
# File lib/just_go/point_set.rb, line 15
def initialize(points: [])
  @points = case
    when !points.is_a?(Array)
      raise ArgumentError, 'points must be an array of Hash or Point'
    when points.all? { |p| p.is_a?(Hash) } 
      points.map { |p| JustGo::Point.new(**p) }
    when points.all? { |p| p.is_a?(JustGo::Point) }
      points
    else
      raise ArgumentError, 'points must be an array of Hash or Point'
    end
end

Public Instance Methods

adjacent(point_or_group) click to toggle source
# File lib/just_go/point_set.rb, line 69
def adjacent(point_or_group)
  case point_or_group
  when JustGo::Point
    select do |p| 
      vector = JustGo::Vector.new(point_or_group, p)
      vector.orthogonal? && vector.magnitude == 1
    end
  when JustGo::Chain
    _points = point_or_group.points.map do |p|
      adjacent(p).points
    end.flatten.reject do |p| 
      point_or_group.include?(p)
    end.uniq do |p|
      p.id
    end

    self.class.new(points: _points)
  when JustGo::Territory
    _points = point_or_group.points.map do |p|
      adjacent(p).points
    end.flatten.reject do |p| 
      point_or_group.include?(p)
    end.uniq do |p|
      p.id
    end

    self.class.new(points: _points)
  else
    raise ArgumentError, 'Must be Point or Chain or Territory'
  end
end
adjacent_chain_id(point, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 203
def adjacent_chain_id(point, player_number)
  adjacent(point).occupied_by(player_number).map { |p| p.stone.chain_id }.first
end
as_json() click to toggle source
# File lib/just_go/point_set.rb, line 36
def as_json
  points.map(&:as_json)
end
build_stone(point, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 211
def build_stone(point, player_number)
  JustGo::Stone.new(
    id: next_stone_id,
    player_number: player_number,
    chain_id: adjacent_chain_id(point, player_number) || next_chain_id
  )
end
capture_stones(player_number) click to toggle source
# File lib/just_go/point_set.rb, line 172
def capture_stones(player_number)
  stone_count = 0

  chains.select do |c| 
    c.player_number != player_number && liberties_for(c) == 0 
  end.each do |c| 
    c.points.each do |p|
      p.capture_stone
      stone_count += 1
    end  
  end
  
  stone_count
end
chains(chain_ids=nil) click to toggle source
# File lib/just_go/point_set.rb, line 116
def chains(chain_ids=nil)
  if chain_ids
    chain_ids.map do |c_id| 
      _points = select { |p| p.stone && p.stone.chain_id == c_id }.points
      JustGo::Chain.new(points: _points)
    end 
  else
    all_chain_ids = select { |p| p.stone }.map { |p| p.stone.chain_id }.uniq 
    chains(all_chain_ids)
  end
end
deprives_liberties?(point, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 148
def deprives_liberties?(point, player_number)
  chain_ids = adjacent(point).occupied_by(player_number).map { |p| p.stone.chain_id }.uniq
  _chains = chains(chain_ids)
  _chains.all? { |c| liberties_for(c) == 1 }
end
deprives_opponents_liberties?(point, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 154
def deprives_opponents_liberties?(point, player_number)
  chain_ids = adjacent(point).occupied_by_opponent(player_number).map { |p| p.stone.chain_id }.uniq
  _chains = chains(chain_ids)
  _chains.any? { |c| liberties_for(c) == 1 }
end
dup() click to toggle source
# File lib/just_go/point_set.rb, line 226
def dup
  self.class.new(points: as_json)
end
find_by_id(point_id) click to toggle source
# File lib/just_go/point_set.rb, line 45
def find_by_id(point_id)
  find { |p| p.id == point_id }
end
find_by_x_and_y(x, y) click to toggle source
# File lib/just_go/point_set.rb, line 49
def find_by_x_and_y(x, y)
  find { |p| p.x == x && p.y == y }
end
liberties_for(point_or_chain) click to toggle source
# File lib/just_go/point_set.rb, line 144
def liberties_for(point_or_chain)
  adjacent(point_or_chain).unoccupied.size
end
mark_territories() click to toggle source
# File lib/just_go/point_set.rb, line 230
def mark_territories
  points.each(&:clear_territory)
  points.each do |point|
    if point.unoccupied? && point.unmarked?
      territory_ids = adjacent(point).unoccupied.map(&:territory_id).compact
      add_territory_id = case territory_ids.size
      when 0
        (points.map(&:territory_id).compact.max || 0) + 1 
      when 1
        territory_ids.first
      else
        min_id, *other_ids = territory_ids.sort
        where(territory_id: other_ids).each do |other_point|
          other_point.add_to_territory(min_id)
        end
        min_id 
      end

      point.add_to_territory(add_territory_id) 
    end
  end
end
minify() click to toggle source
# File lib/just_go/point_set.rb, line 187
def minify
  points.map do |p|
    player_number = p.stone && p.stone.player_number
    player_number ? player_number.to_s : '-'
  end.join
end
next_chain_id() click to toggle source
# File lib/just_go/point_set.rb, line 207
def next_chain_id
  (occupied.map { |p| p.stone.chain_id }.max || 0) + 1
end
next_stone_id() click to toggle source
# File lib/just_go/point_set.rb, line 199
def next_stone_id
  (occupied.map { |p| p.stone.id }.max || 0) + 1
end
occupied() click to toggle source
# File lib/just_go/point_set.rb, line 53
def occupied
  select(&:occupied?)
end
occupied_by(player_number) click to toggle source
# File lib/just_go/point_set.rb, line 61
def occupied_by(player_number)
  select { |p| p.occupied_by?(player_number) }
end
occupied_by_opponent(player_number) click to toggle source
# File lib/just_go/point_set.rb, line 65
def occupied_by_opponent(player_number)
  select { |p| p.occupied_by_opponent?(player_number) }
end
perform_move(point, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 219
def perform_move(point, player_number)
  stone = build_stone(point, player_number)
  place(point.id, stone)
  update_joined_chains(point.id, player_number)
  capture_stones(player_number)
end
place(point_id, stone) click to toggle source
# File lib/just_go/point_set.rb, line 194
def place(point_id, stone)
  point = find_by_id(point_id)
  point.place(stone)
end
select(&block) click to toggle source
# File lib/just_go/point_set.rb, line 40
def select(&block)
  _points = points.select(&block) 
  self.class.new(points: _points)
end
territories(territory_ids=nil) click to toggle source
# File lib/just_go/point_set.rb, line 128
def territories(territory_ids=nil)
  if territory_ids
    territory_ids.map do |t_id|
      _points = select { |p| p.territory_id == t_id }.points
      JustGo::Territory.new(points: _points)
    end
  else
    all_territory_ids = select(&:territory_id).map(&:territory_id).uniq
    territories(all_territory_ids)
  end
end
territories_for(player_number) click to toggle source
# File lib/just_go/point_set.rb, line 140
def territories_for(player_number)
  territories.select { |t| adjacent(t).all? { |p| p.occupied_by?(player_number) } }
end
unoccupied() click to toggle source
# File lib/just_go/point_set.rb, line 57
def unoccupied
  select(&:unoccupied?)
end
update_joined_chains(point_id, player_number) click to toggle source
# File lib/just_go/point_set.rb, line 160
def update_joined_chains(point_id, player_number)
  point = find_by_id(point_id)
  existing_chain_ids = adjacent(point).occupied_by(player_number).map { |p| p.stone.chain_id }.uniq
  existing_chains = chains(existing_chain_ids)

  existing_chains.each do |c|
    c.points.each do |p|
      p.stone.join_chain(point.stone) 
    end
  end
end
where(args) click to toggle source
# File lib/just_go/point_set.rb, line 101
def where(args)
  scope = self
  args.each do |field, value|
    scope = scope.select do |p| 
      case value
      when Array
        value.include?(p.send(field))
      else
        p.send(field) == value 
      end
    end
  end
  scope
end