Class: JustGo::PointSet

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/just_go/point_set.rb

Overview

PointSet

A collection of Points with useful filtering functions

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(points: []) ⇒ PointSet

Returns a new instance of PointSet.



15
16
17
18
19
20
21
22
23
24
25
26
# 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

Instance Attribute Details

#pointsObject (readonly)

Returns the value of attribute points.



28
29
30
# File 'lib/just_go/point_set.rb', line 28

def points
  @points
end

Instance Method Details

#adjacent(point_or_group) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 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) ⇒ Object



203
204
205
# 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_jsonObject



36
37
38
# File 'lib/just_go/point_set.rb', line 36

def as_json
  points.map(&:as_json)
end

#build_stone(point, player_number) ⇒ Object



211
212
213
214
215
216
217
# 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) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
# 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) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# 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) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
152
# 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) ⇒ Boolean

Returns:

  • (Boolean)


154
155
156
157
158
# 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

#dupObject



226
227
228
# File 'lib/just_go/point_set.rb', line 226

def dup
  self.class.new(points: as_json)
end

#find_by_id(point_id) ⇒ Object



45
46
47
# 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) ⇒ Object



49
50
51
# 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) ⇒ Object



144
145
146
# File 'lib/just_go/point_set.rb', line 144

def liberties_for(point_or_chain)
  adjacent(point_or_chain).unoccupied.size
end

#mark_territoriesObject



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# 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

#minifyObject



187
188
189
190
191
192
# 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_idObject



207
208
209
# 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_idObject



199
200
201
# File 'lib/just_go/point_set.rb', line 199

def next_stone_id
  (occupied.map { |p| p.stone.id }.max || 0) + 1
end

#occupiedObject



53
54
55
# File 'lib/just_go/point_set.rb', line 53

def occupied
  select(&:occupied?)
end

#occupied_by(player_number) ⇒ Object



61
62
63
# 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) ⇒ Object



65
66
67
# 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) ⇒ Object



219
220
221
222
223
224
# 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) ⇒ Object



194
195
196
197
# 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) ⇒ Object



40
41
42
43
# 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) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
# 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) ⇒ Object



140
141
142
# 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

#unoccupiedObject



57
58
59
# File 'lib/just_go/point_set.rb', line 57

def unoccupied
  select(&:unoccupied?)
end

#update_joined_chains(point_id, player_number) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
# 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) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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