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



65
66
67
68
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
# File 'lib/just_go/point_set.rb', line 65

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



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

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



207
208
209
210
211
212
213
# File 'lib/just_go/point_set.rb', line 207

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



168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/just_go/point_set.rb', line 168

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



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/just_go/point_set.rb', line 112

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)


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

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)


150
151
152
153
154
# File 'lib/just_go/point_set.rb', line 150

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



222
223
224
# File 'lib/just_go/point_set.rb', line 222

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

#liberties_for(point_or_chain) ⇒ Object



140
141
142
# File 'lib/just_go/point_set.rb', line 140

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

#mark_territoriesObject



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/just_go/point_set.rb', line 226

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



183
184
185
186
187
188
# File 'lib/just_go/point_set.rb', line 183

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



203
204
205
# File 'lib/just_go/point_set.rb', line 203

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

#next_stone_idObject



195
196
197
# File 'lib/just_go/point_set.rb', line 195

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

#occupiedObject



49
50
51
# File 'lib/just_go/point_set.rb', line 49

def occupied
  select(&:occupied?)
end

#occupied_by(player_number) ⇒ Object



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

def occupied_by(player_number)
  select { |p| p.occupied_by?(player_number) }
end

#occupied_by_opponent(player_number) ⇒ Object



61
62
63
# File 'lib/just_go/point_set.rb', line 61

def occupied_by_opponent(player_number)
  select { |p| p.occupied_by_opponent?(player_number) }
end

#perform_move(point, player_number) ⇒ Object



215
216
217
218
219
220
# File 'lib/just_go/point_set.rb', line 215

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



190
191
192
193
# File 'lib/just_go/point_set.rb', line 190

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



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/just_go/point_set.rb', line 124

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



136
137
138
# File 'lib/just_go/point_set.rb', line 136

def territories_for(player_number)
  territories.select { |t| adjacent(t).all? { |p| p.occupied_by?(player_number) } }
end

#unoccupiedObject



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

def unoccupied
  select(&:unoccupied?)
end

#update_joined_chains(point_id, player_number) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/just_go/point_set.rb', line 156

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



97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/just_go/point_set.rb', line 97

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