Demo entry 1487256

Ruby

   

Submitted by anonymous on Apr 21, 2015 at 11:25
Language: Ruby. Code size: 11.9 kB.

# Data o programatorech. Speed udava kolik clovekodni
# programator odpracuje za den. Daily_wage je denni mzda.
programmers = [
  {:name => "Martin", :speed => 1.9, :daily_wage => 2000},
  {:name => "Jarda", :speed => 1.0, :daily_wage => 1300},
  {:name => "Lukas", :speed => 0.6, :daily_wage => 900},
  {:name => "Pepa", :speed => 1.7, :daily_wage => 2200},
  {:name => "Kamil", :speed => 0.4, :daily_wage => 1800},
  {:name => "Honza", :speed => 1.3, :daily_wage => 1500},
  {:name => "Filip", :speed => 1.1, :daily_wage => 1000}
]

# Data o firmach. Capacity udava kolik programatoru muze firma najmout
# Daily_expenses jsou firemni denni fixni naklady
companies = [
  {:name => "Alpha", :capacity => 2, :daily_expenses => 1000, :budget => 90000},
  {:name => "Beta", :capacity => 2, :daily_expenses => 1500, :budget => 100000},
  {:name => "Gamma", :capacity => 3, :daily_expenses => 3000, :budget => 200000},
  {:name => "Delta", :capacity => 5, :daily_expenses => 6000, :budget => 400000},
  {:name => "Epsilon", :capacity => 6, :daily_expenses => 8000, :budget => 900000},
  {:name => "Theta", :capacity => 7, :daily_expenses => 10000, :budget => 1200000},
  {:name => "Omega", :capacity => 7, :daily_expenses => 20000, :budget => 20000000}
]

# Data o projektech. Man days je pocet clovekodni ktere se musi na
# projektu odpracovat. Price je castka kterou firma obdrzi pri dokonceni
projects = [
  {:name => "Web", :man_days => 5.0, :price => 20000},
  {:name => "Portal", :man_days => 15.0, :price => 60000},
  {:name => "Email system", :man_days => 25.0, :price => 90000},
  {:name => "Eshop", :man_days => 40.0, :price => 150000},
  {:name => "CMS", :man_days => 60.0, :price => 250000},
  {:name => "Forum", :man_days => 30.0, :price => 35000},
  {:name => "B2B System", :man_days => 120.0, :price => 800000},
  {:name => "Multimedia Web", :man_days => 7.0, :price => 50000},
  {:name => "TODO List", :man_days => 3.0, :price => 10000},
  {:name => "CRM", :man_days => 20.0, :price => 80000}
]


class Programmer
  attr_reader :name, :speed, :daily_wage
  attr_accessor :project

  def initialize(name, speed, daily_wage)
    @name = name
    @speed = speed
    @daily_wage = daily_wage
    @project = nil
  end

  # Uvolnit programatora z projektu
  def clear_project
    @project = nil
  end

  # Pracovat na projektu
  def write_code
    @project.receive_work(@speed)
  end

  # Vypise nazev prirazeneho projektu, nebo retezec "nil",
  # kdyz zadny projekt prirazen neni
  def project_name
    return project.nil? ? "nil" : project.name
  end

  # Slouzi pouze pro ladici ucely. Vypise dulezite informace o danem programatorovi.
  def print_debug_info
    puts "Programmer #{name}:"
    puts "\tSpeed: #{speed}"
    puts "\tDaily wage: #{daily_wage}"
    puts "\tProject: #{project_name}"
  end
end

class Project
  attr_reader :name, :man_days, :price
  attr_reader :man_days_done
  attr_accessor :state #moznosti :waiting, :current, :done

  def initialize(name, man_days, price)
    @name = name
    @man_days = man_days
    @man_days_done = 0
    @price = price
    @state = :waiting
  end

  # Prace, kterou programator provede na projektu
  def receive_work(man_days)
    @man_days_done += man_days
  end

  # Slouzi pouze pro ladici ucely. Vypise dulezite informace o danem projektu.
  def print_debug_info
    puts "Project #{name}:"
    puts "\tState: #{state}"
    puts "\tMan-days total: #{man_days}"
    puts "\tMan-days done: #{man_days_done}"
    puts "\tPrice: #{price}"
  end
end

class Company
  attr_reader :name, :capacity, :daily_expenses, :budget
  attr_reader :days, :programmers
  attr_reader :projects_waiting, :projects_current, :projects_done
  attr_reader :state # moznosti :idle, :running, :finished, :bankrupt

  def initialize(name, capacity, daily_expenses, budget)
    @name = name
    @capacity = capacity
    @daily_expenses = daily_expenses
    @budget = budget
    @state = :idle
    @days = 0
    @projects_waiting = []
    @projects_current = []
    @projects_done = []
  end

  # Nacist vsechny projekty do pole @projects_waiting
  def allocate_projects(projects_array)
    projects_array.each do |proj|
      @projects_waiting << Project.new(proj[:name], proj[:man_days], proj[:price])
    end
  end

  # Najmout tolik programatoru, kolik cini kapacita
  def allocate_programmers(programmers_array)
    # IMPLEMENTUJTE TUTO METODU
    # Z pole programmers_array vyberte prvnich @capacity programatoru
    # v poradi podle nejvyhodnejsiho pomeru jejich rychlosti proti jejich cene.
    # Nasledne v tomto poradi vytvarejte prislusne instance tridy Programmer
    # a vytvorene objekty vkladejte do pole @programmers.

    sorted_programmers_array = programmers_array.sort_by { |programmer|  programmer[:speed]/programmer[:daily_wage]}.reverse
    @programmers = []
    @capacity.times do |i|
      @programmers << Programmer.new(sorted_programmers_array[i][:name], sorted_programmers_array[i][:speed],sorted_programmers_array[i][:daily_wage])      
    end
  end
    
    
    
    

  # Zjistit ktere projekty jsou uz hotove
  # a presunout je do @projects_done
  def check_projects
    # Nasledujici kod si vyzaduje urcitou pozornost a vysvetleni komentarem. Jeho smyslem je z pole @projects_current
    # odebrat vsechny projekty, ktere jsou jiz hotove (pocet odpracovanych dni je vetsi nebo roven poctu dni potrebnemu
    # k dokonceni projektu) a tyto projekty umistit do pomocneho pole currently_done.
    # V podmince bloku metody reject! vyuzivame toho, ze pokud jeste neni odpracovan dostatecny pocet dni, bude hned
    # prvni cast podminky vyhodnocena jako false a diky zkracenemu vyhodnocovani vyrazu se druha cast podminky vubec
    # neprovede. V pripade, ze uz je odpracovano dostatecne mnozstvi dni, pridani zkoumaneho projektu do currently_done
    # se provede a vyslednou hodnotou celeho bloku bude objekt currently_done samotny, coz v podminkovem kontextu
    # znamena pravdivou hodnotu, a tedy projekt bude metodou reject! odebran z @projects_current.
    # Pokud vam takovato konstrukce pripada ponekud slozita a nepruhledna, nevadi, muzete si predstavit, ze bychom
    # misto toho pouzili nasledujici kod -- vysledek by byl stejny:
    # currently_done = @projects_current.select { |project| project.man_days_done >= project.man_days }
    # @projects_current.reject! { |project| project.man_days_done >= project.man_days }
    currently_done = []
    @projects_current.reject! { |project| project.man_days_done >= project.man_days && currently_done << project }

    currently_done.each do |project|
      project.state = :done
      @projects_done << project
      @budget += project.price
    end
  end

  # Uvolnit programatory, co delaji na projektech,
  # ktere uz jsou hotove.
  def check_programmers
    # IMPLEMENTUJTE TUTO METODU
    @programmers.each do |programmer|
      if programmer.project != nil
        if programmer.project.man_days_done >= programmer.project.man_days
          programmer.clear_project
        end  
      end  
    end
  end
  
  # Nastavit projekty programatorum, kteri jsou volni.
  def assign_new_projects
    # IMPLEMENTUJTE TUTO METODU
    # Pro kazdeho volneho programatora hledejte projekt k prideleni nasledovne:
    # - Pokud existuje nejaky projekt v @projects_waiting, vyberte prvni takovy.
    #   (Nezapomente mu zmenit stav a presunout jej do @projects_current.)
    # - Pokud ne, vyberte takovy projekt z @projects_current, na kterem zbyva
    #   nejvice nedodelane prace.
    
    @programmers.each do |p|    # pro kazdeho volneho programatora      
      if p.project == nil  # kdyz nema prirazeny zadny projekt a tim padem je volny
        if !(@projects_waiting.empty?) # pokud jsou cekajici projekty - jeste neprirazene
          p.project = @projects_waiting[0] #prirad projekt programatorovi
          @projects_current << @projects_waiting[0]   # prida prvni prvek z waiting do current - zacne se na tom delat
          @projects_waiting.shift   #vyhodi prvni prvek z pole
        elsif !(@projects_current.empty?) #pokud existuji nedokoncene bezici projekty
          #priradit programatorovi nejmene dokonceny projekt
          p.project = projects_current.max_by {|proj| proj.man_days-proj.man_days_done}  
        end
      end
    end
  end

  # Programatori pracuji.
  def programmers_work
    # IMPLEMENTUJTE TUTO METODU
    # Projdete vsechny programatory a predejte jejich denni vykon projektum,
    # ktere maji pridelene.
    # Zaroven snizte aktualni stav financi firmy o jejich denni mzdu a rovnez
    # o denni vydaje firmy.
    @programmers.each do |programmer|
      if programmer.project != nil
        programmer.write_code
        @budget -= programmer.daily_wage
      end  
    end
    @budget -= @daily_expenses
  end

  # Zjistit stav spolecnosti.
  def check_company_state
    # IMPLEMENTUJTE TUTO METODU
    # Pokud je aktualni stav financi firmy zaporny, nastavte
    # stav spolecnosti na :bankrupt.
    # Pokud ne a zaroven pokud jsou jiz vsechny projekty hotovy,
    # nastavte stav spolecnosti na :finished.
    if @budget < 0
      @state = :bankrupt
    elsif (@projects_current.empty?) & (@projects_waiting.empty?)
      @state = :finished
    end  
  end

  # Spusteni simulace. Cyklus se ukonci kdyz je stav firmy
  # :bankrupt nebo :finished, nebo pokud simulace bezi vice nez 1000 dni
  def run
    @state = :running
    #print_debug_info
    while @state != :bankrupt and @state != :finished and @days <= 1000
      @days += 1
      assign_new_projects
      programmers_work
      check_programmers
      check_projects
      check_company_state

      # odkomentovani nasledujicich radku zpusobi vypsani velmi podrobnych informaci
      # o stavu spolecnosti na konci kazdeho dne
      # puts
      
      #puts "-------- Loop ------- #{days}"
      #print_debug_info
    end
    @state = :idle if @state == :running
    #print_debug_info
  end

  def output_result
    puts
    puts "Company name #{name}"
    puts "Days running #{@days}"
    puts "Final budget #{@budget}"
    puts "Final state #{@state}"
    puts "Number of projects done #{@projects_done.size}"
  end

  # Slouzi pouze pro ladici ucely. Vypise dulezite informace o danem projektu,
  # vcetne seznamu zamestnanych programatoru a seznamu cekajicich, zpracovavanych a zpracovanych projektu.
  # U zpracovavanych a zpracovanych projektu vypise i podrobnosti o techto projektech.
  def print_debug_info
    puts "Company #{name}, day #{days}:"
    puts "\tState: #{state}"
    puts "\tCurrent cash flow: #{budget}"
    puts "\tDaily expenses: #{daily_expenses}"
    puts "\tCapacity: #{capacity}"
    puts "\tProgrammers: #{programmers.collect { |programmer| programmer.name + " (" + programmer.project_name + ")" }.join(", ")}"
    puts "\tPROJECTS WAITING: #{projects_waiting.collect { |project| project.name }.join(", ")}"
    puts "\tPROJECTS CURRENT:"
    projects_current.each { |project| project.print_debug_info }
    puts "\tPROJECTS DONE:"
    projects_done.each { |project| project.print_debug_info }
  end
end

company_objects = []
companies.each do |c|
  # Vytvorit objekty typu Company a priradit do company_objects
  company_objects << Company.new(c[:name],c[:capacity],c[:daily_expenses],c[:budget])
end

# Tento cyklus se opakuje pro kazdou firmu
company_objects.each do |c|
  
  # Prijmout programatory
  c.allocate_programmers(programmers)
  
  # Nacist projekty
  c.allocate_projects(projects)
  # Spustit simulaci
  c.run
  # Vypsat vysledek
  c.output_result
  
end

This snippet took 0.04 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).