Ruby travel time - ruby

I'm new to ruby and I'm having a hard time trying to figure out how to calculate a random travel time until it passes 1000 miles. So far, I can't figure out why it doesn't output the results, it just stays with the user input. Help please
def travel_time()
printf "Pick a vehicle: \n"
printf "1. Bicycle \n"
printf "2. Car \n"
printf "3. Jet Plane \n"
puts "Choose 1-3: \n"
vehicle = gets.chomp
case vehicle
when "1"
#Bicycle: 5-15 miles per hour
time = 0
distance = 0
until distance > 1000 do
speed = Random.rand(5...15)
distance = speed * 1
time = time + 1
end
puts "The number of hours it took to travel 1000 miles was #{time} hours"
when "2"
#Car: 20-70 miles per hour
time = 0
distance = 0
until distance > 1000 do
speed = Random.rand(20...70)
distance = speed * 1
time = time + 1
end
puts "The number of hours it took to travel 1000 miles was #{time} hours"
when "3"
#Jet Plane: 400-600 miles per hour
time = 0
distance = 0
until distance > 1000 do
speed = Random.rand(400...600)
distance = speed * 1
time = time + 1
end
puts "The number of hours it took to travel 1000 miles was #{time} hours"
end
end
travel_time

You have an infinite loop here:
until distance > 1000 do
speed = Random.rand(5...15)
distance = speed * 1
time = time + 1
end
This loop will never ende because the biggest value distance can get is 15, so i think you want to add to distance, not replace it; son try using += instead of =:
until distance > 1000 do
speed = Random.rand(5...15)
distance += speed * 1
time = time + 1
end
Same goes for all loops in each case.
How can I save the maximum speed and return it in a statement like I
have done?
One way to do it would be to add another variable (i.e. max_speed) and assign speed value to it whenever speed is greater than max_speed:
time = 0
distance = 0
max_speed = 0
until distance > 1000 do
speed = Random.rand(5...15)
max_speed = speed if speed > max_speed
distance += speed * 1
time = time + 1
end
puts "The maximum speed was #{max_speed} miles per hour"
Another way would be to use an array (although i prefer the first option):
speed = []
until distance > 1000 do
speed << Random.rand(5...15)
distance += speed.last * 1
time = time + 1
end
puts "The maximum speed was #{speed.max} miles per hour"

You're not actually summing up the distance - distance is never going to increase past 1000
until distance > 1000 do
speed = Random.rand(5...15)
distance = speed * 1 # will never equal more than 15
time = time + 1
end
You probably want
distance += speed * 1 # not sure why you're multiplying by 1 though

As a style comment: don't use case statements as control flow like if/then statements. Just use them to set values, and move everything else out. This can eliminate a lot of redundant code. Example:
time = 0
distance = 0
until distance > 1000 do
speed = case vehicle
when "1" then Random.rand(5...15) #Bicycle
when "2" then Random.rand(20...70) #Car
when "3" then Random.rand(400...600) #Plane
end
distance += speed * 1
time = time + 1
end
puts "The number of hours it took to travel 1000 miles was #{time} hours"

Related

How to devide some fixed amount of reward points to players of a racing game in a fair way depending on their finishing time

I'm in need of some kind of algorithm I can't figure out on my own sadly.
My biggest problem is that I have no good way to describe the problem... :/
I will try like this:
Imagine you have a racing game where everyone can try to be the fastest on a track or map. Every Map is worth 100 Points in total. If someone finished a map in some amount of time he gets a record in a database. If the player is the first and only player to finish this map he earns all the 100 points of this map.
Now, that's easy ;) but...
Now another player finishes the map. Let's imagine the first player finishes in 50 Seconds and the 2nd player finishes in 55 seconds, so a bit slower. I now need a calculation depending on both records in the database. Each of both players now earn a part of the 100 points. The faster player a bit more then the slower player. Let's say they finished the exact same time they both would get 50 points from 100, but as the first one is slightly faster, he now earns something around 53 of the points and the slower player just 47.
I started to calculate this like this:
Sum of both records is 105 seconds, the faster player took 50/105 in percent of this, so he earns 100-(50/105*100) points and the slower player 100-(55/105*100) points. The key to this is, that all points distributed among the players always equals to 100 in total. This works for 2 players, but it breaks at 3 and more.
For example:
Player 1 : 20 seconds
Player 2 : 20 seconds
Player 3 : 25 seconds
Calculation would be:
Player 1: 100-(20/65*100) = 69 points
Player 2: 100-(20/65*100) = 69 points
Player 3: 100-(25/65*100) = 61 points
This would no longer add up to 100 points in total.
Fair would be something around values of:
Player 1 & 2 (same time) = 35 points
Player 3 = 30 points
My problem is i can't figure out a algorithm which solves this.
And I need the same algorithm for any amount of players. Can someone help with an idea? I don't need a complete finished algorithm, maybe just an idea at which step i used the wrong idea, maybe the sum of all times is already a bad start.
Thx in advance :)
We can give each player points proportional to the reciprocal of their time.
One player with t seconds gets 100 × (1/t) / (1/t) = 100 points.
Of the two players, the one with 50 seconds gets 100 × (1/50) / (1/50 + 1/55) ≈ 52.4, and the one with 55 gets 100 × (1/55) / (1/50 + 1/55) ≈ 47.6.
Of the three players, the ones with 20 seconds get 100 × (1/20) / (1/20 + 1/20 + 1/25) ≈ 35.7, and the one with 25 seconds gets 100 × (1/25) / (1/20 + 1/20 + 1/25) ≈ 28.6.
Simple observation: Let the sum of times for all players be S. A person with lower time t would have a higher value of S-t. So you can reward points proportional to S-t for each player.
Formula:
Let the scores for N players be a,b,c...,m,n. Total sum S = a+b+c...+m+n. Then score for a given player would be
score = [S-(player's score)]/[(N-1)*S] * 100
You can easily see that using this formula, the sum of scores of all players will be always be 100.
Example 1:
S = 50 + 55 = 105, N-1 = 2-1 = 1
Player 1 : 50 seconds => score = ((105-50)/[1*105])*100 = 52.38
Player 2 : 55 seconds => score = ((105-55)/[1*105])*100 = 47.62
Similarly, for your second example,
S = 20 + 20 + 25 = 65
N - 1 = 3 - 1 = 2
For Player 1, (S-t) = 65-20 = 45
Player 1's score => (45/(2*65))*100 = 34.6
Player 2 => same as Player 1
For Player 3, (S-t) = 65-25 = 40
Player 3's score => (40/(2*65))*100 = 30.8
This method avoids any division in the intermediate states, so there will be no floating point issues for the calculations.

Ruby Complexity / Time explaination

I am using HackerRank to improve my ruby skills. I am on the Data Structures - Array Manipulation problem: https://www.hackerrank.com/challenges/crush/problem
My solution is listed first, a supposedly "correct" solution I haven't been able to implement is listed last. My solution works for all test cases except **VERY ** large numbers, it fails due to timeout. I know this is because of a loop, but can someone offer a different solution, and explain why theirs works?
EXPLAINATION OF PROBLEM:
Sample Input
5 3
1 2 100
2 5 100
3 4 100
#n=5 m=3, then following numbers leftIndex=1 rightIndex=3 sum=100 and so on
Sample Output
200
Explanation
After the first update list will be 100 100 0 0 0.
After the second update list will be 100 200 100 100 100.
After the third update list will be 100 200 200 200 100.
The required answer will be 200.
OR
Explain how the why the bottom solution can work without looping?
#Problem Data Set, my solution times out for the listed data set
10000000 100000
[
[1400906,9889280,90378],
[6581237,9872072,87106],
[4386373,9779851,52422],
[198648,4373818,5289]
]
# For this problem, variables will look like:
n = 10000000
m = 100000
q = [[1400906,9889280,90378],[6581237,9872072,87106],[4386373,9779851,52422],[198648,4373818,5289]]
def arrayManipulation(n, q)
arr = Array.new(n,0)
max = 0
q.size.times do |i|
left, right, value = q[i][0],q[i][1],q[i][2]
left -= 1
(left...right).each do |j|
arr[j] += value
max = arr[j] if max < arr[j]
end
end
return max
end
# this times out on HackerRank, please explain better solution,
#or why the bottom solution works!
result = arrayManipulation n, queries
Working SOlution on Discussion board
N, M = gets.chomp.split(' ').map(&:to_i)
# create array of zeros of length N + 1
arr = Array.new(N + 1, 0)
M.times do
# cycle through and get the inputs
start, finish, value = gets.chomp.split(' ').map(&:to_i)
# increment value at start of sequence
arr[start - 1] += value
# decrement value at first position after sequence
arr[finish] -= value
end
tmp = 0
max = 0
arr.each do |value|
# step through summing array
tmp += value
# capture the max value of tmp
max = tmp if max < tmp
end
puts max
Your code is O(m * n) as you have a nested loop to update the array for each entry.
The working code is O(m + n): it never really stores the array, it stores the delta array, the array of changes that makes it possible to reconstruct the array. In your first example, it would store:
0 0 0 0 0 0
+100 0 -100 0 0 0
+100 +100 -100 0 0 -100
+100 +100 0 0 -100 -100
This requires only a loop of m iterations, no nested loops; then you need another loop of n iterations to run through the array, keep running total, and identify the maximum of it.

Fortran MPI slowdown of highly parallel task

I have been trying to diagnose why my Fortran code will not scale well and have reduced the program down to a very simple test case which still will not scale well. The test case is below. I am trying to create an array, split it evenly between processors, and then do some operation on it (in this case just scale it by weights).
I am not passing any information between processes so it seems to me that this should scale well, however, as I run with increasing number of processors and normalize by the number of elements in the array that each processor operates on I see that there is very poor scaling:
2 Processors:
For Rank: 0 Average time for 100 iterations was 6.3680603710015505E-009 with 25525500 points per loop
For Rank: 1 Average time for 100 iterations was 6.3611264474244413E-009 with 25576551 points per loop
3 Processors:
For Rank: 2 Average time for 100 iterations was 8.0085945661011481E-009 with 17102085 points per loop
For Rank: 0 Average time for 100 iterations was 8.2051102639337855E-009 with 16999983 points per loop
For Rank: 1 Average time for 100 iterations was 8.2249291072820462E-009 with 16999983 points per loop
4 Processors:
For Rank: 0 Average time for 100 iterations was 1.0044801473036765E-008 with 12762750 points per loop
For Rank: 3 Average time for 100 iterations was 1.0046922454937459E-008 with 12813801 points per loop
For Rank: 1 Average time for 100 iterations was 1.0178132064014425E-008 with 12762750 points per loop
For Rank: 2 Average time for 100 iterations was 1.0260574719398254E-008 with 12762750 points per loop
6 Processors:
For Rank: 1 Average time for 100 iterations was 1.5841797042924197E-008 with 8525517 points per loop
For Rank: 4 Average time for 100 iterations was 1.5990067816415119E-008 with 8525517 points per loop
For Rank: 0 Average time for 100 iterations was 1.6105490894647526E-008 with 8474466 points per loop
For Rank: 3 Average time for 100 iterations was 1.6141289610460415E-008 with 8474466 points per loop
For Rank: 5 Average time for 100 iterations was 1.5936059738580745E-008 with 8576568 points per loop
For Rank: 2 Average time for 100 iterations was 1.6052278119907569E-008 with 8525517 points per loop
I am running on a MacPro 8 core desktop with 64 GB of RAM so it shouldn't be constrained by system resources and without any actual message passing I don't know why it should progressively run slower as more cores are utilized. Am I missing something obvious that should cause this issue? Using GCC 5.1.0 and Open MPI 1.6.5 (EDIT: using -O3 flag). Any help would be appreciated. Thanks!
Code:
PROGRAM MAIN
use mpi
implicit none
real*8,allocatable::MX(:,:,:)
real*8,allocatable::XFEQ(:,:,:,:)
integer:: rank, iter, nte
INTEGER:: top,bottom,xmin,xmax,zmin,zmax,q,ymax,ymin
integer:: num_procs, error
call MPI_Init ( error ) ! Initialize MPI.
call MPI_Comm_size ( MPI_COMM_WORLD, num_procs, error ) ! Get the number of processes.
call MPI_Comm_rank ( MPI_COMM_WORLD, rank, error ) ! Get the individual process ID.
q = 7
xmin = 0
ymin = 0
zmin = 0
ymax = 1000
xmax = 1000
zmax = 50
nte = 100
top = rank *ymax/num_procs
bottom = (rank+1)*ymax/num_procs-1
if (rank+1 == num_procs) bottom = ymax
allocate(MX ((ZMIN):(ZMAX),(xMIN):(xMAX),(top):(bottom)))
allocate(xfeq (0:Q-1,(ZMIN):(ZMAX),(xMIN):(xMAX),(top):(bottom)))
DO ITER = 1, nte
MX = 1
CALL COMPFEQ(top, bottom, xmin, xmax, zmin, zmax, q, rank, iter, nte, xfeq, mx)
ENDDO
!clean up and exit MPI
call MPI_Finalize ( error )
contains
SUBROUTINE COMPFEQ(top, bottom, xmin, xmax, zmin, zmax, q, rank, iter, nte, xfeq, mx)
implicit none
INTEGER::I,J,L,top,bottom,xmin,xmax,zmin,zmax,q,rank, iter, nte
real*8::xfeq(0:Q-1,(ZMIN):(ZMAX),(xMIN):(xMAX), (top):(bottom))
real*8::MX((ZMIN):(ZMAX),(xMIN):(xMAX),(top):(bottom))
real*8::weight(0:q-1)
real*8::time_start, time_stop, time_col = 0
integer :: count
count = 0
weight(0) = 0.25
weight(1:q-1) = 0.125
CALL CPU_TIME ( TIME_start )
DO J=top,bottom
DO I=XMIN,XMAX
DO L=zmin, zmax
XFEQ(:,L,I,J) = weight*MX(L,I,J)
count = count +1
ENDDO
ENDDO
ENDDO
CALL CPU_TIME ( TIME_stop )
time_col = time_col + (time_stop - time_start)/count
if (iter == nte) print*, "For Rank: ",rank, "Average time for ",nte,'iterations was', &
time_col/(iter+nte), "with ", count, "points per loop"
END SUBROUTINE
END PROGRAM

Fitness Proportionate Selection when some fitnesses are 0

I have a question about what to do with the fitnesses (fitness'?) that are 0 when getting the fitness proportionate probabilities. Should the container for the members be sorted by highest fitness first, then do code similar to this:
for all members of population
sum += fitness of this individual
end for
for all members of population
probability = sum of probabilities + (fitness / sum)
sum of probabilities += probability
end for
loop until new population is full
do this twice
number = Random between 0 and 1
for all members of population
if number > probability but less than next probability then you have been selected
end for
end
create offspring
end loop
My problem that I am seeing as I go through one iteration by hand with randomly generated members is that I have some member's fitness as 0, but when getting the probability of those members, it keeps the same probability as the last non zero member. Is there a way I can separate the non zero probabilities from the zero probabilities? I was thinking that even if I sort based on highest fitness, the last non zero member would have the same probability as the zero probabilities.
Consider this example:
individual fitness(i) probability(i) partial_sum(i)
1 10 10/20 = 0.50 0.50
2 3 3/20 = 0.15 0.5+0.15 = 0.65
3 2 2/20 = 0.10 0.5+0.15+0.1 = 0.75
4 0 0/20 = 0.00 0.5+0.15+0.1+0.0 = 0.75
5 5 5/20 = 0.25 0.5+0.15+0.1+0.0+0.25 = 1.00
------
Sum 20
Now if number = Random between [0;1[ we are going to pick individual i if:
individual condition
1 0.00 <= number < partial_sum(1) = 0.50
2 0.50 = partial_sum(1) <= number < partial_sum(2) = 0.65
3 0.65 = partial_sum(2) <= number < partial_sum(3) = 0.75
4 0.75 = partial_sum(3) <= number < partial_sum(4) = 0.75
5 0.75 = partial_sum(4) <= number < partial_sum(5) = 1.00
If an individual has fitness 0 (e.g. I4) it cannot be selected because of its selection condition (e.g. I4 has the associated condition 0.75 <= number < 0.75).

Ruby: Time difference in percentage?

How would I, for example, find out that 6pm is 50% between 4pm and 8pm?
Or that 12am Wednesday is 50% between 12pm Tuesday and 12pm Wednesday?
Convert the times to seconds, calculate the span in seconds, calculate the difference between your desired time and the first time in seconds, calculate the fraction of the whole span, and then multiply by 100%?
Example:
12 AM = 0 seconds (of day)
12 PM = 43200 seconds (of day)
Your desired time = 3 AM = 10800 seconds of day
Total time span = 43200 - 0 = 43200 seconds
Time difference of your desired time from first time = 10800 - 0 = 10800 seconds
Fraction = 10800 / 43200 = 0.25
Percentage = 0.25 * 100% = 25%
(Sorry don't know Ruby but there's the idea.)
require 'date'
start = Date.new(2008, 4, 10)
middle = Date.new(2009, 12, 12)
enddate = Date.new(2009, 4, 10)
duration = start - enddate #Duration of the whole time
desired = middle - start #Difference between desired + Start
fraction = desired / duration
percentage = fraction * 100
puts percentage.to_i
Thanks to 'John W' for the math.

Resources