1P5: Earthquake!

13

USGS's seismometers have just detected a major earthquake! Emergency response teams need a quick estimate of the number of people affected. Write a program to compute this estimate.

Your program receives 2 inputs. The first is the details of the earthquake itself. The earthquake modeled as a line segment along which the earth ruptured, along with the critical distance from the fault within which damage could be expected. The second input is a list of the location and population of cities in the area. Your program should compute the number of people living in the affected area, that is the sum of the population of all cities within the critical distance of the fault segment.

Input

First a line describing the earthquake, containing the x,y coordinates of the start and end points of the fault, plus the critical distance. The format is A_x A_y B_x B_y D. For example:

3.0 3.0 7.0 4.0 2.5

encodes the fault extending from (3.0,3.0) to (7.0,4.0) and a critical distance of 2.5.

Second, one line per city in the area, containing the x,y coordinates of the city and its population. For example:

1.0 1.0 2500
5.0 7.0 8000
3.0 4.0 7500
9.0 6.0 3000
4.0 2.0 1000

enter image description here

Output

The number of people living in the affected area. For the above example only the third and fifth cities are in the danger area, so the output would be

8500

Shortest code wins.

Example 2

0.0 0.0 10.0 0.0 5.0
5.0 4.0 10000
5.0 -4.0 1000
5.0 6.0 100
11.0 2.0 10 
-4.0 4.0 1

generates

11010

Keith Randall

Posted 2011-05-08T03:31:00.443

Reputation: 19 865

Does the output have to be an integer, or would 8500.0 be ok for the example? And could we maybe get some more testcases? – Ventero – 2011-05-08T12:21:45.790

Also, what is the type of the input? As in, how many decimal places could it have? This is relevant for languages which don't have floating point. – Peter Taylor – 2011-05-08T12:46:36.427

The output needs to be an integer, can't have fractional people. Let's say the input is at most 2 decimal places. – Keith Randall – 2011-05-08T14:33:30.133

Does the critical area extend in a semicircle around the endpoints, or is it just a rectangle? – Peter Olson – 2011-05-08T14:37:36.520

@Peter: It ends in semicircles, so the whole thing is lozenge-shaped. – Keith Randall – 2011-05-08T17:24:38.953

Answers

11

Ruby, 171 152 155 153

u,v,a,b,d=gets.split.map &:to_f
a-=u;b-=v
p eval$<.map{|l|"(x=%f-u;t=(a*x+b*y=%f-v)/(a*a+b*b);d*d<(x-a*t=t<0?0:t>1?1:t)**2+(y-t*b)**2?0:%d)"%l.split}*'+'

This is my first ruby submission and my first code-golf at all. Straight forward implementation of the task. Please give me some hints how to improve (there must be a shorter way to read floats...).

Howard

Posted 2011-05-08T03:31:00.443

Reputation: 23 109

You can save a few characters by eliminating the parentheses around map and eval, and inlining t. And since you're already eval'ing, you can use format-strings instead of .to_f, so the last block can be shortened to p eval$<.map{|l|"(x=%f-u;t=(x*a+b*y=%f-v)/(a**2+b**2);d*d<(x-t=t<0?0:t>1?1:t)**2+(y-t*b)**2?0:%d)"%l.split}*'+' – Ventero – 2011-05-08T17:29:18.577

@Ventero thank you. Inlining t again saves another two. – Howard – 2011-05-08T17:46:38.240

I can't get this to work on example #2 (just added), it errors with undefined method > for nil:NilClass (NoMethodError) – Keith Randall – 2011-05-09T03:42:46.430

@Keith should work now on your input as well. – Howard – 2011-05-09T04:55:29.803

4

C# - 743 715

namespace System{using Linq;using m=Math;class P{public float X,Y;}class E{static void Main(){Func<string,float>p=s=>float.Parse(s);Func<P,P,double>d=(a,b)=>{return a.X*b.X+a.Y*b.Y;},c=(a,b)=>{return a.X*b.Y-a.Y*b.X;};Func<P,P,P>u=(a,b)=>{return new P{X=a.X-b.X,Y=a.Y-b.Y};};Func<P,P,P,double>g=(A,B,C)=>{return d(u(C,B),u(B,A))>0?m.Sqrt(d(u(B,C),u(B,C))):d(u(C,A),u(A,B))>0?m.Sqrt(d(u(A,C),u(A,C))):m.Abs(c(u(B,A),u(C,A))/m.Sqrt(d(u(B,A),u(B,A))));};var n=IO.File.ReadAllLines("i");var i=n[0].Split();var q=new{A=new P{X=p(i[0]),Y=p(i[1])},B=new P{X=p(i[2]),Y=p(i[3])},D=p(i[4])};Console.WriteLine((from l in n.Skip(1)let f=l.Split()let w=new P{X=p(f[0]),Y=p(f[1])}where g(q.A,q.B,w)<q.D select p(f[2])).Sum());}}}

Non-Golfed:

namespace System
{
    using Linq;
    using m = Math;
    class Point { public float X, Y;}
    class Earthquake
    {
        static void Main()
        {
            Func<string, float> parse = s => float.Parse(s);
            Func<Point, Point, double> dotProduct = (a, b) => { return a.X * b.X + a.Y * b.Y; }, 
                                       crossProduct = (a, b) => { return a.X * b.Y - a.Y * b.X; };
            Func<Point, Point, Point> subtract = (a, b) => { return new Point { X = a.X - b.X, Y = a.Y - b.Y }; };
            Func<Point, Point, Point, double> getDistance = (A, B, C) => { 
                return dotProduct(subtract(C, B), subtract(B, A)) > 0 ? 
                        m.Sqrt(dotProduct(subtract(B, C), subtract(B, C))) : 
                        dotProduct(subtract(C, A), subtract(A, B)) > 0 ? 
                            m.Sqrt(dotProduct(subtract(A, C), subtract(A, C))) : 
                            m.Abs(crossProduct(subtract(B, A), subtract(C, A)) / m.Sqrt(dotProduct(subtract(B, A), subtract(B, A)))); 
            };
            var inputLines = IO.File.ReadAllLines("i"); 
            var quakeLine = inputLines[0].Split(); 
            var quake = new { 
                PointA = new Point { X = parse(quakeLine[0]), Y = parse(quakeLine[1]) }, 
                PointB = new Point { X = parse(quakeLine[2]), Y = parse(quakeLine[3]) }, 
                Distance = parse(quakeLine[4]) 
            };
            var affectedPopulations = (from line in inputLines.Skip(1) 
                                       let fields = line.Split() 
                                       let location = new Point { X = parse(fields[0]), Y = parse(fields[1]) } 
                                       let population = parse(fields[2])
                                       where getDistance(quake.PointA, quake.PointB, location) < quake.Distance 
                                       select population);
            Console.WriteLine(affectedPopulations.Sum());
        }
    }
}

Rebecca Chernoff

Posted 2011-05-08T03:31:00.443

Reputation: 397

Something is wrong with the golfed version, I get an error when I compile it (quake.cs(1,254): error CS1525: Unexpected symbol ',', expecting 'from', 'group', 'join', 'let', 'orderby', 'select', or 'where'). The ungolfed version works fine. – Keith Randall – 2011-05-09T03:52:23.167

@KeithRandall, oops - too much golfing! – Rebecca Chernoff – 2011-05-09T04:19:25.027

4

Javascript (437)

This can probably be golfed significantly, but not enough to beat the Ruby solution.

p=$("#i").text().split("\n");for(i=0;i<p.length;i++){p[i]=p[i].split(" ")}
z=p[0];a=z[0];b=z[1];c=z[2];d=z[3];e=z[4];o=0;f=[a,b];g=[c,d];
function q(r,s){return Math.sqrt(Math.pow(s[0]-r[0],2)+Math.pow(s[1]-r[1],2))}
for(i=1;i<p.length;i++){w=p[i];u=((w[0]-a)*(c-a)+(w[1]-b)*(d-b))/Math.pow(q(f,g,2),2);
x=[(a*1)+u*(c-a),(b*1)+u*(d-b)];l=e;m=w[2]*1;u=w[0];w=w[1];v=[u,w];
o+=q(v,x)<l&&q(x,g)+q(x,f)==q(f,g)?m:q(v,f)<l?m:q(v,g)<l?m:0}alert(o);

You can see it in action here.

Peter Olson

Posted 2011-05-08T03:31:00.443

Reputation: 7 412

2You can save 2 characters by using b-0 instead of (b*1), 1 character by removing the trailing semicolon. Finally, start with M=Math and replace all Maths with M, saving 6 characters. Using Prototype and .value saves 2 characters (the # and one parenthesis). – Ry- – 2011-05-13T03:46:19.520

2

c -- 471 characters

#include <stdio.h>
#define F float
#define G getline(&v,&l,stdin)
F a[2],b[2],c[2],d[2],e[2],r,t,y,z;char*v;size_t l,n,p;
F s(F u[2],F v[2]){y=u[0]-v[0];z=u[1]-v[1];return y*y+z*z;}
j(F g[2],F h[2],F i[2]){*i=*g-*h;i[1]=g[1]-h[1];}
int i(){j(b,a,d);j(c,a,e);t=*d**e+d[1]*e[1];
return s(a,c)<=r||s(b,c)<=r||t>0&&t/s(a,b)<=1&&s(a,c)-t*t/s(a,b)<=r;}
int main(){G;sscanf(v,"%f %f %f %f %f",a,a+1,b,b+1,&r);r*=r;
while(G!=-1)sscanf(v,"%f %f %i",c,c+1,&p),n+=p*i();printf("%d\n",n);}

It assumes your standard library has getline.

The method is clarified a bit in the comment to the ungolfed version:

#include <stdio.h>

float a[2],b[2],c[2],d[2],e[2],r,t,y,z;
char*v;
size_t l,n,p;
float s(float u[2],float v[2]){ /* returns the square of the distance
                   between two points */
  y=u[0]-v[0];
  z=u[1]-v[1];
  return y*y+z*z;
}
j(float g[2],float h[2],float i[2]){ /* sets i=g-h */
  i[0]=g[0]-h[0];
  i[1]=g[1]-h[1];
}
int i/*sCLose*/(){
  j(b,a,d); /* d=b-a */
  j(c,a,e); /* e=c-a */
  t=d[0]*e[0]+d[1]*e[1]; /* dot product */ 
  return 
    (s(a,c)<=r) || /* near one end point */
    (s(b,c)<=r) || /* near the other */
    (  
     (t>0) && /* C lies more "towards" B than away */
     (t/s(a,b)<=1) && /* Nearest point on AB to C lies between A and B */
     (s(a,c)-t*t/s(a,b)<=r) /* length of the altitude less than R */
       ); 
}
int main(){
  getline(&v,&l,stdin);
  sscanf(v,"%f %f %f %f %f",a,a+1,b,b+1,&r);
  r*=r; /* r is now r squared, as that is the only way we use it */
  printf("(%f, %f); (%f, %f): %f\n",a[0],a[1],b[0],b[1],r);
  while (getline(&v,&l,stdin) != -1){
    sscanf(v,"%f %f %i",c,c+1,&p);
    printf("\t (%f, %f): %d\n",c[0],c[1],p);
    n+=p*i/*sClose*/();
  }
  printf("%d\n",n);
}

dmckee --- ex-moderator kitten

Posted 2011-05-08T03:31:00.443

Reputation: 2 726

0

scala: 660 chars:

object E extends App{
type I=Int
type D=Double
def b(h:D,i:D,x:I,y:I,d:D)=(x-h)*(x-h)+(y-i)*(y-i)<=d*d
def a(p:java.awt.Polygon,x:I,y:I,h:I,i:I,d:D,r:Array[String])={
val w=r(0).toDouble
val j=r(1).toDouble
val n=r(2).toInt
if (p.contains(w,j)||b(j,w,x,y,d)||b(j,w,i,h,d))n
else 0}
val s=new java.util.Scanner(System.in)
val b=s.nextLine.split(" ")
val c=b.map(_.toDouble)
val e=c.map(_.toInt)
val(x,h,y,i,d)=(e(0),e(2),e(1),e(3),c(4))
val f=List(x,h)
val g=List(y,i)
val p=new java.awt.Polygon((f:::f.reverse).toArray,(g.map(_-e(4)):::g.reverse.map(_+e(4))).toArray,4)
var r=0
while(s.hasNext){
val row=s.nextLine
r+=a(p,x,y,h,i,d,row.split(" "))}
println(r)}

ungolfed:

object Earthquake extends App {

  def bowContains (h: Double, i: Double, x:Int, y:Int, d: Double) : Boolean = {
    (x-h)*(x-h) + (y-i)*(y-i) <= d*d
  }

  import java.awt._    

  def affected (polygon: Polygon, x:Int, y:Int, h: Int, i: Int, d: Double, row: Array[String]) : Int = {
    val w = row (0).toDouble 
    val j = row (1).toDouble 
    val population = row (2).toInt
    if (polygon.contains (w, j) || bowContains (j, w, x, y, d) || bowContains (j, w, i, h, d))
      population 
    else 0 
  }
  val sc = new java.util.Scanner (System.in)
  val line = sc.nextLine.split (" ")

  val li = line.map (_.toDouble)
  val ll = li.map (_.toInt)

  val (x, h, y, i, d) = (ll (0), ll (2), ll (1), ll (3), li(4))
  val xs = List (x, h)
  val ys = List (y, i)

  val polygon = new Polygon ((xs ::: xs.reverse).toArray, (ys.map (_ - ll(4)) ::: ys.reverse.map (_ + ll(4))).toArray, 4)
  var res = 0 
  while (sc.hasNext) {
    val row = sc.nextLine
    println ("line: " + line) 
    res += affected (polygon, x, y, h, i, d, row.split (" "))     
  } 
  println (res)
}

user unknown

Posted 2011-05-08T03:31:00.443

Reputation: 4 210