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.



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/just_go/point_set.rb', line 14

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.



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

def points
  @points
end

Instance Method Details

#adjacent(point_or_group) ⇒ Object



64
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
# File 'lib/just_go/point_set.rb', line 64

def adjacent(point_or_group)
  case point_or_group
  when JustGo::Point
    select do |p| 
      vector = 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



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

def adjacent_chain_id(point, player_number)
  adjacent(point).occupied_by(player_number).map { |p| p.stone.chain_id }.first
end

#as_jsonObject



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

def as_json
  points.map(&:as_json)
end

#build_stone(point, player_number) ⇒ Object



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

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



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

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



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

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:



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

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:



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

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



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

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

#find_by_id(point_id) ⇒ Object



44
45
46
# File 'lib/just_go/point_set.rb', line 44

def find_by_id(point_id)
  find { |p| p.id == point_id }
end

#liberties_for(point_or_chain) ⇒ Object



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

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

#mark_territoriesObject



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

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



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

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



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

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

#next_stone_idObject



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

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

#occupiedObject



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

def occupied
  select(&:occupied?)
end

#occupied_by(player_number) ⇒ Object



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

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

#occupied_by_opponent(player_number) ⇒ Object



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

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

#perform_move(point, player_number) ⇒ Object



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

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



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

def place(point_id, stone)
  point = find_by_id(point_id)
  point.place(stone)
end

#select(&block) ⇒ Object



39
40
41
42
# File 'lib/just_go/point_set.rb', line 39

def select(&block)
  _points = points.select(&block) 
  self.class.new(points: _points)
end

#territories(territory_ids = nil) ⇒ Object



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

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



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

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

#unoccupiedObject



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

def unoccupied
  select(&:unoccupied?)
end

#update_joined_chains(point_id, player_number) ⇒ Object



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

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



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

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