foot_stats_simulator 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,34 @@
1
1
  class SimulatorPlayer < ActiveRecord::Base
2
+ belongs_to :simulator_team
3
+
4
+ def to_foot_stats
5
+ {
6
+ '@Id' => self.source_id,
7
+ '@Nome' => self.full_name,
8
+ '@Apelido' => self.nickname
9
+ }
10
+ end
11
+
12
+ def self.to_foot_stats
13
+ # FootStats suck!
14
+ # Yes, it's stupid, but it's true...
15
+ # FootStats doesn't return a collection on this...
16
+ if count == 0
17
+ nil
18
+ else
19
+ if count == 1
20
+ self.first.to_foot_stats
21
+ else
22
+ { 'Equipe' => all.map(&:to_foot_stats) }
23
+ end
24
+ end
25
+ end
26
+
2
27
  def self.dump!
3
28
  SimulatorTeam.all.each do |team|
4
29
  FootStats::Player.all(team: team.source_id).each do |foot_stats_player|
5
30
  player = self.find_or_create_by_source_id foot_stats_player.source_id
6
- player.update_attributes foot_stats_player.attributes
31
+ player.update_attributes foot_stats_player.attributes.merge(simulator_team_id: team.id)
7
32
  end
8
33
  end
9
34
  end
@@ -1,9 +1,27 @@
1
1
  class SimulatorTeam < ActiveRecord::Base
2
+ has_many :simulator_championship_participations
3
+ has_many :simulator_championships, through: :simulator_championship_participations
4
+ has_many :simulator_players
5
+
6
+ def to_foot_stats
7
+ {
8
+ '@Id' => self.source_id,
9
+ '@Nome' => self.full_name,
10
+ '@Cidade' => self.city,
11
+ '@Pais' => self.country
12
+ }
13
+ end
14
+
15
+ def self.to_foot_stats
16
+ { 'Equipe' => all.map(&:to_foot_stats) }
17
+ end
18
+
2
19
  def self.dump!
3
20
  SimulatorChampionship.all.each do |championship|
4
21
  FootStats::Team.all(championship: championship.source_id).each do |foot_stats_team|
5
22
  team = self.find_or_create_by_source_id foot_stats_team.source_id
6
23
  team.update_attributes foot_stats_team.attributes
24
+ SimulatorChampionshipParticipation.find_or_create_by_simulator_team_id_and_simulator_championship_id team.id, championship.id
7
25
  end
8
26
  end
9
27
  end
@@ -1,111 +1,103 @@
1
- class SimulatorTimeline < ActiveRecord::Base
2
- belongs_to :match
1
+ # TODO: Handle penalties
2
+
3
+ class SimulatorTimeline
4
+ attr_reader :match
3
5
 
4
6
  attr_accessor :states, :current_period, :current_minute
5
- attr_accessor :narration, :home_goals, :home_cards, :home_players, :visitor_goals, :visitor_cards, :visitor_players
7
+ attr_accessor :narration, :home_goals, :home_cards, :current_home_players, :visitor_goals, :visitor_cards, :current_visitor_players
6
8
 
7
- def period(period)
8
- if block_given?
9
- yield Period.new(self, period)
10
- else
11
- Period.new(self, period_time)
12
- end
9
+ def initialize(match, timeline_name)
10
+ @match = match
11
+ @timeline_path = File.expand_path File.join(FootStatsSimulator.timelines_dir, "#{timeline_name}.rb")
12
+ load_timeline
13
13
  end
14
14
 
15
- def current_period_time
16
- SimulatorMatch::STATUS_SEQUENCE[current_period] || current_period.to_i
15
+ def timeline_rand(limit = nil)
16
+ @random.rand limit
17
17
  end
18
18
 
19
- def transitions
20
- states = States.new self
21
- yield(states)
22
- states.set_current
19
+ def sample(collection)
20
+ collection[timeline_rand(collection.size)]
23
21
  end
24
22
 
25
- def setup
26
- @narration = []
27
- @home_goals = []
28
- @home_cards = []
29
- @home_players = []
30
- @visitor_goals = []
31
- @visitor_cards = []
32
- @visitor_players = []
33
- yield(self)
23
+ def collection_of(n, collection)
24
+ collecteds = []
25
+ while collecteds.size < n
26
+ collected = sample(collection)
27
+ collecteds << collected unless collecteds.include?(collected)
28
+ end
29
+ collecteds
34
30
  end
35
31
 
36
- class States
37
- def initialize(timeline)
38
- @timeline = timeline
39
- @timeline.states = []
40
- end
32
+ def home_score
33
+ home_goals.count{ |g| g.type == 'Favor' } + visitor_goals.count{ |g| g.type != 'Favor' }
34
+ end
41
35
 
42
- def set_current
43
- delta = (Time.now - @timeline.match.scheduled_start).to_i
44
- period = @timeline.states.find{|minute, status| delta > minute }[1]
36
+ def visitor_score
37
+ visitor_goals.count{ |g| g.type == 'Favor' } + home_goals.count{ |g| g.type != 'Favor' }
38
+ end
45
39
 
46
- @timeline.current_period = period
40
+ def home_team
41
+ @match.home_team
42
+ end
47
43
 
48
- @timeline.current_minute if period.to_s.match(/(period|prorrogation)/)
49
- started_second = @timeline.states.find{ |minute, status| status == period }[0]
50
- ((Time.now - @timeline.match.scheduled_start) + started_second).from_now
51
- else
52
- 0
53
- end
54
- end
44
+ def visitor_team
45
+ @match.visitor_team
46
+ end
55
47
 
56
- def add_transition(status, time)
57
- @timeline.states << [time, status]
58
- @timeline.sort!
59
- end
48
+ def home_players
49
+ @home_players ||= @match.home_simulator_team.simulator_players.order(:source_id)
50
+ end
60
51
 
61
- def method_missing(method_name, *args, &block)
62
- if SimulatorMatch::STATUS_SEQUENCE[method_name]
63
- add_transition(method_name, args.first)
64
- else
65
- super(method_name, *args, &block)
66
- end
67
- end
52
+ def visitor_players
53
+ @visitor_players ||= @match.visitor_simulator_team.simulator_players.order(:source_id)
68
54
  end
69
55
 
70
- class Period
71
- def initialize(timeline, period)
72
- @timeline, @period = timeline, period
73
- end
56
+ def all_current_players
57
+ current_home_players + current_visitor_players
58
+ end
74
59
 
75
- def period_time
76
- SimulatorMatch::STATUS_SEQUENCE[@period] || @period.to_i
77
- end
60
+ def all_players
61
+ home_players + visitor_players
62
+ end
78
63
 
79
- def at(minute)
80
- if block_given?
81
- yield Minute.new(@timeline, period_time, @minute)
82
- else
83
- Minute.new(@timeline, period_time, @minute)
84
- end
85
- end
64
+ def update_match
65
+ @match.update_attributes status: current_period,
66
+ home_score: home_score,
67
+ home_penalties_score: nil,
68
+ visitor_score: visitor_score,
69
+ visitor_penalties_score: nil
86
70
  end
87
71
 
88
- class Minute
89
- def initialize(timeline, minute)
90
- @timeline, @minute = timeline, minute
91
- end
72
+ def transitions(&block)
73
+ States.new(self, &block)
74
+ end
92
75
 
93
- def event(type, *args)
94
- [@timeline, @minute, type, args]
76
+ def period(period)
77
+ if block_given?
78
+ yield Period.new(self, period)
79
+ else
80
+ Period.new(self, period_time)
95
81
  end
82
+ end
96
83
 
97
- def add_home_goal(player_source_id, type = 'Favor', reference = nil)
98
- @timeline.home_goals << event(:goal, player_source_id, type, reference)
99
- end
84
+ def current_period_time
85
+ SimulatorMatch::STATUS_SEQUENCE[current_period] || current_period.to_i
86
+ end
100
87
 
101
- def add_visitor_goal(player_source_id, type = 'Favor', reference = nil)
102
- @timeline.visitor_goals << event(:goal, player_source_id, type, reference)
103
- end
88
+ protected
89
+ def load_timeline
90
+ @random = Random.new @match.timeline_random_seed
104
91
 
105
- def remove_goal(reference)
106
- @timeline.home_goals.delete_all do |period, minute, type, *args|
107
- type == goal && args[2] == reference
108
- end
109
- end
92
+ @states = []
93
+ @narration = []
94
+ @home_goals = []
95
+ @home_cards = []
96
+ @current_home_players = []
97
+ @visitor_goals = []
98
+ @visitor_cards = []
99
+ @current_visitor_players = []
100
+
101
+ eval File.read(@timeline_path)
110
102
  end
111
103
  end
@@ -0,0 +1,41 @@
1
+ class SimulatorTimeline
2
+ class CardEvent < SimulatorTimeline::Event
3
+ attr_reader :player, :type, :reference
4
+
5
+ def initialize(event_handler, timeline, period_time, minute, options = {})
6
+ @player, @type, @reference = options.values_at :player, :type, :reference
7
+ @type ||= :yellow
8
+ super(event_handler, timeline, period_time, minute, options)
9
+ end
10
+
11
+ def to_foot_stats
12
+ {
13
+ "@Jogador" => @player.full_name,
14
+ "@Periodo" => SimulatorMatch::STATUS_MAP[SimulatorMatch::STATUSES[@period_time]],
15
+ "@Minuto" => @minute.to_s,
16
+ "@Tipo" => @type
17
+ }
18
+ end
19
+
20
+ def self.remove(timeline, reference)
21
+ timeline.home_cards.delete_if{ |event| event.reference == reference }
22
+ timeline.visitor_cards.delete_if{ |event| event.reference == reference }
23
+ end
24
+
25
+ def self.to_foot_stats(array_of_cards)
26
+ fuck_collection 'Cartoes', array_of_cards.map(&:to_foot_stats)
27
+ end
28
+
29
+ protected
30
+ def apply_event
31
+ if @player.simulator_team == @timeline.home_team
32
+ @timeline.home_cards << self
33
+ else
34
+ @timeline.visitor_cards << self
35
+ end
36
+
37
+ card_kind = (@type == :yellow) ? 'amarelo' : 'vermelho'
38
+ event_handler.narration :card, current_player: @player.nickname, card_kind: card_kind
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ class SimulatorTimeline
2
+ class Event
3
+ attr_reader :period_time, :minute, :event_handler
4
+
5
+ def initialize(event_handler, timeline, period_time, minute, options = {})
6
+ @event_handler, @timeline, @period_time, @minute = event_handler, timeline, period_time, minute
7
+ apply_event
8
+ end
9
+
10
+ def <=>(other)
11
+ [@period_time, @minute] <=> [other.period_time, other.minute]
12
+ end
13
+
14
+ # Yeah... FootStats fucks collection...
15
+ def self.fuck_collection(key, collection)
16
+ case collection.size
17
+ when 0
18
+ nil
19
+ when 1
20
+ { key => collection.first }
21
+ else
22
+ { key => collection }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,69 @@
1
+ class SimulatorTimeline
2
+ class EventHandler
3
+ def initialize(timeline, period_time, minute)
4
+ @timeline, @period_time, @minute = timeline, period_time, minute
5
+ end
6
+
7
+ def add_goal(player, options={})
8
+ options = { player: player }.merge(options)
9
+ GoalEvent.new self, @timeline, @period_time, @minute, options
10
+ end
11
+
12
+ def remove_goal(reference)
13
+ GoalEvent.remove @timeline, reference
14
+ end
15
+
16
+ def add_card(player, options={})
17
+ options = { player: player }.merge(options)
18
+ CardEvent.new self, @timeline, @period_time, @minute, options
19
+ end
20
+
21
+ def add_yellow_card(player, options={})
22
+ options = { player: player, type: :yellow }.merge(options)
23
+ add_card player, options
24
+ end
25
+
26
+ def add_red_card(player, options={})
27
+ options = { player: player, type: :red }.merge(options)
28
+ add_card player, options
29
+ end
30
+
31
+ def remove_card(reference)
32
+ CardEvent.remove @timeline, reference
33
+ end
34
+
35
+ def escalation(players)
36
+ players.each do |player|
37
+ self.player(player)
38
+ end
39
+ end
40
+
41
+ def player(player, options={})
42
+ options = { player: player }.merge(options)
43
+ PlayerEvent.new self, @timeline, @period_time, @minute, options
44
+ end
45
+
46
+ def remove_player(reference)
47
+ PlayerEvent.remove @timeline, reference
48
+ end
49
+
50
+ def narration(message_name = :lorem, options = {})
51
+ message = if message_name.is_a?(String)
52
+ message_name
53
+ else
54
+ message = Lorem.new(@timeline, @period_time, @minute, options).public_send message_name
55
+ end
56
+ options = { message: message }.merge(options)
57
+ NarrationEvent.new self, @timeline, @period_time, @minute, options
58
+ end
59
+
60
+ def remove_narration(reference)
61
+ NarrationEvent.remove @timeline, reference
62
+ end
63
+
64
+ protected
65
+ def event(type, *args)
66
+ [@period_time, @minute, type, args]
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,40 @@
1
+ class SimulatorTimeline
2
+ class GoalEvent < SimulatorTimeline::Event
3
+ attr_reader :player, :type, :reference
4
+
5
+ def initialize(event_handler, timeline, period_time, minute, options = {})
6
+ @player, @type, @reference = options.values_at :player, :type, :reference
7
+ @type ||= 'Favor'
8
+ super(event_handler, timeline, period_time, minute, options)
9
+ end
10
+
11
+ def to_foot_stats
12
+ {
13
+ "@Jogador" => @player.full_name,
14
+ "@Periodo" => SimulatorMatch::STATUS_MAP[SimulatorMatch::STATUSES[@period_time]],
15
+ "@Minuto" => @minute.to_s,
16
+ "@Tipo" => @type
17
+ }
18
+ end
19
+
20
+ def self.remove(timeline, reference)
21
+ timeline.home_goals.delete_if{ |event| event.reference == reference }
22
+ timeline.visitor_goals.delete_if{ |event| event.reference == reference }
23
+ end
24
+
25
+ def self.to_foot_stats(array_of_goals)
26
+ fuck_collection 'Gol', array_of_goals.map(&:to_foot_stats)
27
+ end
28
+
29
+ protected
30
+ def apply_event
31
+ if @player.simulator_team == @timeline.home_team
32
+ @timeline.home_goals << self
33
+ else
34
+ @timeline.visitor_goals << self
35
+ end
36
+
37
+ event_handler.narration :goal, current_player: @player.nickname, player_team: @player.simulator_team.full_name
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ class SimulatorTimeline
2
+ class Lorem
3
+ attr_reader :timeline, :period_time, :minute
4
+ include LoremMessages
5
+
6
+ def initialize(timeline, period_time, minute, options = {})
7
+ @timeline, @period_time, @minute, @options = timeline, period_time, minute, options
8
+ end
9
+
10
+ def method_missing(method_name, *args, &block)
11
+ return render(@options[method_name]) if @options[method_name]
12
+ return render(send("#{method_name}_message", *args, &block)) if respond_to?("#{method_name}_message")
13
+ return @timeline.public_send(method_name, *args, &block) if @timeline.respond_to?(method_name)
14
+ super(method_name, *args, &block)
15
+ end
16
+
17
+ protected
18
+ def render(sentence)
19
+ normalized_sentence = sentence.is_a?(String) ? sentence : sample(sentence)
20
+ eval Erubis::Eruby.new(normalized_sentence).src, binding
21
+ end
22
+ end
23
+ end