From: Simeon Willbanks Date: 2009-10-21T02:24:45+09:00 Subject: Please Review My First Ruby Program I've written a simple program to simulate a Soccer game. Its the first full program I've written in Ruby, so please forgive any obvious mistakes. :) In advance, thanks for your comments. It requires Ruby 1.9. Please run the unit tests to see the program in action. Simeon $ ruby TestSoccerGame.rb --- ### TestSoccerGame.rb require "SoccerGame" require "test/unit" class TestSoccerGame < Test::Unit::TestCase # M辿s que un club FC_BARCELONA = { 'club' => 'FC Barcelona', 'players' => [ [1, 'Victor Valdes Arribas', :keeper], [20, 'Daniel Alves da Silva', :defender], [3, 'Gerard Pique Bernabeu', :defender], [4, 'Rafael Marquez Alvarez', :defender], [5, 'Carles Puyol Saforcada', :defender], [6, 'Xavier Hernandez Creus', :midfielder], [8, 'Andres Iniesta Lujan', :midfielder], [15, 'Seydou Keita', :midfielder], [9, 'Zlatan Ibrahimovic', :striker], [10, 'Lionel Andres Messi', :striker], [14, 'Thierry Henry', :striker] ] } # You'll Never Walk Alone LIVERPOOL_FC = { 'club' => 'Liverpool FC', 'players' => [ [25, 'Pepe Reina', :keeper], [2, 'Glen Johnson', :defender], [23, 'Jamie Carragher', :defender], [37, 'Martin Skrtel', :defender], [22, 'Emiliano Insua', :defender], [20, 'Javier Mascherano',:midfielder], [8, 'Steven Gerrard', :midfielder], [11, 'Albert Riera', :midfielder], [15, 'Yossi Benayoun', :midfielder], [9, 'Fernando Torres', :striker], [18, 'Dirk Kuyt', :striker] ] } def setup if RUBY_VERSION.to_f < 1.9 flunk("SoccerGame requires Ruby 1.9 or greater") end # @g used for all tests except full game test @g = SoccerGame.new FC_BARCELONA, LIVERPOOL_FC end # Full game test def test_champions_league_final @f = SoccerGame.new FC_BARCELONA, LIVERPOOL_FC @f.title = "UEFA Champions League Final" # Starting lineups assert @f.home assert @f.away assert_equal 11, @f.home.players.length assert_equal 11, @f.away.players.length # Kickoff assert @f.events(:first_half_kickoff) assert @f.first_half assert_equal false, @f.second_half # Show Alves yellow assert_block "Dani Alves" do @f.yellow_card(:home, 20) end assert_equal 1, @f.yellow_cards[:home].length # El Nino sneaks one in @f.goal(:away, 9) assert_equal 1, @f.score[:away] assert_equal 1, @f.goals[:away][9] # Halftime assert @f.events(:half_time) assert_equal false, @f.first_half assert_equal false, @f.second_half # Start second half assert @f.events(:second_half_kickoff) assert @f.second_half assert_equal false, @f.first_half # Show Skrtel red away_team_length = @f.away.players.length assert_block "Skrtel wasn't sent to the showers" do @f.red_card(:away, 37) end assert_equal away_team_length-1, @f.away.players.length assert_equal 1, @f.red_cards[:away].length # Xavi ties the match @f.goal(:home, 6) assert_equal 1, @f.score[:home] assert_equal 1, @f.goals[:home][6] # Messi seals the victory @f.goal(:home, 10) assert_equal 2, @f.score[:home] assert_equal 1, @f.goals[:home][10] # Fulltime assert @f.events(:final) assert_equal false, @f.second_half assert_equal false, @f.first_half # Champions League Final stats puts @f.stats end # A home and away team are required def test_home_away assert @g.home assert @g.away end # Both home and away teams must have 11 players def test_starting_lineups assert_equal 11, @g.home.players.length assert_equal 11, @g.away.players.length end # Positions normally have at least a certian number players def test_players_per_position assert_equal 1, @g.home.keepers.length assert_operator 3, :<=, @g.home.defenders.length assert_operator 3, :<=, @g.home.midfielders.length assert_operator 1, :<=, @g.home.strikers.length assert_equal 1, @g.away.keepers.length assert_operator 3, :<=, @g.away.defenders.length assert_operator 3, :<=, @g.away.midfielders.length assert_operator 1, :<=, @g.away.strikers.length end def test_first_half_kickoff assert @g.events(:first_half_kickoff) assert @g.first_half assert_equal false, @g.second_half end def test_half_time assert @g.events(:half_time) assert_equal false, @g.first_half assert_equal false, @g.second_half end def test_second_half_kickoff assert @g.events(:second_half_kickoff) assert @g.second_half assert_equal false, @g.first_half end def test_final_whistle assert @g.events(:final) assert_equal false, @g.second_half assert_equal false, @g.first_half end def test_cards # Show Pique yellow assert_block "Pique isn't cautioned" do @g.yellow_card(:home, 3) end assert_equal 1, @g.yellow_cards[:home].length # Show Skrtel red away_team_length = @g.away.players.length assert_block "Skrtel wasn't sent to the showers" do @g.red_card(:away, 37) end assert_equal away_team_length-1, @g.away.players.length assert_equal 1, @g.away.showers.length assert_equal 1, @g.red_cards[:away].length # Show Pique second yellow then red home_team_length = @g.home.players.length assert_block "Pique wasn't sent off" do @g.yellow_card(:home, 3) end assert_equal home_team_length-1, @g.home.players.length assert_equal 1, @g.red_cards[:home].length end def test_scoring_a_goals # Messi opens the scoring @g.goal(:home, 10) assert_equal 1, @g.score[:home] assert_equal 1, @g.goals[:home][10] # El Nino sneaks one in @g.goal(:away, 9) assert_equal 1, @g.score[:away] assert_equal 1, @g.goals[:away][9] # Ibra is so smooth @g.goal(:home, 9) assert_equal 2, @g.score[:home] assert_equal 1, @g.goals[:home][9] # Messi seals the victory @g.goal(:home, 10) assert_equal 3, @g.score[:home] assert_equal 2, @g.goals[:home][10] end end ### SoccerGame.rb require "SoccerTeam" require "SoccerStats" class SoccerGame attr_accessor :title attr_reader :home, :away, :yellow_cards, :red_cards, :clock, :score, :goals, :first_half, :second_half def initialize(home, away) @home = SoccerTeam.new(home['club'],home['players']) @away = SoccerTeam.new(away['club'],away['players']) @yellow_cards = {:home => [], :away => []} @red_cards = {:home => [], :away => []} @score = {:home => 0, :away => 0} @goals = {:home => {}, :away => {}} @first_half = false @second_half = false end def stats s = SoccerStats.new stats = "\n"+s.title(self.title) stats << s.teams(@home.club, @away.club) stats << s.final_score(@score[:home], @score[:away]) stats << "\n"+s.cards(:yellow, @yellow_cards[:away], @away) stats << s.cards(:yellow, @yellow_cards[:home], @home) stats << s.cards(:red, @red_cards[:away], @away) stats << s.cards(:red, @red_cards[:home], @home) stats << s.scorers(@goals, @home, @away) stats end def events(whistle) case whistle when :first_half_kickoff then @first_half = true when :half_time then @first_half = false when :second_half_kickoff then @second_half = true when :final then @second_half = false end @clock = Time.now.to_i end def count_players_on_pitch msg = "team doesn't have the right number of players on the pitch" if @home.players.length != 11 raise "Home" + msg elsif @away.players.length != 11 raise "Away" + msg end end def yellow_card(team, player) # Second yellow card so, show a red if @yellow_cards[team].index(player) @yellow_cards[team].push player red_card(team, player) else @yellow_cards[team].push player end end def red_card(team, player) @red_cards[team].push player if team == :home # Send player to the showers @home.showers[player] = @home.players[player] @home.players.delete(player) else @away.showers[player] = @away.players[player] @away.players.delete(player) end end def goal(team, player) @score[team] += 1 if @goals[team][player] @goals[team][player] += 1 else @goals[team][player] = 1 end end end ### SoccerTeam.rb class SoccerTeam attr_accessor :showers attr_reader :club, :players, :keepers, :defenders, :midfielders, :strikers def initialize(club, players) @club = club @players = {} @keepers = {} @defenders = {} @midfielders = {} @strikers = {} @showers = {} players.each do |number, name, position| @players[number] = name # Push player into position case position when :keeper then @keepers[number] = name when :defender then @defenders[number] = name when :midfielder then @midfielders[number] = name when :striker then @strikers[number] = name end end end end ### SoccerStats.rb class SoccerStats def title(name) self.own_line(name) end def teams(home,away) self.own_line(away+" visiting "+home) end def final_score(home,away) self.own_line(away.to_s+" / "+home.to_s) end def cards(type, cards, team) str = "" if !cards.empty? if (type == :yellow) str << "Yellow" # Player hasn't been deleted from the team # He was only shown a yellow card player_hash = team.players else str << "Red" # Player was deleted from the team # He was shown a red card player_hash = team.showers end str << " Cards:\n" cards.each do |number| str << number.to_s+"/"+player_hash[number]+"/"+team.club+"\n" end str = self.own_line(str) end str end def scorers(goals, home, away) str = "" if !goals.empty? # Loop through each teams' goals, and print player number, name and goals scored {:home=>home,:away=>away}.each do |key, team| if goals.has_key?(key) goals[key].each do |number, goals| str << number.to_s+"/"+team.players[number]+"/"+team.club+" scores "+goals.to_s+" goal" if goals > 1 str << "s" end str << "\n" end end end str = self.own_line("Goals:")+self.own_line(str) end str end def own_line(str) str+"\n" end end -- Posted via http://www.ruby-forum.com/.