Class: Mjai::Manue::DangerEstimator::Scene

Inherits:
Object
  • Object
show all
Defined in:
lib/mjai/manue/danger_estimator.rb

Constant Summary collapse

@@feature_names =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Scene

Returns a new instance of Scene.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/mjai/manue/danger_estimator.rb', line 31

def initialize(params)
  
  if params[:game]
    params = params.dup()
    # Adds params[:dapai] because the game object points to the scene after the dapai.
    params[:tehais] = params[:me].tehais + (params[:dapai] ? [params[:dapai]] : [])
    params[:anpais] = params[:reacher].anpais
    params[:doras] = params[:game].doras
    params[:bakaze] = params[:game].bakaze
    params[:reacher_kaze] = params[:reacher].jikaze
    params[:visible] = []
    params[:visible] += params[:game].dora_markers
    params[:visible] += params[:me].tehais
    for player in params[:game].players
      params[:visible] += player.ho + player.furos.map(){ |f| f.pais }.flatten()
    end
  end
  
  prereach_sutehais = params[:prereach_sutehais]
  @tehai_set = to_pai_set(params[:tehais])
  @anpai_set = to_pai_set(params[:anpais])
  @visible_set = to_pai_set(params[:visible])
  @dora_set = to_pai_set(params[:doras])
  @bakaze = params[:bakaze]
  @reacher_kaze = params[:reacher_kaze]
  
  @prereach_sutehai_set = to_pai_set(prereach_sutehais)
  @early_sutehai_set = to_pai_set(prereach_sutehais[0...(prereach_sutehais.size / 2)])
  @late_sutehai_set = to_pai_set(prereach_sutehais[(prereach_sutehais.size / 2)..-1])
  # prereach_sutehais can be empty in unit tests.
  @reach_pai = prereach_sutehais[-1] ? prereach_sutehais[-1].remove_red() : nil
  
  @candidates = @tehai_set.keys.select(){ |pai| !@anpai_set.has_key?(pai) }
  
end

Instance Attribute Details

#candidatesObject (readonly)

Returns the value of attribute candidates.



67
68
69
# File 'lib/mjai/manue/danger_estimator.rb', line 67

def candidates
  @candidates
end

Class Method Details

.define_feature(name, &block) ⇒ Object



22
23
24
25
# File 'lib/mjai/manue/danger_estimator.rb', line 22

def self.define_feature(name, &block)
  define_method(name, &block)
  @@feature_names.push(name)
end

.feature_namesObject



27
28
29
# File 'lib/mjai/manue/danger_estimator.rb', line 27

def self.feature_names
  return @@feature_names
end

Instance Method Details

#anpai?(pai) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/mjai/manue/danger_estimator.rb', line 84

def anpai?(pai)
  return @anpai_set.has_key?(pai.remove_red())
end

#fanpai_fansu(pai) ⇒ Object



407
408
409
410
411
412
413
# File 'lib/mjai/manue/danger_estimator.rb', line 407

def fanpai_fansu(pai)
  if pai.type == "t" && pai.number >= 5
    return 1
  else
    return (pai == @bakaze ? 1 : 0) + (pai == @reacher_kaze ? 1 : 0)
  end
end

#feature_vector(pai) ⇒ Object

pai is without red. Use bit vector to make match? faster.



79
80
81
82
# File 'lib/mjai/manue/danger_estimator.rb', line 79

def feature_vector(pai)
  return DangerEstimator.bool_array_to_bit_vector(
      @@feature_names.map(){ |s| __send__(s, pai) })
end

#get_possible_sujis(pai) ⇒ Object

Uses the first pai to represent the suji. e.g. 1p for 14p suji



341
342
343
344
345
346
347
348
349
350
# File 'lib/mjai/manue/danger_estimator.rb', line 341

def get_possible_sujis(pai)
  if pai.type == "t"
    return []
  else
    ns = [pai.number - 3, pai.number].select() do |n|
      [n, n + 3].all?(){ |m| (1..9).include?(m) && !@anpai_set.include?(Pai.new(pai.type, m)) }
    end
    return ns.map(){ |n| Pai.new(pai.type, n) }
  end
end

#get_suji_numbers(pai) ⇒ Object



336
337
338
# File 'lib/mjai/manue/danger_estimator.rb', line 336

def get_suji_numbers(pai)
  return [pai.number - 3, pai.number + 3].select(){ |n| (1..9).include?(n) }
end

#matagisuji_of(pai, target_pai_set) ⇒ Object



389
390
391
392
393
394
395
396
# File 'lib/mjai/manue/danger_estimator.rb', line 389

def matagisuji_of(pai, target_pai_set)
  if pai.type == "t"
    return false
  else
    sujis = get_possible_sujis(pai)
    return sujis.any?(){ |s| target_pai_set.has_key?(s.next(1)) || target_pai_set.has_key?(s.next(2)) }
  end
end

#n_chance_or_less(pai, n) ⇒ Object



352
353
354
355
356
357
358
359
360
361
# File 'lib/mjai/manue/danger_estimator.rb', line 352

def n_chance_or_less(pai, n)
  if pai.type == "t" || (4..6).include?(pai.number)
    return false
  else
    return (1..2).any?() do |i|
      kabe_pai = Pai.new(pai.type, pai.number + (pai.number < 5 ? i : -i))
      @visible_set[kabe_pai] >= 4 - n
    end
  end
end

#n_or_more_of_neighbors_in_prereach_sutehais(pai, n, neighbor_distance) ⇒ Object



308
309
310
311
312
313
314
315
316
317
318
# File 'lib/mjai/manue/danger_estimator.rb', line 308

def n_or_more_of_neighbors_in_prereach_sutehais(pai, n, neighbor_distance)
  if pai.type == "t"
    return false
  else
    num_neighbors =
        ((pai.number - neighbor_distance)..(pai.number + neighbor_distance)).
        select(){ |n| @prereach_sutehai_set.has_key?(Pai.new(pai.type, n)) }.
        size
    return num_neighbors >= n
  end
end

#n_outer_prereach_sutehai(pai, n) ⇒ Object



297
298
299
300
301
302
303
304
305
306
# File 'lib/mjai/manue/danger_estimator.rb', line 297

def n_outer_prereach_sutehai(pai, n)
  if pai.type == "t"
    return false
  elsif pai.number < 6 - n || pai.number > 4 + n
    n_inner_pai = Pai.new(pai.type, pai.number < 5 ? pai.number + n : pai.number - n)
    return @prereach_sutehai_set.include?(n_inner_pai)
  else
    return false
  end
end

#num_n_or_inner(pai, n) ⇒ Object



363
364
365
# File 'lib/mjai/manue/danger_estimator.rb', line 363

def num_n_or_inner(pai, n)
  return pai.type != "t" && pai.number >= n && pai.number <= 10 - n
end

#outer(pai, target_pai_set) ⇒ Object



398
399
400
401
402
403
404
405
# File 'lib/mjai/manue/danger_estimator.rb', line 398

def outer(pai, target_pai_set)
  if pai.type == "t" || pai.number == 5
    return false
  else
    inner_numbers = pai.number < 5 ? ((pai.number + 1)..5) : (5..(pai.number - 1))
    return inner_numbers.any?(){ |n| target_pai_set.has_key?(Pai.new(pai.type, n)) }
  end
end

#senkisuji_of(pai, target_pai_set) ⇒ Object



380
381
382
383
384
385
386
387
# File 'lib/mjai/manue/danger_estimator.rb', line 380

def senkisuji_of(pai, target_pai_set)
  if pai.type == "t"
    return false
  else
    sujis = get_possible_sujis(pai)
    return sujis.any?(){ |s| target_pai_set.has_key?(s.next(-2)) || target_pai_set.has_key?(s.next(5)) }
  end
end

#suji_of(pai, target_pai_set) ⇒ Object



320
321
322
323
324
325
326
# File 'lib/mjai/manue/danger_estimator.rb', line 320

def suji_of(pai, target_pai_set)
  if pai.type == "t"
    return false
  else
    return get_suji_numbers(pai).all?(){ |n| target_pai_set.has_key?(Pai.new(pai.type, n)) }            
  end
end

#to_pai_set(pais) ⇒ Object



69
70
71
72
73
74
75
# File 'lib/mjai/manue/danger_estimator.rb', line 69

def to_pai_set(pais)
  pai_set = Hash.new(0)
  for pai in pais
    pai_set[pai.remove_red()] += 1
  end
  return pai_set
end

#urasuji_of(pai, target_pai_set) ⇒ Object



371
372
373
374
375
376
377
378
# File 'lib/mjai/manue/danger_estimator.rb', line 371

def urasuji_of(pai, target_pai_set)
  if pai.type == "t"
    return false
  else
    sujis = get_possible_sujis(pai)
    return sujis.any?(){ |s| target_pai_set.has_key?(s.next(-1)) || target_pai_set.has_key?(s.next(4)) }
  end
end

#visible_n_or_more(pai, n) ⇒ Object



367
368
369
# File 'lib/mjai/manue/danger_estimator.rb', line 367

def visible_n_or_more(pai, n)
  return @visible_set[pai] >= n
end

#weak_suji_of(pai, target_pai_set) ⇒ Object



328
329
330
331
332
333
334
# File 'lib/mjai/manue/danger_estimator.rb', line 328

def weak_suji_of(pai, target_pai_set)
  if pai.type == "t"
    return false
  else
    return get_suji_numbers(pai).any?(){ |n| target_pai_set.has_key?(Pai.new(pai.type, n)) }
  end
end