Problem:
Problem E:
Spherical Mirrors
A long time ago in a galaxy, far, far away, there were N spheres with various radii.
Spheres were mirrors, that is, they had reflective surfaces . . . .
You are standing at the origin of the galaxy (0, 0, 0), and emit a laser ray to the direction
(
u
,
v
,
w
). The ray travels in a straight line.
When the laser ray from
I
hits the surface of a sphere at
Q
, let
N
be a point outside of the
sphere on the line connecting the sphere center and Q. The reflected ray goes to the direction
towards
R
that satisfies the following conditions: (1)
R
is on the plane formed by the three
points
I
,
Q
and
N
, (2) ∠
IQN
= ∠
NQR
, as shown in Figure 1.
Figure 1: Laser ray reflection
After it is reflected several times, finally it goes beyond our observation. Your mission is to write
a program that identifies the last reflection point.
Input
The input consists of multiple datasets, each in the following format.
N
u v w
x
1
y
1
z
1
r
1
.
         .
         .
x
N
y
N
z
N
r
N
The first line of a dataset contains a positive integer
N
which is the number of spheres. The
next line contains three integers
u
,
v
and
w
separated by single spaces, where (
u
,
v
,
w
) is the
direction of the laser ray initially emitted from the origin.
Each of the following
N
lines contains four integers separated by single spaces. The
i
-th line
corresponds to the
i
-th sphere, and the numbers represent the center position (
x
i
,
y
i
,
z
i
) and the
radius
r
i
.
N
,
u
,
v
,
w
,
x
i
,
y
i
,
z
i
and
r
i
satisfy the following conditions.
1 ≤
N
≤ 100
−100 ≤
u
,
v
,
w
≤ 100
−100 ≤
x
i
,
y
i
,
z
i
≤ 100
5 ≤
r
i
≤ 30
u
2
+
v
2
+
w
2
> 0
You can assume that the distance between the surfaces of any two spheres is no less than 0.1.
You can also assume that the origin (0, 0, 0) is located outside of any sphere, and is at least 0.1
distant from the surface of any sphere.
The ray is known to be reflected by the sphere surfaces at least once, and at most five times.
You can assume that the angle between the ray and the line connecting the sphere center and
the reflection point, which is known as the angle of reflection (i.e. θ in Figure 1), is less than 85
degrees for each point of reflection.
The last dataset is followed by a line containing a single zero.
Output
For each dataset in the input, you should print the x-, y- and z-coordinates of the last reflection
point separated by single spaces in a line. No output line should contain extra characters.
No coordinate values in the output should have an error greater than 0.01.
Sample Input
3
-20 -20 -24
100 100 100 30
10 8 3 5
-70 -70 -84 5
4
0 47 84
-23 41 42 8
45 -10 14 19
-5 28 47 12
-27 68 34 14
0
Output for the Sample Input
79.0940 79.0940 94.9128
-21.8647 54.9770 34.1761

Submitted solutions:

code_snippet: #include <iostream>
#include <cmath>
using namespace std;

struct Point3D {
	double px, py, pz;
};

Point3D operator+(const Point3D &a1, const Point3D &a2) {
	return Point3D{ a1.px + a2.px, a1.py + a2.py, a1.pz + a2.pz };
}

Point3D operator-(const Point3D &a1, const Point3D &a2) {
	return Point3D{ a1.px - a2.px, a1.py - a2.py, a1.pz - a2.pz };
}

Point3D operator*(const Point3D &a1, const double &a2) {
	return Point3D{ a1.px * a2, a1.py * a2, a1.pz * a2 };
}

double ABS(Point3D A1) {
	return sqrt(A1.px * A1.px + A1.py * A1.py + A1.pz * A1.pz);
}

double dot(Point3D A1, Point3D A2) {
	return A1.px * A2.px + A1.py * A2.py + A1.pz * A2.pz;
}

Point3D Normalization(Point3D A1) {
	double LEN = ABS(A1);
	return A1 * (1.0 / LEN);
}

// Get next laser vector, when reflect point is A1 and current laser vector is A2
Point3D NextVector(Point3D A1, Point3D A2) {
	double val = dot(A1, A2); val *= -1.0;
	if (abs(val) < 1e-6) return (A2 * -1.0);
	double LEN = val / ABS(A1);
	Point3D Projection = A1 * (LEN / ABS(A1));
	return (Projection * 2.0) + A2;
}
int N;
Point3D Laser;
Point3D P[109]; double R[109];

// Return the index of sphere that point A is inside
int check(Point3D A) {
	for (int i = 1; i <= N; i++) {
		if (ABS(A - P[i]) <= R[i]) return i;
	}
	return -1;
}

// Binary Search "the hit place"
double search(Point3D Current) {
	double cl = 0.00, cr = 0.01, cm;
	for (int i = 0; i < 30; i++) {
		cm = (cl + cr) / 2.0;
		Point3D TargetPlace = Current + (Laser * cm);
		if (check(TargetPlace) == -1) { cl = cm; }
		else { cr = cm; }
	}
	return cm;
}

// Return Answer
Point3D Simulation() {
	Point3D Last = Point3D{ 0.0, 0.0, 0.0 };
	Point3D Current = Point3D{ 0.0, 0.0, 0.0 };
	
	// Begin Simulation
	while (true) {
		bool flag = false;
		for (int i = 1; i <= 80000; i++) {
			Point3D NextPlace = Current + (Laser * 0.01);
			int idx = check(NextPlace);
			if (idx == -1) {
				Current = NextPlace;
				continue;
			}
			
			// If NextPlace is inside sphere
			double Target = search(Current);
			Point3D Reflected = Current + (Laser * Target);
			Last = Reflected;
			Current = Reflected;
			Laser = NextVector(Reflected - P[idx], Laser);
			Laser = Normalization(Laser);
			flag = true;
			break;
		}
		if (flag == false) return Last;
	}
}

int main() {
	while (true) {
		// Input
		cin >> N; if (N == 0) break;
		cin >> Laser.px >> Laser.py >> Laser.pz;
		for (int i = 1; i <= N; i++) cin >> P[i].px >> P[i].py >> P[i].pz >> R[i];
		Laser = Normalization(Laser);
		
		// Simulation
		Point3D Answer = Simulation();
		printf("%.12lf %.12lf %.12lf\n", Answer.px, Answer.py, Answer.pz);
	}
	return 0;
}
accuracy: 1
time_ms: 840
memory_kb: 3468
final_rank: 19

code_snippet: #include<bits/stdc++.h>
#define rep(i,a,...) for(int i = (a)*(strlen(#__VA_ARGS__)!=0);i<(int)(strlen(#__VA_ARGS__)?__VA_ARGS__:(a));++i)
#define per(i,a,...) for(int i = (strlen(#__VA_ARGS__)?__VA_ARGS__:(a))-1;i>=(int)(strlen(#__VA_ARGS__)?(a):0);--i)
#define foreach(i, n) for(auto &i:(n))
#define all(x) (x).begin(), (x).end()
#define bit(x) (1ll << (x))
#define lambda(RES_TYPE, ...) (function<RES_TYPE(__VA_ARGS__)>)[&](__VA_ARGS__) -> RES_TYPE
#define method(FUNC_NAME, RES_TYPE, ...) function<RES_TYPE(__VA_ARGS__)> FUNC_NAME = lambda(RES_TYPE, __VA_ARGS__)
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
//const ll MOD = (ll)1e9+7;
const ll MOD = 998244353;
const int INF = (ll)1e9+7;
const ll INFLL = (ll)1e18 + 10;
template<class t>
using vvector = vector<vector<t>>;
template<class t>
using vvvector = vector<vector<vector<t>>>;
template<class t>
using priority_queuer = priority_queue<t, vector<t>, greater<t>>;
template<class t, class u> bool chmax(t &a, u b){if(a<b){a=b;return true;}return false;}
template<class t, class u> bool chmin(t &a, u b){if(a>b){a=b;return true;}return false;}
#ifdef DEBUG
#define debug(x) cout<<"LINE "<<__LINE__<<": "<<#x<<" = "<<x<<endl;
#else
#define debug(x) (void)0
#endif

namespace templates{
    ll modpow(ll x, ll b,ll mod=MOD){
        ll res = 1;
        while(b){
            if(b&1)res = res * x % mod;
            x = x * x % mod;
            b>>=1;
        }
        return res;
    }

    ll modinv(ll x){
        return modpow(x, MOD-2);
    }

    bool was_output = false;

    void print();
    template <class t> void print(const vector<t> &);
    template <class t, class u> void print(const pair<t, u> &);
    template <class t> void print(const t&);
    template <class Head, class... Tail> void print(const Head&, const Tail&...);

    template <class t> void println(const vector<vector<t>>&);
    template <class t> void println(const vector<t>&);
    template <class t> void println(const t&);
    template <class Head, class... Tail> void println(const Head&, const Tail&...);
    void println();
    void newline();

    void print(){
        return;
    }

    template <class t>
    void print(const vector<t>&x){
        for(const t&i:x)print(i);
    }
    template <class t, class u>
    void print(const pair<t,u>&p){
        print(p.first);
        print(p.second);
    }
    template <class t>
    void print(const t&x){
        if(was_output)cout<<" ";
        cout<<x;
        was_output = true;
    }
    template <class Head, class... Tail>
    void print(const Head&head,const Tail&...tail){
        print(head);
        print(tail...);
    }

    template<class t>
    void println(const vector<vector<t>>&x){
        for(vector<t> i:x)println(i);
    }
    template<class t>
    void println(const vector<t>&x){
        for(const t&i:x)print(i);
        println();
    }
    template <class t>
    void println(const t&x){
        print(x);
        println();
    }
    void println(){
        if(was_output){
            cout << endl;
            was_output = false;
        }
    }
    template <class Head, class... Tail>
    void println(const Head&head,const Tail&...tail){
        print(head);
        println(tail...);
    }

    void newline(){
        was_output = true;
        println();
    }

    template<class t>
    istream& operator>>(istream&is, vector<t>&x){
        for(auto &i:x)is >> i;
        return is;
    }

    template<class t, class u>
    istream& operator>>(istream&is, pair<t, u>&x){
        is >> x.first >> x.second;
        return is;
    }

    template<class t>
    ostream& operator<<(ostream&os, vector<t> &v){
        os << "{";
        for(t &i:v){
            os << i << ", ";
        }
        os << "}";
        return os;
    }

    template<class t = long long>
    t in(){
        t res; cin >> res; return res;
    }

    template<class t>
    vector<t> sorted(vector<t> line,function<bool(t,t)> comp=[](t a,t b){return a<b;}){
        sort(line.begin(),line.end(),comp);
        return line;
    }

    template<class t>
    vector<t> reversed(vector<t> line){
        reverse(line.begin(),line.end());
        return line;
    }
    string reversed(string str){
        reverse(str.begin(),str.end());
        return str;
    }

    long long gcd(long long a,long long b){
        while(b){
            a %= b;
            swap(a,b);
        }
        return a;
    }

    long long lcm(long long a,long long b){
        return a / gcd(a,b) * b;
    }

    class output_initializer{
    public:
        output_initializer(){
            ios::sync_with_stdio(false);
            cin.tie(nullptr);
            cout << setprecision(20);
        }
    };output_initializer OUTPUT_INITIALIZER_INSTANCE = output_initializer();
}

using namespace templates;

using V = vector<double>;

V operator+(V a,V b){
    V res(3);
    rep(i,3){
        res[i] = a[i] + b[i];
    }
    return res;
}
V operator-(V a,V b){
    V res(3);
    rep(i,3){
        res[i] = a[i] - b[i];
    }
    return res;
}
V operator*(V a,double k){
    V res(3);
    rep(i,3){
        res[i] = a[i] * k;
    }
    return res;
}
V operator/(V a, double k) { return a * (1 / k); }

V readV(){
    V res(3);
    foreach(i,res)i=in();
    return res;
}

double abs(V x){
    double res = 0;
    rep(i,3)res += x[i] * x[i];
    return sqrt(res);
}
double dot(V x,V y){
    double res = 0;
    rep(i,3)res += x[i] * y[i];
    return res;
}
V normal(V x){
    return x / abs(x);
}

vector<double> func(int n){
    V p(3,0);
    V dir = normal(readV());
    vector<V> spheres(n);
    vector<double> Rs(n);
    rep(i,n){
        spheres[i] = readV();
        Rs[i] = in();
    }
    V last;
    while(true){
        double dist = INF;
        int itr = -1;
        rep(i,n){
            V d = normal(spheres[i] - p);
            if(dot(dir,d) < 0)continue;
            double lp = 0;
            double rp = INF;
            rep(_,100){
                double mid1 = (lp + lp + rp) / 3;
                double mid2 = (lp + rp + rp) / 3;
                if(abs(p + dir * mid1 - spheres[i]) < abs(p + dir * mid2 - spheres[i])){
                    rp = mid2;
                }else{
                    lp = mid1;
                }
            }
            if(abs(p + dir * lp - spheres[i]) > Rs[i]+0.01)continue;
            lp = 0;
            rep(_,100){
                double mid = (lp + rp) / 2;
                if(abs(p + dir * mid - spheres[i]) < Rs[i]){
                    rp = mid;
                }else{
                    lp = mid;
                }
            }
            if(chmin(dist,lp)){
                itr = i;
            }
        }
        if(itr == -1)break;
        V at = p + dir * dist;
        last = at;
        V d = normal(at - spheres[itr]);
        dir = normal(dir - d * dot(dir,d) * 2);
        p = last;
    }
    return last;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while(true){
        int n = in();
        if(n==0)break;
        println(func(n));
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 3432
final_rank: 18

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-9;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

struct Point3d {
	long double x, y, z;
	Point3d(const long double xx = 0, const long double yy = 0, const long double zz = 0) {
		x = xx, y = yy, z = zz;
	}
	void Input() {
		cin >> x >> y >> z;
	}
	long double Distance(Point3d p) {
		return hypot(hypot(x - p.x, y - p.y), z - p.z);
	}
	Point3d operator+(const Point3d&p)const {
		return Point3d(x + p.x, y + p.y, z + p.z);
	}
	Point3d operator-(const Point3d&p)const {
		return Point3d(x - p.x, y - p.y, z - p.z);
	}
	Point3d operator*(const long double r)const {
		return Point3d(x*r, y*r, z*r);
	}
	void Output() {
		cout << fixed << setprecision(20) << x << " " << y << " " << z << endl;
	}
};

struct Line {
	Point3d st, ed;
	Line(const Point3d aa, const Point3d bb) {
		st = aa, ed = bb;
	}
	long double Distance(Point3d p) {
		p = p - st;
		auto ced = ed - st;
		auto cst = st - st;
		{
			long double rad = atan2(ced.z, ced.x);
			p = Point3d(hypot(p.x, p.z)*cos(atan2(p.z, p.x) - rad), p.y, hypot(p.x, p.z)*sin(atan2(p.z, p.x) - rad));
			ced = Point3d(hypot(ced.x, ced.z), ced.y, 0);
		}
		{
			long double rad = atan2(ced.y, ced.x);
			p = Point3d(hypot(p.x, p.y)*cos(atan2(p.y, p.x) - rad), hypot(p.x, p.y)*sin(atan2(p.y, p.x) - rad), p.z);
			ced = Point3d(hypot(ced.x, ced.y), 0, 0);
		}
		p = Point3d(p.x, hypot(p.y, p.z), 0);
		if (0 <= p.x&&p.x <= ced.x)return p.y;
		return hypot(min(abs(p.x), abs(p.x - ced.x)), p.y);
	}
	bool Intersect(Point3d p, long double r) {
		return Distance(p) <= r;
	}
};

Point3d reflect(Point3d a, Point3d b) {
	long double radz = atan2(b.z, b.x);
	a = Point3d(hypot(a.x, a.z)*cos(atan2(a.z, a.x) - radz), a.y, hypot(a.x, a.z)*sin(atan2(a.z, a.x) - radz));
	b = Point3d(hypot(b.x, b.z), b.y, 0);
	long double rady = atan2(b.y, b.x);
	a = Point3d(hypot(a.x, a.y)*cos(atan2(a.y, a.x) - rady), hypot(a.x, a.y)*sin(atan2(a.y, a.x) - rady), a.z);
	b = Point3d(hypot(b.x, b.y), 0, 0);
	a.x *= -1;
	radz *= -1, rady *= -1;
	a = Point3d(hypot(a.x, a.y)*cos(atan2(a.y, a.x) - rady), hypot(a.x, a.y)*sin(atan2(a.y, a.x) - rady), a.z);
	a = Point3d(hypot(a.x, a.z)*cos(atan2(a.z, a.x) - radz), a.y, hypot(a.x, a.z)*sin(atan2(a.z, a.x) - radz));
	return a;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	while (cin >> N, N) {
		Point3d st, v;
		v.Input();
		vector<long double>ra(N);
		vector<Point3d>p(N);
		for (int i = 0; i < N; i++) {
			p[i].Input();
			cin >> ra[i];
		}
		int bef = -1;
		while (1) {
			int nx = -1;
			long double l = 0, r = 500;
			for (int loop = 0; loop < 100; loop++) {
				long double mid = (l + r) / 2;
				bool ok = false;
				Line line(st, st + v * mid);
				for (int i = 0; i < N; i++) {
					if (i == bef)continue;
					if (line.Intersect(p[i], ra[i])) {
						ok = true;
						nx = i;
					}
				}
				if (ok)r = mid;
				else l = mid;
			}
		//	cout << l << " " << nx << endl;
			if (nx == -1)break;
			auto nv = v;
			bef = nx;
			auto nst = st + v * l;
			nv = reflect(v, nst - p[nx]);
			v = nv;
			st = nst;
		//	v.Output();
		}
		st.Output();
	}
}
accuracy: 1
time_ms: 1810
memory_kb: 3628
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

struct Point{
    double X,Y,Z;

    void PRINT(){
        printf("%.8f %.8f %.8f\n",X,Y,Z);
    }

    void ADD(Point p){
        X += p.X;
        Y += p.Y;
        Z += p.Z;
    }

    void MUL(double m){
        X *= m;
        Y *= m;
        Z *= m;
    }

    double norm(){
        return X*X + Y*Y + Z*Z;
    }

    double size(){
        return sqrt(norm());
    }

    void normalize(){
        double sz = size();
        X /= sz;
        Y /= sz;
        Z /= sz;
    }
};

using Vec = Point;

double dist(Point p, Point q){
    double dx = p.X-q.X;
    double dy = p.Y-q.Y;
    double dz = p.Z-q.Z;
    return sqrt(dx*dx + dy*dy + dz*dz);
}

double dot(Vec v, Vec u){
    return v.X*u.X + v.Y*u.Y + v.Z*u.Z;
}

Point READ(){
    double x,y,z;
    cin >>x >>y >>z;
    return {x,y,z};
}

const double LIM = 1000;
const double EPS = 1e-7;

int main(){
    int n;
    while(cin >>n,n){
        Vec v = READ();

        vector<Point> c(n);
        vector<double> r(n);
        rep(i,n){
            c[i] = READ();
            cin >>r[i];
        }

        Point now = {0,0,0};
        v.normalize();

        // Segment to Sphere
        auto distSS = [&](Point start, Vec dir, int idx){
            double L=0, R=LIM;
            rep(loop,100){
                double m1 = (2*L+R)/3 , m2 = (L+2*R)/3;
                Vec v1(dir), v2(dir);
                v1.MUL(m1);
                v2.MUL(m2);

                Point p1(start), p2(start);
                p1.ADD(v1);
                p2.ADD(v2);

                if(dist(c[idx],p1) > dist(c[idx],p2)) L=m1;
                else R=m2;
            }

            Vec add(dir);
            add.MUL(R);
            Point pos(start);
            pos.ADD(add);

            // NOT intersect
            if( dist(pos, c[idx]) > r[idx]+EPS ) return LIM;

            // 交点までのパラメータを改めて求める
            L = 0;
            rep(loop,100){
                double mid = (L+R)/2;
                Vec vv(dir);
                vv.MUL(mid);

                Point pp(start);
                pp.ADD(vv);

                if(dist(c[idx],pp) < r[idx]) R = mid;
                else L = mid;
            }
            return L;
        };

        int prev = -1;
        while(1){
            double min_t = LIM;
            int idx = -1;
            rep(i,n)if(prev!=i){
                double tt = distSS(now,v,i);
                // dbg(i);dbg(tt);
                if(tt < min_t){
                    min_t = tt;
                    idx = i;
                }
            }

            if(idx == -1) break;

            Vec vv(v);
            vv.MUL(min_t);
            Point q(now);
            q.ADD(vv);

            // dbg(dist(c[idx],q));
            Vec qn = {q.X-c[idx].X, q.Y-c[idx].Y, q.Z-c[idx].Z};
            qn.normalize();

            Vec qi(v);
            qi.MUL(-1);

            // qn.PRINT();
            // qi.PRINT();

            double cos_theta = dot(qn,qi);
            // dbg(cos_theta);

            double D = dist(now,q);
            // dbg(D);
            D *= cos_theta;

            Vec hh(qn);
            hh.MUL(D);
            Point H(q);
            H.ADD(hh);

            Vec nh = {H.X-now.X, H.Y-now.Y, H.Z-now.Z};;
            nh.MUL(2);

            Point ref(now);
            ref.ADD(nh);

            now = q;
            v = {ref.X-q.X, ref.Y-q.Y, ref.Z-q.Z};
            v.normalize();
            // printf("v = ");v.PRINT();
            prev = idx;
        }

        now.PRINT();
    }
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3200
final_rank: 17

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define int long long

#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define PI 3.141592653589793238
struct Point3D{
  double x,y,z;
  Point3D(){}
  Point3D(double x,double y,double z):x(x),y(y),z(z){}
  Point3D operator+(Point3D p) {return Point3D(x+p.x,y+p.y,z+p.z);}
  Point3D operator-(Point3D p) {return Point3D(x-p.x,y-p.y,z-p.z);}
  Point3D operator*(double k){return Point3D(x*k,y*k,z*k);}
  Point3D operator/(double k){return Point3D(x/k,y/k,z/k);}
  double norm(){return x*x+y*y+z*z;}
  double abs(){return sqrt(norm());}
  bool operator < (const Point3D &p) const{
    if(x!=p.x) return x<p.x;
    if(y!=p.y) return y<p.y;
    return z<p.z;
  }
  bool operator == (const Point3D &p) const{
    return fabs(x-p.x)<EPS && fabs(y-p.y)<EPS && fabs(z-p.z)<EPS;
  }
};
istream &operator >> (istream &is,Point3D &p){
  is>>p.x>>p.y>>p.z;
  return is;
}
ostream &operator << (ostream &os,Point3D p){
  os<<fixed<<setprecision(12)<<p.x<<" "<<p.y<<" "<<p.z;
  return os;
}

typedef Point3D Vector3D;
typedef vector<Point3D> Polygon3D;

struct Segment3D{
  Point3D p1,p2;
  Segment3D(){}
  Segment3D(Point3D p1, Point3D p2):p1(p1),p2(p2){}
};
typedef Segment3D Line3D;

istream &operator >> (istream &is,Segment3D &s){
  is>>s.p1>>s.p2;
  return is;
}

struct Sphere{
  Point3D c;
  double r;
  Sphere(){}
  Sphere(Point3D c,double r):c(c),r(r){}
};

istream &operator >> (istream &is,Sphere &c){
  is>>c.c>>c.r;
  return is;
}

double norm(Vector3D a){
  return a.x*a.x+a.y*a.y+a.z*a.z;
}
double abs(Vector3D a){
  return sqrt(norm(a));
}
double dot(Vector3D a,Vector3D b){
  return a.x*b.x+a.y*b.y+a.z*b.z;
}
Vector3D cross(Vector3D a,Vector3D b){
  return Vector3D(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}

Point3D project(Line3D l,Point3D p){
  Point3D b=l.p2-l.p1;
  double t=dot(p-l.p1,b)/norm(b);
  return l.p1+b*t;
}

double getDistanceLP(Line3D l,Point3D p){
  return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment3D s,Point3D p){
  if(dot(s.p2-s.p1,p-s.p1) < 0.0 ) return abs(p-s.p1);
  if(dot(s.p1-s.p2,p-s.p2) < 0.0 ) return abs(p-s.p2);
  return getDistanceLP(s,p);
}

bool intersectSC(Segment3D s,Sphere c){
  double d=getDistanceSP(s,c.c);
  if(d>c.r) return 0;
  return !((abs(s.p1-c.c)<=c.r)&&(abs(s.p2-c.c)<=c.r));
}


signed main(){
  int n;
  while(cin>>n,n){
    Vector3D v;
    cin>>v;
    Sphere s[n];
    for(int i=0;i<n;i++) cin>>s[i];
    Point3D p(0,0,0);
    int last=-1;
    while(1){
      Segment3D ss(p,p+v*1e7);
      bool f=0;
      for(int i=0;i<n;i++){
	if(i==last) continue;
	//cout<<i<<":"<<getDistanceSP(ss,s[i].c)<<" "<<s[i].r<<endl;
	if(getDistanceSP(ss,s[i].c)<=s[i].r) f=1;
      }
      if(!f) break;
      double l=0,r=1e7;
      for(int k=0;k<100;k++){
	double m=(l+r)/2;
	ss=Segment3D(p,p+v*m);
	f=0;
	for(int i=0;i<n;i++){
	  if(i==last) continue;
	  if(getDistanceSP(ss,s[i].c)<=s[i].r) f=1;
	}
	if(f) r=m;
	else l=m;
      }
      ss=Segment3D(p,p+v*r);
      f=0;
      for(int i=0;i<n;i++){
	if(i==last) continue;
	if(getDistanceSP(ss,s[i].c)<=s[i].r){
	  last=i;
	  break;
	}
      }
      p=ss.p2;
      Vector3D nm=p-s[last].c;
      nm=nm/abs(nm);
      double len=dot(nm,v);
      v=v-nm*len*2;
    }
    cout<<p<<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3188
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;

double eps = 1e-8, PI = acos(-1);

double Sqrt(double x){
  return (x<0?0:sqrt(x));
}

bool eq(double a, double b){
  return (-eps<a-b&&a-b<eps);
}

struct Point{
  double x,y,z;
  Point (double a=0,double b=0,double c=0): x(a),y(b),z(c) {}
  Point operator + (const Point &p)const{
    return Point(x+p.x,y+p.y,z+p.z);
  }
  Point operator - (const Point &p)const{
    return Point(x-p.x,y-p.y,z-p.z);
  }
  Point operator * (const double &r)const{
    return Point(x*r,y*r,z*r);
  }
  Point operator / (const double &r)const{
    return Point(x/r,y/r,z/r);
  }
};

typedef Point Vector;

double dot(Point a,Point b){
  return a.x*b.x+a.y*b.y+a.z*b.z;
}

Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return Point(nx,ny,nz);
}

double norm(Point a){
  return dot(a,a);
}

double abs(Point a){
  return sqrt( norm(a) );
}

struct Line{
  Point p;
  Vector v;
  Line(Point a=Point(),Vector b=Vector()):p(a),v(b){}
};

struct Plane{
  Point p;
  Vector v0,v1;
  Plane(Point a=Point(),Vector b=Vector(),Vector c=Vector())
    :p(a),v0(b),v1(c){}
};

Vector cross(Plane p){
  return cross(p.v0,p.v1);
}

struct Ball{
  Point p;
  double r;
  Ball(Point a=Point(),double b=1.0):p(a),r(b){}
};

vector<Point> getCrossPoint(Ball s,Line t){
  vector<Point> res;
  Vector a=s.p-t.p;
  Vector b=t.v;
  double base=dot(a,b)/abs(b);
  double hh=norm(cross(a,b))/norm(b);
  if(s.r*s.r+eps < hh )return res;
  double w=Sqrt( s.r*s.r - hh );
  res.push_back(t.p+t.v/abs(t.v)*(base-w));
  res.push_back(t.p+t.v/abs(t.v)*(base+w));
  return res;
}

Point reflect(Point sp,Vector sk,Point t){
  return t-sk*dot(sk,t-sp)*2.0/norm(sk);
}

int n;
Point v;
Ball t[100];

void solve(){
  Line a=Line( Point() , v );
  while(1){
    Line next;
    double mini=1e9;
    for(int i=0;i<n;i++){
      vector<Point> u=getCrossPoint(t[i],a);
      for(int j=0;j<(int)u.size();j++){
        Point np=u[j];
        double dist=abs(np-a.p);
        if(dist<eps)continue;
        if(dot(np-a.p,a.v)<0)continue;
        if(dist<mini){
          mini=dist;
          next.p=np;
          next.v=reflect(np,np-t[i].p,np+a.v)-np;
        }
      }
    }
    if(mini==1e9)break;
    a=next;
  }
  printf("%.8f %.8f %.8f\n",a.p.x,a.p.y,a.p.z);
}

int main(){
  while(1){
    cin>>n;
    if(n==0)break;
    cin>>v.x>>v.y>>v.z;
    for(int i=0;i<n;i++)cin>>t[i].p.x>>t[i].p.y>>t[i].p.z>>t[i].r;
    solve();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1256
final_rank: 4

code_snippet: #include <bits/stdc++.h>

using namespace std;

namespace {

    typedef double real;
    real EPS = 1e-8;

    struct Point {
        real x, y, z;
        Point() {}
        Point(real x, real y, real z) : x(x), y(y), z(z) {}
    };
    Point operator+(const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y, a.z + b.z); }
    Point operator-(const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y, a.z - b.z); }
    Point operator*(const Point& a, real k) { return Point(a.x * k, a.y * k, a.z * k); }
    Point operator/(const Point& a, real k) { return a * (1.0 / k); }
    istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y >> p.z; }
    ostream& operator<<(ostream& os, const Point& p) { return os << "Point(" << p.x << "," << p.y << "," << p.z << ")"; }
    real dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
    real norm(const Point& a) { return sqrt(dot(a, a)); }
    real cos(const Point& a, const Point& b) { return dot(a, b) / (norm(a) * norm(b)); }
    real dist(const Point& a, const Point& b) {
        real dx = a.x - b.x;
        real dy = a.y - b.y;
        real dz = a.z - b.z;
        return sqrt(dx * dx + dy * dy + dz * dz);
    }

    struct Line {
        Point a, b;
        Line(Point a, Point b) : a(a), b(b) {}
    };
    Point projection(const Line& l, const Point& p) {
        Point u = (p - l.a), v = (l.b - l.a);
        return l.a + (v / norm(v)) * (dot(u, v) / norm(v));
    }
    Point reflection(const Line& l, const Point& p) {
        Point h = projection(l, p);
        return p + (h - p) * 2;
    }
    real dist(const Line& l, const Point& p) {
        Point q = projection(l, p);
        return norm(p - q);
    }

    int N;
    Point U;
    vector<Point> Q; vector<real> R;
    bool input() {
        cin >> N;
        if (N == 0) return false;
        cin >> U;
        Q.clear(); Q.resize(N);
        R.clear(); R.resize(N);
        for (int i = 0; i < N; i++) {
            cin >> Q[i] >> R[i];
        }
        return true;
    }

    bool reflect(const Point& org, const Point& v, int sphere_index) {
        int n = sphere_index;
        Point p = Q[n] - org;
        real cos_phi = cos(v, p);
        if (cos_phi < -EPS) return false;
        return dist(Line(org, org + v), Q[n]) < R[n];
    }
    pair<Point, Point> ref(const Point& org, const Point& v, int sphere_index) {
        int n = sphere_index;
        Point p = Q[n] - org;
        real cos_phi = cos(v, p);
        real d = dist(org, Q[n]);
        real r = R[n];
        real x = d * cos_phi - sqrt( (d * cos_phi) * (d * cos_phi) - d * d + r * r );
        Point refpoint = org + v / norm(v) * x;
        Point refvector = reflection(Line(Q[n], refpoint), org) - refpoint;
        return make_pair(refpoint, refvector);
    }

    pair<Point, Point> next(const Point& org, const Point& v) {
        vector< pair<Point, Point> > refs;
        for (int i = 0; i < N; i++) {
            if (reflect(org, v, i)) {
                refs.push_back(ref(org, v, i));
            }
        }
        if (refs.empty()) throw "foo";
        pair<Point, Point> r = refs[0];
        real d = dist(org, refs[0].first);
        for (int i = 0; i < refs.size(); i++) {
            real nd = dist(org, refs[i].first);
            if (nd < d) {
                d = nd;
                r = refs[i];
            }
        }
        return r;
    }

    void solve() {
        Point org(0, 0, 0);
        Point u = U;
        try {
            while (true) {
                pair<Point, Point> r = next(org, u);
                org = r.first;
                u = r.second;
            }
        } catch (const char* e) {
            printf("%.8f %.8f %.8f\n", org.x, org.y, org.z);
        }
    }
}

int main() {
    while (input()) solve();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1336
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
typedef double D;
struct P{
	D x,y,z;
	P(D a,D b,D c){x=a,y=b,z=c;}
};
P operator+(P a,P b){
	return P(a.x+b.x,a.y+b.y,a.z+b.z);
}
P operator-(P a,P b){
	return P(a.x-b.x,a.y-b.y,a.z-b.z);
}
P operator*(P a,D b){
	return P(a.x*b,a.y*b,a.z*b);
}
P operator/(P a,D b){
	return P(a.x/b,a.y/b,a.z/b);
}
typedef pair<P,P> L;
D dot(P a,P b){return a.x*b.x+a.y*b.y+a.z*b.z;}
D norm(P a){return dot(a,a);}
P perp(L l,P p){
	D t=dot(p-l.fs,l.fs-l.sc)/norm(l.fs-l.sc);
	return l.fs+(l.fs-l.sc)*t;
}
P refl(L l,P p){
	return p+(perp(l,p)-p)*2.0;
}
double x_[100],y_[100],z_[100],r_[100];
int main(){
	while(true){
		int N;
		cin>>N;
		if(N==0) break;
		double a=0,b=0,c=0,d,e,f;
		cin>>d>>e>>f;
		rep(i,N) cin>>x_[i]>>y_[i]>>z_[i]>>r_[i];
		while(true){
			int id=-1;
			double mn=1e9;
			rep(i,N){
				double x=x_[i],y=y_[i],z=z_[i],r=r_[i];
				double A=d*d+e*e+f*f;
				double B=2*(d*(a-x)+e*(b-y)+f*(c-z));
				double C=(a-x)*(a-x)+(b-y)*(b-y)+(c-z)*(c-z)-r*r;
				double D=B*B-4*A*C;
				if(D<0) continue;
				double t=(-B-sqrt(D))/(2*A);
				if(t<1e-7) continue;
				if(t<mn) mn=t,id=i;
			}
			if(id<0){
				printf("%.4f %.4f %.4f\n",a,b,c);
				break;
			}
			double t=mn;
			double na=a+t*d,nb=b+t*e,nc=c+t*f;
			P p(a,b,c);
			P np(na,nb,nc);
			L l=L(P(x_[id],y_[id],z_[id]),np);
			P ref=refl(l,p);
			P nd=ref-np;
			nd=nd/norm(nd);
			a=na,b=nb,c=nc;
			d=nd.x,e=nd.y,f=nd.z;
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1240
final_rank: 1

code_snippet: #include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <memory>
#include <cstring>
#include <cassert>
#include <numeric>
#include <sstream>
#include <complex>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
#include <unordered_map>
#include <unordered_set>
using namespace std;

#define REP2(i, m, n) for (int i = (int)(m); i < (int)(n); i++)
#define REP(i, n) REP2(i, 0, n)
#define ALL(S) (S).begin(), (S).end()

template <typename T, typename E>
ostream &operator<<(std::ostream &os, const std::pair<T, E> &p){
  return os << "(" << p.first << ", " << p.second << ")";
}

typedef long long ll;

struct xyz_t {
  double x;
  double y;
  double z;
  friend bool operator<(const xyz_t &p, const xyz_t &q){
    return p.x != q.x ? p.x < q.x : p.y != q.y ? p.y < q.y : p.z < q.z;
  }
  friend ostream &operator<<(ostream &os, const xyz_t &p){
    os << "(" << p.x << ", " << p.y << ", " << p.z << ")";
    return os;
  }
};

inline double dot(const xyz_t &p1, const xyz_t &p2){
  return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z;
}

inline double norm(const xyz_t &p){
  return dot(p, p);
}

inline double abs(const xyz_t &p){
  return sqrt(norm(p));
}

xyz_t direction(const xyz_t &p1, const xyz_t &p2){
  xyz_t vec;
  vec.x = p2.x - p1.x;
  vec.y = p2.y - p1.y;
  vec.z = p2.z - p1.z;
  return vec;
}

void normalize(xyz_t &p){
  double l = abs(p);
  p.x /= l; p.y /= l; p.z /= l;
}

xyz_t operator+(const xyz_t &p1, const xyz_t &p2){
  xyz_t p;
  p.x = p1.x + p2.x;
  p.y = p1.y + p2.y;
  p.z = p1.z + p2.z;
  return p;
}

xyz_t operator-(const xyz_t &p1, const xyz_t &p2){
  xyz_t p;
  p.x = p1.x - p2.x;
  p.y = p1.y - p2.y;
  p.z = p1.z - p2.z;
  return p;
}

xyz_t operator*(const xyz_t &p1, double scale){
  xyz_t p;
  p.x = p1.x * scale;
  p.y = p1.y * scale;
  p.z = p1.z * scale;
  return p;
}


double distance(const xyz_t &p1, const xyz_t &p2){
  return abs(p2 - p1);
}

bool intersect(xyz_t curr, xyz_t dir, const pair<xyz_t, double> &C){
  normalize(dir);
  double t = dot(direction(curr, C.first), dir);
  xyz_t  p = curr + dir * t;
  // cout << t << " " << p << endl;
  return t > 0 && distance(p, C.first) < C.second;
}

xyz_t crossing_point(xyz_t curr, xyz_t dir, const pair<xyz_t, double> &C){
  normalize(dir);
  double t = dot(direction(curr, C.first), dir);
  xyz_t  p = curr + dir * t;
  double d = sqrt(C.second * C.second - norm(p - C.first));
  return curr + dir * (t - d);
  
}

int main(){
  ios::sync_with_stdio(false);
  int N;
  while (cin >> N && N){
    xyz_t vec;
    vector<pair<xyz_t, double> > cs(N);
    cin >> vec.x >> vec.y >> vec.z;
    
    REP(i, N){
      cin >> cs[i].first.x >> cs[i].first.y >> cs[i].first.z >> cs[i].second;
    }
    
    xyz_t last;
    last.x = last.y = last.z = 0;
    
    while (true){
      // cout << last << endl;
      vector<tuple<double, int, xyz_t> > ps;
      
      REP(i, N) if (intersect(last, vec, cs[i])){
        // cout << last << " " << vec << " " << cs[i].first << " " << cs[i].second << endl;
        xyz_t p = crossing_point(last, vec, cs[i]);
        // cout << p << endl;
        ps.push_back(make_tuple(distance(p, last), i, p));
      }
      sort(ALL(ps));
      if (ps.empty()){
        break;
      }

      xyz_t a = get<2>(ps[0]) - cs[get<1>(ps[0])].first;
      xyz_t v = last - get<2>(ps[0]);
      vec = a * 2 * (dot(a, v) / dot(a, a)) - v;
      normalize(vec);
      // cout << a << " " << v << " " << dot(a, v) << " " << get<2>(ps[0]) << " " << vec << endl;
      // break;
      
      last = get<2>(ps[0]);
    }
    
    printf("%.10lf %.10lf %.10lf\n", last.x, last.y, last.z);
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1276
final_rank: 11

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <cstdio>

using namespace std;

class P3 {
public:
	double x, y, z;
	P3(double x=0, double y=0, double z=0) : x(x), y(y), z(z) {}
	P3(const P3& p) : x(p.x), y(p.y), z(p.z) {}
	P3 operator + (const P3 &p) const { return P3(x+p.x, y+p.y, z+p.z); }
	P3 operator - (const P3 &p) const { return P3(x-p.x, y-p.y, z-p.z); }
	P3 operator * (double p) const { return P3(x*p, y*p, z*p); }
	void scale(double s){ x *= s, y *= s, z *= s; }
	double dot(const P3& p) const { return x*p.x + y*p.y + z*p.z; }
	double squaredLength() const { return x*x + y*y + z*z; }
	double length() const { return sqrt(squaredLength()); }
	double normalize(){ double L = length(); if(L>0) scale(1.0/L); return L; }
};

int main(){
	int N;
	while(cin >> N && N){
		P3 pos(0, 0, 0), dir;
		cin >> dir.x >> dir.y >> dir.z;
		dir.normalize();
		vector< pair<P3, double> > vp(N);
		for(int i=0;i<N;i++){
			cin >> vp[i].first.x >> vp[i].first.y >> vp[i].first.z >> vp[i].second;
		}
		while(true){
			bool end = true;
			double nearest = 1e12;
			P3 npos, ndir;
			for(int i=0;i<N;i++){
				P3 p(vp[i].first - pos);
				double l = dir.dot(p);
				p = p - dir*l;
				double dist = p.length();
				if(dist > vp[i].second - 1e-8) continue;
				double sub = sqrt(vp[i].second*vp[i].second - dist*dist);
				if(l-sub > 0 && nearest > l-sub){
					nearest = l-sub;
					npos = pos + dir*(l-sub);
					P3 ref(npos-vp[i].first);
					ref.normalize();
					ndir = dir - ref*dir.dot(ref)*2.0;
					end = false;
				}
			}
			if(end) break;
			pos = npos;
			dir = ndir;
		}
		printf("%.8lf %.8lf %.8lf\n", pos.x, pos.y, pos.z);
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1256
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <cmath>
#include <cstdio>

using namespace std;

class P3 {
public:
	double x, y, z;
	P3(double x=0, double y=0, double z=0) : x(x), y(y), z(z) {}
	P3(const P3& p) : x(p.x), y(p.y), z(p.z) {}
	void set(const P3& p){ x = p.x, y = p.y, z = p.z; }
	void set(double px, double py, double pz){ x = px, y = py, z = pz; }
	P3 operator + (const P3 &p) const { return P3(x+p.x, y+p.y, z+p.z); }
	P3 operator - (const P3 &p) const { return P3(x-p.x, y-p.y, z-p.z); }
	P3 operator * (double p) const { return P3(x*p, y*p, z*p); }
	void add(const P3& p){ x += p.x, y += p.y, z += p.z; }
	void sub(const P3& p){ x -= p.x, y -= p.y, z -= p.z; }
	void scale(double s){ x *= s, y *= s, z *= s; }
	double dot(const P3& p) const { return x*p.x + y*p.y + z*p.z; }
	double squaredLength() const { return x*x + y*y + z*z; }
	double length() const { return sqrt(squaredLength()); }
	double normalize(){ double L = length(); if(L>0) scale(1.0/L); return L; }
};

int main(){
	int N;
	while(cin >> N && N){
		P3 pos(0, 0, 0), dir;
		cin >> dir.x >> dir.y >> dir.z;
		dir.normalize();
		vector< pair<P3, double> > vp(N);
		for(int i=0;i<N;i++){
			cin >> vp[i].first.x >> vp[i].first.y >> vp[i].first.z >> vp[i].second;
		}
		while(true){
			bool end = true;
			double nearest = 1e12;
			P3 npos, ndir;
			for(int i=0;i<N;i++){
				P3 p(vp[i].first);
				p.sub(pos);
				double l = dir.dot(p);
				p.sub(dir*l);
				double dist = p.length();
				if(dist > vp[i].second - 1e-8) continue;
				double sub = sqrt(vp[i].second*vp[i].second - dist*dist);
				if(l-sub > 0 && nearest > l-sub){
					nearest = l-sub;
					npos.set(pos);
					npos.add(dir*(l-sub));
					ndir.set(dir);
					ndir.scale(-1);
					P3 ref(npos-vp[i].first);
					ref.normalize();
					P3 add(ndir);
					ref.scale(ndir.dot(ref));
					add.sub(ref);
					add.scale(-2.0);
					ndir.add(add);
					end = false;
				}
			}
			if(end) break;
			pos.set(npos);
			dir.set(ndir);
		}
		printf("%.8lf %.8lf %.8lf\n", pos.x, pos.y, pos.z);
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1252
final_rank: 3

code_snippet: #include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>

using namespace std;
static const double EPS = 1e-8;
inline int sign(double x){ return abs(x) < EPS ? 0 : (x > 0 ? 1 : -1); }

struct Point3D {
	double x, y, z;
	Point3D() : x(0), y(0), z(0) { }
	Point3D(double x, double y, double z) : x(x), y(y), z(z) { }

	Point3D operator-() const { return Point3D(-x, -y, -z); }
	Point3D operator+(const Point3D &p) const {
		return Point3D(x + p.x, y + p.y, z + p.z);
	}
	Point3D operator-(const Point3D &p) const {
		return Point3D(x - p.x, y - p.y, z - p.z);
	}
	Point3D operator*(const double s) const {
		return Point3D(x * s, y * s, z * s);
	}
	Point3D operator/(const double s) const {
		return Point3D(x / s, y / s, z / s);
	}
};

struct Line3D {
	Point3D a, b;
	Line3D() : a(), b() { }
	Line3D(const Point3D &a, const Point3D &b) : a(a), b(b) { }
};

struct Sphere {
	Point3D c;
	double r;
	Sphere() : c(), r(0) { }
	Sphere(const Point3D &c, double r) : c(c), r(r) { }
};

inline double dot(const Point3D &a, const Point3D &b){
	return a.x * b.x + a.y * b.y + a.z * b.z;
}
inline Point3D cross(const Point3D &a, const Point3D &b){
	return Point3D(
		a.y * b.z - a.z * b.y,
		a.z * b.x - a.x * b.z,
		a.x * b.y - a.y * b.x);
}
inline double norm(const Point3D &p){
	return p.x * p.x + p.y * p.y + p.z * p.z;
}
inline double abs(const Point3D &p){
	return sqrt(norm(p));
}
inline Point3D unit(const Point3D &p){
	return p / abs(p);
}
inline Point3D vec(const Line3D &l){
	return l.b - l.a;
}

inline Point3D projection(const Line3D &l, const Point3D &p){
	const Point3D v = vec(l);
	return l.a + v * (dot(p - l.a, v) / norm(v));
}
inline Point3D reflection(const Line3D &l, const Point3D &p){
	const Point3D q = projection(l, p);
	return q + q - p;
}

inline bool intersectLP(const Line3D &l, const Point3D &p){
	return !sign(norm(cross(p - l.a, vec(l))));
}
inline bool intersectSP(const Line3D &l, const Point3D &p){
	const Point3D a = p - l.a, b = vec(l);
	if(norm(a) < EPS || norm(a - b) < EPS){ return true; }
	if(norm(cross(a, b)) > EPS){ return false; }
	if(sign(a.x * b.x) < 0){ return false; }
	if(sign(a.y * b.y) < 0){ return false; }
	if(sign(a.z * b.z) < 0){ return false; }
	return norm(a) < norm(b);
}
inline double distanceLP(const Line3D &l, const Point3D &p){
	const Point3D q = projection(l, p);
	return abs(p - q);
}
inline double distanceSP(const Line3D &l, const Point3D &p){
	const Point3D u = p - l.a;
	const Point3D v = projection(Line3D(Point3D(), vec(l)), u);
	if(intersectSP(Line3D(Point3D(), vec(l)), v)){ return abs(u - v); }
	return sqrt(min(norm(p - l.a), norm(p - l.b)));
}

vector<Point3D> crosspointCL(const Sphere &s, const Line3D &l){
	const Point3D &p = projection(l, s.c);
	const double d2 = norm(s.c - p);
	if(d2 > s.r * s.r + EPS){ return vector<Point3D>(); }
	if(d2 > s.r * s.r - EPS){ return vector<Point3D>(1, p); }
	const double sc = sqrt(s.r * s.r - d2);
	vector<Point3D> ret;
	ret.push_back(p + unit(vec(l)) * sc);
	ret.push_back(p - unit(vec(l)) * sc);
	return ret;
}
vector<Point3D> crosspointCS(const Sphere &s, const Line3D &l){
	const vector<Point3D> ps = crosspointCL(s, l);
	vector<Point3D> ret;
	for(int i = 0; i < ps.size(); ++i){
		if(intersectSP(l, ps[i])){ ret.push_back(ps[i]); }
	}
	return ret;
}

bool intersectCL(const Sphere &s, const Line3D &l){
	return distanceLP(l, s.c) < s.r + EPS;
}
bool intersectCS(const Sphere &s, const Line3D &l){
	return !crosspointCS(s, l).empty();
}

int main(){
	ios_base::sync_with_stdio(false);
	cout << setiosflags(ios::fixed) << setprecision(10);
	const double length = 1000.0;
	while(true){
		int n;
		cin >> n;
		if(n == 0){ break; }
		Point3D init;
		cin >> init.x >> init.y >> init.z;
		vector<Sphere> spheres(n);
		for(int i = 0; i < n; ++i){
			double x, y, z, r;
			cin >> x >> y >> z >> r;
			spheres[i] = Sphere(Point3D(x, y, z), r);
		}
		Line3D cur(Point3D(), unit(init) * length);
		Point3D answer;
		while(true){
			double best_length = length;
			Line3D next;
			for(int i = 0; i < n; ++i){
				if(abs(abs(spheres[i].c - cur.a) - spheres[i].r) < EPS){
					continue;
				}
				const vector<Point3D> ps = crosspointCS(spheres[i], cur);
				if(ps.empty()){ continue; }
				double l = length;
				int key = 0;
				for(int j = 0; j < ps.size(); ++j){
					const double t = abs(ps[j] - cur.a);
					if(t >= l){ continue; }
					l = t;
					key = j;
				}
				if(l >= best_length){ continue; }
				best_length = l;
				answer = ps[key];
				const Point3D r =
					reflection(Line3D(spheres[i].c, answer), cur.a);
				next = Line3D(answer, answer + unit(r - answer) * length);
			}
			if(best_length >= length){ break; }
			cur = next;
		}
		cout << answer.x << " " << answer.y << " " << answer.z << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1312
final_rank: 14

code_snippet: #include<iostream>
#include<vector>
#include<array>
#include<cmath>

using namespace std;

typedef array<double,3> P3;

P3 operator-(P3 p){
  return P3{-p[0],-p[1],-p[2]};
}

P3 operator+(P3 a,P3 b){
  return P3{a[0]+b[0],a[1]+b[1],a[2]+b[2]};
}

P3 operator-(P3 a,P3 b){
  return a+-b;
}

P3 operator-=(P3 &a,P3 b){
  return a=a-b;
}
  
P3 operator*(P3 p,double d){
  return P3{p[0]*d,p[1]*d,p[2]*d};
}
  
P3 operator/(P3 p,double d){
  return p*(1/d);
}

double dot(P3 a,P3 b){
  return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
}

double abs(P3 p){
  return sqrt(dot(p,p));
}

P3 cross(P3 a,P3 b){
  return P3{a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]};
}
  
P3 Rodrigues(P3 r,P3 base,double phy){
  P3 n=base/abs(base);
  P3 nnr=n*dot(n,r);
  return nnr+(r-nnr)*cos(phy)+cross(n,r)*sin(phy);
}

P3 closest_to_origin(P3 a,P3 b){
  P3 x=a-b;
  return b+x*-dot(b,x)/dot(x,x);
}

vector<P3> intersection(P3 p,double r,P3 a,P3 b){
  a-=p;
  b-=p;
  P3 cp=closest_to_origin(a,b);
  double d=abs(cp);
  if(d>r){
    return {};
  }else{
    P3 x=a-b;
    double f=sqrt(r*r-d*d)/abs(x);
    return {cp+x*f+p,cp+x*-f+p};
  }
}


int main(){
  for(int N;cin>>N,N;){
    double u,v,w;
    cin>>u>>v>>w;
    P3 p[100];
    int r[100];
    for(int i=0;i<N;i++){
      double x,y,z;
      cin>>x>>y>>z>>r[i];
      p[i]=P3{x,y,z};
    }
    P3 f{0,0,0},t{u,v,w};
    for(;;){
      double d=1e99;
      P3 nf,nt;
      for(int i=0;i<N;i++){
	if(dot(t-f,p[i]-f)>0){
	  auto res=intersection(p[i],r[i],t,f);
	  for(auto e:res){
	    if(abs(e-f)<d){
	      d=abs(e-f);
	      nf=e;
	      nt=Rodrigues(f-nf,nf-p[i],2*acos(0))+nf;
	    }
	  }
	}
      }
      if(d>1e98)break;
      f=nf;
      t=nt;
    }
    for(int i=0;i<3;i++){
      cout.precision(9);
      cout<<fixed<<f[i]<<" \n"[i==2];
    }
  }
}
accuracy: 1
time_ms: 10
memory_kb: 1296
final_rank: 13

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <iterator>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) container.begin(), container.end()
#define RALL(container) container.rbegin(), container.rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}

const int INF = 1<<28;
const double EPS = 1e-8;
const int MOD = 1000000007;


#define EPS 1.0e-10
inline int signum(double x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }

struct P{
	double x, y, z;
	P():x(0),y(0),z(0){}
	P(double a, double b, double c):x(a),y(b),z(c){}
	
	P operator+(const P &opp){
		return P(x+opp.x, y+opp.y, z+opp.z);
	}
	P operator-(const P &opp){
		return P(x-opp.x, y-opp.y, z-opp.z);
	}
	P operator/(const P &opp){
		return P(abs(opp.x)<EPS?0:x/opp.x, abs(opp.y)<EPS?0:y/opp.y, abs(opp.z)<EPS?0:z/opp.z);
	}
	P operator/(const double &opp){
		return P(x/opp, y/opp, z/opp);
	}
	P operator*(const double opp){
		return P(x*opp, y*opp, z*opp);
	}
	friend ostream& operator<<(ostream &os, const P &t) { return os<<"("<<t.x<<","<<t.y<<","<<t.z<<")";}
};

struct L{
	P pos, dir;
	L(){}
	L(P p, P d):pos(p),dir(d){}
	L(P d):pos(),dir(d){}
};

struct C{
	P p;
	double r;
	C(){}
	C(P q, double s):p(q),r(s){}
};

inline double inp(P v1, P v2){
	return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}

inline P outp(P p1, P p2){
	return P(p1.y*p2.z - p1.z*p2.y, p1.z*p2.x - p1.x*p2.z, p1.x*p2.y - p1.y*p2.x);
}

inline double norm(P v){
	return v.x*v.x + v.y*v.y + v.z*v.z;
}
inline double abs(P v){
	return sqrt(norm(v));
}

inline P perf(P v1, L l){
	return l.pos + l.dir*(inp(v1-l.pos, l.dir)/norm(l.dir));
}

bool lp_intersect(L l, P t){	// 点が直線上にあるかどうか
	return !signum(norm(outp(t-l.pos, l.dir)));
}

bool sp_intersect(L l, P t){	// 点が線分上にあるかどうか
	P a(t-l.pos), b(l.dir);
	if(signum(norm(a)) == 0 || signum(norm(a-b)) == 0) return true;	// 端点
	if(signum(norm(outp(a, b)))) return false;	// 直線上にない
	if(signum(a.x*b.x) == -1 || signum(a.y*b.y) == -1 || signum(a.z*b.z) == -1) return false;	// 逆方向
	if(norm(a) < norm(b)) return true;
	return false;	// イキスギィ！
}

double sp_distance(L l, P t){
	P v1 = t-l.pos;
	P v2 = perf(v1, L(l.dir));
	if(sp_intersect(L(l.dir), v2)) return abs(v1 - v2);
	else return sqrt(min(norm(t-l.pos), norm(t-(l.pos + l.dir))));
}

double sp_distance(P t, P p1, P p2){
	return sp_distance(L(p1, p2-p1), t);
}

vector<P> cl_crosspoint(C c, L l){
	P p = perf(c.p, l);
	double d2 = norm(c.p-p);
	if(d2 > c.r*c.r + EPS) return vector<P>();
	if(d2 > c.r*c.r - EPS) return vector<P>(1, p);	//境界
	double s = sqrt(c.r*c.r - d2);
	vector<P> ret;
	ret.push_back(p + l.dir/abs(l.dir)*s);
	ret.push_back(p - l.dir/abs(l.dir)*s);
	return ret;
}

vector<P> cs_crosspoint(C c, L l){
	vector<P> ret, res = cl_crosspoint(c, l);
	REP(i, res.size()) if(sp_intersect(l, res[i])) ret.push_back(res[i]);
	return ret;
}

bool cl_intersect(C c, L l){
	return sp_distance(l, c.p) < c.r + EPS;	// 境界を含む
}

bool cs_intersect(C c, L l){
	return !cs_crosspoint(c, l).empty();
}

P reflect(P p, L l){
	P q = perf(p, l);
	return q + (q - p);
}


int n;

main(){
	int i,j;
	while(cin >> n, n){
		vector<C> c;
		double x, y, z, r;
		cin >> x >> y >> z;
		L s(P(x*100, y*100, z*100));
		REP(i, n){
			cin >> x >> y >> z >> r;
			c.push_back(C(P(x, y, z), r));
		}
		P ans(0, 0, 0);
		while(1){
			pair<double, L> csp(1e10, L());
//			cout << "s: " << s.pos << " -> " << s.dir << endl;
			REP(i, n){
				vector<P> ret = cs_crosspoint(c[i], s);
				REP(j, ret.size()){
					if(norm(ret[j] - s.pos) > EPS && csp.first > norm(ret[j] - s.pos))
						csp = pair<double, L>(norm(ret[j] - s.pos), L(ret[j], c[i].p-ret[j]));
				}
			}
			if(csp.first > 1e9) break;
			ans = csp.second.pos;
			P ref = reflect(s.pos, csp.second);
//			cout << "reflect: " << ans << endl;
//			cout << "d: " << ref << endl;
			s = L(csp.second.pos, ref - csp.second.pos);
			s.dir = s.dir/abs(s.dir)*1000;
		}
		printf("%.4f %.4f %.4f\n", ans.x, ans.y, ans.z);
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1264
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define dump(n) cout<<"# "<<#n<<'='<<(n)<<endl
#define repi(i,a,b) for(int i=int(a);i<int(b);i++)
#define peri(i,a,b) for(int i=int(b);i-->int(a);)
#define rep(i,n) repi(i,0,n)
#define per(i,n) peri(i,0,n)
#define all(c) begin(c),end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

const int INF=1e9;
const int MOD=1e9+7;
const double EPS=1e-9;

template<typename T1,typename T2>
ostream& operator<<(ostream& os,const pair<T1,T2>& p){
	return os<<'('<<p.first<<','<<p.second<<')';
}
template<typename T>
ostream& operator<<(ostream& os,const vector<T>& a){
	os<<'[';
	rep(i,a.size()) os<<(i?" ":"")<<a[i];
	return os<<']';
}

struct Point{
	double x,y,z;
	Point(){}
	Point(double x,double y,double z):x(x),y(y),z(z){}
	Point& operator+=(Point p){x+=p.x,y+=p.y,z+=p.z; return *this;}
	Point& operator-=(Point p){x-=p.x,y-=p.y,z-=p.z; return *this;}
	Point& operator*=(double c){x*=c,y*=c,z*=c; return *this;}
	Point& operator/=(double c){x/=c,y/=c,z/=c; return *this;}
};
Point operator+(Point a,Point b){return a+=b;}
Point operator-(Point a,Point b){return a-=b;}
Point operator*(Point a,double c){return a*=c;}
Point operator*(double c,Point a){return a*=c;}
Point operator/(Point a,double c){return a/=c;}
double Dot(Point a,Point b){return a.x*b.x+a.y*b.y+a.z*b.z;}
double Abs2(Point p){return Dot(p,p);}
double Abs(Point p){return sqrt(Abs2(p));}

struct Line{
	Point pos,dir;
	Line(){}
	Line(Point p,Point d):pos(p),dir(d){}
};

struct Sphere{
	Point center;
	double radius;
	Sphere(){}
	Sphere(Point c,double r):center(c),radius(r){}
	Sphere(double x,double y,double z,double r):center(x,y,z),radius(r){}
};

Point Proj(Line l,Point p){
	Point a=p-l.pos,b=l.dir;
	return l.pos+Dot(a,b)/Abs2(b)*b;
}
double DistLP(Line l,Point p){
	return Abs(Proj(l,p)-p);
}

pair<double,double> InterPoint(Sphere s,Line l){
	Point p=l.pos-s.center,d=l.dir;
	double a=Abs2(d),b=Dot(p,d),c=Abs2(p)-pow(s.radius,2);
	double t1=(-b-sqrt(b*b-a*c))/a;
	double t2=(-b+sqrt(b*b-a*c))/a;
	return mp(t1,t2);
}

ostream& operator<<(ostream& os,const Point& p){
	return os<<'('<<p.x<<','<<p.y<<','<<p.z<<')';
}

int main()
{
	for(int n;cin>>n && n;){
		Point d0; cin>>d0.x>>d0.y>>d0.z;
		vector<Sphere> ss(n);
		rep(i,n){
			double x,y,z,r; cin>>x>>y>>z>>r;
			ss[i]=Sphere(x,y,z,r);
		}
		
		Line l(Point(0,0,0),d0);
		for(;;){
			vd ts(n,INF);
			rep(i,n) if(DistLP(l,ss[i].center)<ss[i].radius){
				double t1,t2; tie(t1,t2)=InterPoint(ss[i],l);
				ts[i]=t1>EPS?t1:t2>EPS?t2:INF;
			}
			
			int i=min_element(all(ts))-begin(ts);
			if(ts[i]==INF){
				printf("%.4f %.4f %.4f\n",l.pos.x,l.pos.y,l.pos.z);
				break;
			}
			
			// aから球面上の点bで跳ね返りcへ
			Point a=l.pos,b=l.pos+l.dir*ts[i];
			Point p=Proj(Line(ss[i].center,b-ss[i].center),a);
			Point c=p+(p-a);
			l=Line(b,c-b);
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 1244
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
 
const double eps = 1e-8;
const double inf = 1e10;
 
bool equals(double a, double b) {
  return abs(a-b) < eps;
}
 
struct P {
  double x, y, z;
  P() : x(0), y(0), z(0) {}
  P(double x, double y, double z) : x(x), y(y), z(z) {}
};
 
P operator + (const P &a, const P &b) {
  return P(a.x+b.x, a.y+b.y, a.z+b.z);
}
P operator - (const P &a, const P &b) {
  return P(a.x-b.x, a.y-b.y, a.z-b.z);
}
P operator * (const P &p, const double &a) {
  return P(p.x*a, p.y*a, p.z*a);
}
P operator / (const P &p, const double &a) {
  return P(p.x/a, p.y/a, p.z/a);
}
 
double dot(P a, P b) {
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
double norm(P a) {
  return dot(a,a);
}
 
double abs(P a) {
  return sqrt(norm(a));
}
 
P project(P s1, P s2, P p) {
  P base = s2 - s1;
  double t = dot(p - s1, base)/norm(base);
  return s1 + base*t;
}
 
P reflect(P s1, P s2, P p) {
  return p + (project(s1, s2, p) - p)*2.0;
}
 
double getDistanceLP(P s1, P s2, P p) {
  return abs(project(s1, s2, p) - p);
}
 
P getQ(P s1, P s2, P p, double r) {
  P m = project(s1, s2, p);
  P base = s2 - s1;
  double x = r*r - norm(m-p);
  if(equals(x, 0.0)) x = 0.0;
  else if(x < 0) return P(inf,inf,inf);
  return m - base * sqrt(x) / abs(base);
}
 
int main() {
  int N;
  P v;
  vector<P> p;
  vector<double> r;
  while(cin >> N && N) {
    p.resize(N);
    r.resize(N);
    cin >> v.x >> v.y >> v.z;
    for(int i = 0; i < N; ++i) {
      cin >> p[i].x >> p[i].y >> p[i].z >> r[i];
    }
     
    P s, t;
    t = v;
    while(1) {
      double mini = inf;
      int k = -1;
      for(int i = 0; i < N; ++i) {
        P q = getQ(s, t, p[i], r[i]);
        if(q.x == inf) continue;
        if(dot(t-s, q-s) < eps) continue;
        double dist = abs(q - s);
        if(mini > dist) {
          mini = dist;
          k = i;
        }
      }
      if(k == -1) break;
      P q = getQ(s, t, p[k], r[k]);
      t = reflect(p[k], q, s);
      s = q;
    }
    printf("%.4f %.4f %.4f\n", s.x, s.y, s.z);
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1280
final_rank: 12

code_snippet: #include<bits/stdc++.h>
   
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define MAX 110
   
using namespace std;
   
//テッツセツεッツスツ、テッツセツづッツスツステッツセツづヲツ?ソテッツスツヲテッツセツづヲツ個嘉ゥツ敖凖ッツスツ、テッツセツづッツスツクテッツセツづッツスツュ Verifyテッツセツεッツスツ」テッツセツ?テァツ卍づッツスツ」テッツセツ?テヲツキツ古ッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツ」テッツセツ?テッツスツョテッツセツεッツスツ」テッツセツ?テッツスツォテッツセツεッツスツ」テッツセツ?テッツスツッVerifyテッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツヲテッツセツづ・ツエツ「テッツスツクテッツセツεッツスツ」テッツセツ??テッツスツ」テッツセツ?テッツスツヲテッツセツεッツスツ」テッツセツ?テ」ツ?・テッツスツ」テッツセツづ」ツ?、?
   
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
   
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
   
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
   
  bool operator < (const Point3d& p)const{
    return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:z<p.z);
  }
   
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
   
};
   
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
  bool operator == (const Segment3d& seg)const{
    return p[0] == seg.p[0] && p[1] == seg.p[1];
  }
};
   
typedef Point3d Vector3d;
typedef Segment3d Line3d;
   
   
   
   
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
   
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
   
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
   
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
   
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
   
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
   
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
   
   
   
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
   
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
   
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
   
  //テッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツォpテッツセツεッツスツ」テッツセツ?テ・ツ渉、テッツスツ」テッツセツ?テ」ツ?・テッツスツ」テッツセツ?テッツスツ」テッツセツεッツスツ」テッツセツ?テヲツキツ古ッツスツ・テッツセツ?テッツスツエテッツセツεッツスツ・テッツセツづゥツ敖津ヲツ堋療ッツスツ」テッツセツ??テッツスツ、テッツセツづッツスツクテッツセツづ・ツ伉嘉ッツスツィテッツセツづッツスツァテッツセツづヲツエツ・テッツスツ・テッツセツづッツスツステッツセツづッツスツ「テッツセツεッツスツ・テッツセツ??テッツスツ」テッツセツ?テッツスツィテッツセツεッツスツ」テッツセツ?テッツスツソテッツセツεッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;
   
  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
   
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
   
  // テッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツォpテッツセツεッツスツ」テッツセツ?テ・ツ渉、テッツスツ」テッツセツ?テ」ツ?・テッツスツ」テッツセツ?テッツスツ」テッツセツεッツスツ」テッツセツ?テヲツキツ古ッツスツ・テッツセツ?テッツスツエテッツセツεッツスツ・テッツセツづゥツ敖?テッツセツεッツスツ、テッツセツづッツスツクテッツセツづ・ツ伉嘉ッツスツィテッツセツづッツスツァテッツセツづヲツエツ・テッツスツ・テッツセツづッツスツステッツセツづッツスツ「テッツセツεッツスツ・テッツセツ??テッツスツ」テッツセツ?テッツスツィテッツセツεッツスツ」テッツセツ?テッツスツッテッツセツεッツスツ」テッツセツ?テッツスツソテッツセツεッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ?テゥツ卍崚ッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
   
  // テッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツォpテッツセツεッツスツ」テッツセツ?テ・ツ渉、テッツスツ」テッツセツ?テ」ツ?・テッツスツ」テッツセツ?テッツスツ」テッツセツεッツスツ」テッツセツ?テヲツキツ古ッツスツ・テッツセツ?テッツスツエテッツセツεッツスツ・テッツセツづゥツ敖?テッツセツεッツスツ、テッツセツづッツスツクテッツセツづ・ツ伉嘉ッツスツィテッツセツづッツスツァテッツセツづヲツエツ・テッツスツ・テッツセツづッツスツステッツセツづッツスツ「テッツセツεッツスツ・テッツセツ??テッツスツ」テッツセツ?テッツスツィテッツセツεッツスツ」テッツセツ?テッツスツソテッツセツεッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
   
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
   
inline Point3d rorateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
   
inline Point3d rorateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
   
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
          (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
          (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
   
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
          ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
          -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
   
   
class Plane3d{
public:
  Point3d normal_vector; //テッツセツεッツスツヲテッツセツづッツスツウテッツセツづゥツ卍崚ッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ」テッツセツづ篠エテ・ツ?姪ッツスツ」テッツセツづ」ツ?、テッツスツッテッツセツεッツスツ」テッツセツづ篠エテヲツ堋療ッツスツ」テッツセツづ篠エテッツスツォ
  double d; // テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツヲテッツセツづゥツウツエテッツスツケテッツセツεッツスツァテッツセツづッツスツィテッツセツづ・ツ?敕ッツスツ・テッツセツづッツスツシテッツセツ?normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
   
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
   
  //Verify AOJ 0115
  //テッツセツεッツスツヲテッツセツづッツスツウテッツセツづゥツ卍崚ッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ」テッツセツづ篠エテ・ツ?姪ッツスツ」テッツセツづ」ツ?、テッツスツッテッツセツεッツスツ」テッツセツづ篠エテヲツ堋療ッツスツ」テッツセツづ篠エテッツスツォnormal_vectorテッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツョテッツセツεッツスツッテッツセツづッツスツシテッツセツづ・ツヲツ・テッツスツァテッツセツづ」ツ?、テッツスツケテッツセツεッツスツ」テッツセツ?テ・ツ?敕ッツスツ」テッツセツづ」ツ?、テ・ツャツーテッツセツεッツスツ」テッツセツづ」ツ?、テヲツエツ・テッツスツィテッツセツづッツスツィテッツセツづヲツ堋療ッツスツァテッツセツづッツスツョテッツセツづァツ卍づッツスツ」テッツセツ?テ・ツ?姪ッツスツ」テッツセツづ」ツ?、?
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
   
  //テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツァテッツセツづ」ツ?、テッツスツケpテッツセツεッツスツ」テッツセツ?テッツスツョテッツセツεッツスツィテッツセツづッツスツキテッツセツづヲツ閉陛ッツスツゥテッツセツづ・ツエツ「テッツスツ「テッツセツεッツスツ」テッツセツづ」ツ?、テヲツエツ・テッツスツヲテッツセツづッツスツアテッツセツづ」ツ?・テッツスツ」テッツセツづ」ツ?、?テッツスツ」テッツセツづ」ツ?、?
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツョテッツセツεッツスツゥテッツセツ?テッツスツゥテッツセツεッツスツ・テッツセツづッツスツステッツセツづァツヲツソテッツスツ」テッツセツ?テッツスツェテッツセツεッツスツァテッツセツづ」ツ?、テッツスツケテッツセツεッツスツ」テッツセツづ」ツ?、テヲツエツ・テッツスツ」テッツセツ?テッツスツ、テッツセツεッツスツ」テッツセツ?テヲツケツ佚ッツスツ」テッツセツづ」ツ?、?
    return abs( dot(p-a,normal_vector) );
  }
   
  //テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ、テッツセツづッツスツクテッツセツづァツ板佚ッツスツ」テッツセツ?テッツスツァテッツセツεッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツ」テッツセツ?テッツスツ」テッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツァテッツセツづ」ツ?、テッツスツケpテッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツィテッツセツづッツスツソテッツセツづ・ツヲツ・テッツスツ」テッツセツ??テッツスツァテッツセツづ」ツ?、テッツスツケテッツセツεッツスツ」テッツセツづ」ツ?、テヲツエツ・テッツスツヲテッツセツづッツスツアテッツセツづ」ツ?・テッツスツ」テッツセツづ」ツ?、?テッツスツ」テッツセツづ」ツ?、?
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
   
  //Verify AOJ 0115
  //テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ」テッツセツ?テ・ツ渉、テッツスツ、テッツセツづッツスツコテッツセツづッツスツ、テッツセツεッツスツ・テッツセツづッツスツキテッツセツづッツスツョテッツセツεッツスツ」テッツセツ?テ・ツ?姪ッツスツ」テッツセツづ」ツ?、テ・ツ?敕ッツスツ」テッツセツ??
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
   
  //Verify AOJ 0115
  //テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツゥテッツセツづヲツ閉姪ッツスツ「テッツセツεッツスツ」テッツセツ?テッツスツィテッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ」テッツセツ?テッツスツョテッツセツεッツスツ、テッツセツづッツスツコテッツセツづッツスツ、テッツセツεッツスツァテッツセツづ」ツ?、テッツスツケテッツセツεッツスツ」テッツセツづ」ツ?、テヲツエツ・テッツスツヲテッツセツづッツスツアテッツセツづ」ツ?・テッツスツ」テッツセツづ」ツ?、?テッツスツ」テッツセツづ」ツ?、?
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
   
};
   
// Verify AOJ 1289
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}
  
// Verify AOJ 1289
double distanceSP(Segment3d seg,Point3d p){
  double res = dot(seg.p[1]-seg.p[0],p-seg.p[0]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[0] );
  res = dot(seg.p[0]-seg.p[1],p-seg.p[1]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[1] );
  return distanceLP(seg,p);
}
   
// Verify AOJ 1289
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
   
// Verify AOJ 1289
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}
  
//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
   
//Verify AOJ 2081 
//l1,l2テッツセツεッツスツ」テッツセツ?テ・ツ渉、テッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツィテッツセツづッツスツ。テッツセツづ・ツ渉、テッツスツ」テッツセツ?テッツスツェテッツセツεッツスツヲテッツセツづ・ツ債催」ツ?・テッツスツ」テッツセツ?テッツスツォテッツセツεッツスツ」テッツセツ?テッツスツッテッツセツεッツスツ、テッツセツづッツスツステッツセツづッツスツソテッツセツεッツスツァテッツセツづヲツ敖ソテッツスツィテッツセツεッツスツ」テッツセツ?テッツスツァテッツセツεッツスツ」テッツセツ?テ・ツつャテッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??テッツスツ」テッツセツ?テッツスツョテッツセツεッツスツ」テッツセツ?テッツスツァテッツセツεッツスツヲテッツセツづッツスツウテッツセツづッツスツィテッツセツεッツスツヲテッツセツ??
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // テッツセツεッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツィテッツセツづッツスツ。テッツセツづ・ツ渉、テッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ・テッツセツ?テッツスツエテッツセツεッツスツ・テッツセツづゥツ敖津ヲツ堋療ッツスツ」テッツセツ?テッツスツッテッツセツεッツスツ、テッツセツづッツスツステッツセツづッツスツソテッツセツεッツスツァテッツセツづヲツ敖ソテッツスツィテッツセツεッツスツ、テッツセツづッツスツクテッツセツづ・ツつャテッツスツ・テッツセツづヲツクツ嘉ッツスツッ
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
   
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
   
  //テッツセツεッツスツ」テッツセツ?テヲツ閉陛ッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツ」テッツセツ?テヲツ閉陛ッツスツ」テッツセツづ」ツ?、テッツシツュ1,l2テッツセツεッツスツ」テッツセツ?テ・ツ渉、テッツスツァテッツセツづ・ツエツ「テッツスツエテッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ」テッツセツ?テ、ツスツ堙ッツスツ」テッツセツづ」ツ?、テ篠オテッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      テッツセツεッツスツ」テッツセツ?テァツヲツソテッツスツ」テッツセツ?テッツスツョテッツセツεッツスツ・テッツセツ?テッツスツエテッツセツεッツスツ・テッツセツづゥツ敖津ヲツ堋療ッツスツ」テッツセツ?テッツスツッテッツセツεッツスツヲテッツセツづッツスツウテッツセツづッツスツィテッツセツεッツスツヲテッツセツ??
      テッツセツεッツスツ」テッツセツ?テヲツ閉陛ッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツ」テッツセツ?テヲツ閉陛ッツスツ」テッツセツづ」ツ?、テ」ツ?・テッツスツ、テッツセツづッツスツクテッツセツづ・ツ?イテッツスツ」テッツセツ?テヲツ堋療ッツスツ」テッツセツづ」ツ?、テ・ツ伉嘉ッツスツ」テッツセツづ」ツ?、テ・ツ渉、テッツスツ」テッツセツ?テヲツキツ古ッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ」テッツセツ?テ・ツ渉、テッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ・テッツセツづヲツ個?テッツスツ」テッツセツ?テッツスツォテッツセツεッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ?テッツスツ」テッツセツεッツスツ」テッツセツ?テッツスツヲテッツセツεッツスツ」テッツセツ??テッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??テッツスツ」テッツセツ?テッツスツョテッツセツεッツスツ」テッツセツ?テッツスツァテッツセツεッツスツ」テッツセツ??テッツスツ、テッツセツづッツスツコテッツセツづッツスツ、テッツセツεッツスツ・テッツセツづッツスツキテッツセツづッツスツョテッツセツεッツスツ」テッツセツ?テ・ツ?姪ッツスツ」テッツセツづ」ツ?、テ・ツ?敕ッツスツ」テッツセツ?テ・ツ?敕ッツスツ」テッツセツ?テッツスツゥテッツセツεッツスツ」テッツセツ??テッツスツ」テッツセツ?テ・ツ?敕ッツスツ」テッツセツ?テッツスツッテッツセツεッツスツ・テッツセツづヲツ個嘉ッツスツ、テッツセツεッツスツ・テッツセツづッツスツョテッツセツづ・ツ?凖ッツスツ」テッツセツ?テッツスツァテッツセツεッツスツ」テッツセツ?テ・ツつャテッツスツ」テッツセツ?テッツスツェテッツセツεッツスツ」テッツセツ??
    */
    return false;
  }
   
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
   
  if( equals(tmp,0.0) ) return 0; // テッツセツεッツスツァテッツセツづ・ツエツ「テッツスツエテッツセツεッツスツァテッツセツづッツスツキテッツセツづ・ツ?凖ッツスツ」テッツセツ?テ・ツ渉、テッツスツ・テッツセツづッツスツケテッツセツづッツスツウテッツセツεッツスツィテッツセツづッツスツ。テッツセツ?
   
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}
  
bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}
  
  
int N;
Segment3d ururu_beam;
Point3d Circle[MAX];
double R[MAX];
  
inline void Input3d(Point3d &p){ cin >> p.x >> p.y >> p.z; }
  
inline void compute(){
  int skip = -1;
  bool update = true;
  while(update){
    update = false;
    Point3d tmp_p0,tmp_p1;
    int tmp_skip = -1;
    double tmp_dist = IINF;
    Vector3d vect = ( ururu_beam.p[1] - ururu_beam.p[0] ) / abs( ururu_beam.p[1] - ururu_beam.p[0] );
    Vector3d rvect = ( ururu_beam.p[0] - ururu_beam.p[1] ) / abs( ururu_beam.p[0] - ururu_beam.p[1] );
    ururu_beam.p[1] = ururu_beam.p[0] + vect * 500;
    rep(i,N){
      if( i == skip ) continue;
  
      double dist = distanceSP(ururu_beam,Circle[i]);
      if( !equals(dist,R[i]) && dist > R[i] ) continue;
  
      Point3d on_seg = project(ururu_beam,Circle[i]);
  
      dist = sqrt(pow(R[i],2.0)-norm(on_seg-Circle[i]));
  
      Point3d cp = on_seg + rvect * dist;
      Line3d line = Line3d(Circle[i],cp);
  
      dist = abs(ururu_beam.p[0]-cp);
      if( tmp_dist > dist ){
        tmp_p0 = cp, tmp_p1 = reflect(line,ururu_beam.p[0]);
        tmp_dist = dist;
        tmp_skip = i;
      }
      update = true;
    }
    if( update ){
      ururu_beam = Segment3d(tmp_p0,tmp_p1);
      skip = tmp_skip;
    }
  }
  printf("%.4f %.4f %.4f\n",ururu_beam.p[0].x,ururu_beam.p[0].y,ururu_beam.p[0].z);
}
  
int main(){
  while( cin >> N, N ){
    ururu_beam.p[0] = Point3d(0,0,0);
    Input3d(ururu_beam.p[1]);
    rep(i,N){
      Input3d(Circle[i]);
      cin >> R[i];
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1260
final_rank: 6

code_snippet: #include<bits/stdc++.h>
  
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define MAX 110
  
using namespace std;
  
//テ、ツスツ愿ヲツ按静、ツクツュ Verifyテ」ツ?療」ツ?淌」ツつづ」ツ?ョテ」ツ?ォテ」ツ?ッVerifyテ」ツ?ィテヲツ崢クテ」ツ??」ツ?ヲテ」ツ?づ」ツつ?
  
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
  
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
  
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
  
  bool operator < (const Point3d& p)const{
    return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:z<p.z);
  }
  
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
  
};
  
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
  bool operator == (const Segment3d& seg)const{
    return p[0] == seg.p[0] && p[1] == seg.p[1];
  }
};
  
typedef Point3d Vector3d;
typedef Segment3d Line3d;
  
  
  
  
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
  
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
  
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
  
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
  
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
  
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
  
  
  
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
  
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
  
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
  
  //テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青暗」ツ??、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ソテ」ツ?ェテ」ツ??
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;
  
  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
  
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
  
  // テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青?テ、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ッテ」ツ?ソテ」ツ?ェテ」ツ?陛」ツ?ェテ」ツ??
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
  
  // テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青?テ、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ソテ」ツ?ェテ」ツ??
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
  
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
  
inline Point3d rorateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
  
inline Point3d rorateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
  
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
          (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
          (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
  
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
          ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
          -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
  
  
class Plane3d{
public:
  Point3d normal_vector; //テヲツウツ陛ァツキツ堙」ツδ凖」ツつッテ」ツδ暗」ツδォ
  double d; // テ・ツケツウテゥツ敖「テヲツ鳴ケテァツィツ凝・ツシツ?normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
  
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
  
  //Verify AOJ 0115
  //テヲツウツ陛ァツキツ堙」ツδ凖」ツつッテ」ツδ暗」ツδォnormal_vectorテ」ツ?ィテ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ョテッツシツ妥ァツつケテ」ツ?凝」ツつ嬰テ」ツつ津ィツィツ暗ァツョツ療」ツ?凖」ツつ?
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
  
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツつケpテ」ツ?ョティツキツ敕ゥツ崢「テ」ツつ津ヲツアツづ」ツつ?」ツつ?
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//テ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ョテゥツ?ゥテ・ツスツ禿」ツ?ェテァツつケテ」ツつ津」ツ?、テ」ツ?湘」ツつ?
    return abs( dot(p-a,normal_vector) );
  }
  
  //テ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ァテ」ツつづ」ツ?」テ」ツ?ィテ」ツつづァツつケpテ」ツ?ィティツソツ妥」ツ??ァツつケテ」ツつ津ヲツアツづ」ツつ?」ツつ?
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
  
  //Verify AOJ 0115
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツキツ堙・ツ按?」ツ?古、ツコツ、テ・ツキツョテ」ツ?凖」ツつ凝」ツ??
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
  
  //Verify AOJ 0115
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツキツ堙・ツ按?」ツ?ョテ、ツコツ、テァツつケテ」ツつ津ヲツアツづ」ツつ?」ツつ?
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
  
};
  
// Verify AOJ 1289
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}
 
// Verify AOJ 1289
double distanceSP(Segment3d seg,Point3d p){
  double res = dot(seg.p[1]-seg.p[0],p-seg.p[0]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[0] );
  res = dot(seg.p[0]-seg.p[1],p-seg.p[1]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[1] );
  return distanceLP(seg,p);
}
  
// Verify AOJ 1289
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
  
// Verify AOJ 1289
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}
 
//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
  
//Verify AOJ 2081 
//l1,l2テ」ツ?古・ツケツウティツ。ツ古」ツ?ェテヲツ卍づ」ツ?ォテ」ツ?ッテ、ツスツソテァツ板ィテ」ツ?ァテ」ツ?催」ツ?ェテ」ツ??」ツ?ョテ」ツ?ァテヲツウツィテヲツ??
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // テ・ツケツウティツ。ツ古」ツ?ェテ・ツ?エテ・ツ青暗」ツ?ッテ、ツスツソテァツ板ィテ、ツクツ催・ツ渉ッ
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
  
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  
  //テ」ツ?敕」ツつづ」ツ?敕」ツつＭ1,l2テ」ツ?古ァツ崢エテァツキツ堙」ツ?佚」ツつε」ツ?ェテ」ツ??
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      テ」ツ?禿」ツ?ョテ・ツ?エテ・ツ青暗」ツ?ッテヲツウツィテヲツ??
      テ」ツ?敕」ツつづ」ツ?敕」ツつづ、ツクツ偲」ツ?暗」ツつ嘉」ツつ古」ツ?淌ァツキツ堙・ツ按?」ツ?古ァツキツ堙・ツ按?」ツ?ォテ」ツ?ェテ」ツ?」テ」ツ?ヲテ」ツ??」ツ?ェテ」ツ??」ツ?ョテ」ツ?ァテ」ツ??、ツコツ、テ・ツキツョテ」ツ?凖」ツつ凝」ツ?凝」ツ?ゥテ」ツ??」ツ?凝」ツ?ッテ・ツ按、テ・ツョツ堙」ツ?ァテ」ツ?催」ツ?ェテ」ツ??
    */
    return false;
  }
  
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  
  if( equals(tmp,0.0) ) return 0; // テァツ崢エテァツキツ堙」ツ?古・ツケツウティツ。ツ?
  
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}
 
bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}
 
 
int N;
Segment3d ururu_beam;
Point3d Circle[MAX];
double R[MAX];
 
inline void Input3d(Point3d &p){ cin >> p.x >> p.y >> p.z; }
 
inline void compute(){
  int skip = -1;
  bool update = true;
  while(update){
    update = false;
    Point3d tmp_p0,tmp_p1;
    int tmp_skip = -1;
    double tmp_dist = IINF;
    Vector3d vect = ( ururu_beam.p[1] - ururu_beam.p[0] ) / abs( ururu_beam.p[1] - ururu_beam.p[0] );
    Vector3d rvect = ( ururu_beam.p[0] - ururu_beam.p[1] ) / abs( ururu_beam.p[0] - ururu_beam.p[1] );
    ururu_beam.p[1] = ururu_beam.p[0] + vect * 500;
    rep(i,N){
      if( i == skip ) continue;
 
      double dist = distanceSP(ururu_beam,Circle[i]);
      if( !equals(dist,R[i]) && dist > R[i] ) continue;
 
      Point3d on_seg = project(ururu_beam,Circle[i]);
 
      dist = sqrt(pow(R[i],2.0)-norm(on_seg-Circle[i]));
 
      Point3d cp = on_seg + rvect * dist;
      Line3d line = Line3d(Circle[i],cp);
 
      dist = abs(ururu_beam.p[0]-cp);
      if( tmp_dist > dist ){
        tmp_p0 = cp, tmp_p1 = reflect(line,ururu_beam.p[0]);
        tmp_dist = dist;
        tmp_skip = i;
      }
      update = true;
    }
    if( update ){
      ururu_beam = Segment3d(tmp_p0,tmp_p1);
      skip = tmp_skip;
    }
  }
  printf("%.4f %.4f %.4f\n",ururu_beam.p[0].x,ururu_beam.p[0].y,ururu_beam.p[0].z);
}
 
int main(){
  while( cin >> N, N ){
    ururu_beam.p[0] = Point3d(0,0,0);
    Input3d(ururu_beam.p[1]);
    rep(i,N){
      Input3d(Circle[i]);
      cin >> R[i];
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1260
final_rank: 6

code_snippet: #include<bits/stdc++.h>
 
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define MAX 110
 
using namespace std;
 
//テ、ツスツ愿ヲツ按静、ツクツュ Verifyテ」ツ?療」ツ?淌」ツつづ」ツ?ョテ」ツ?ォテ」ツ?ッVerifyテ」ツ?ィテヲツ崢クテ」ツ??」ツ?ヲテ」ツ?づ」ツつ?
 
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
 
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
 
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
 
  bool operator < (const Point3d& p)const{
    return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:z<p.z);
  }
 
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
 
};
 
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
  bool operator == (const Segment3d& seg)const{
    return p[0] == seg.p[0] && p[1] == seg.p[1];
  }
};
 
typedef Point3d Vector3d;
typedef Segment3d Line3d;
 
 
 
 
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
 
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
 
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
 
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
 
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
 
 
 
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
 
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
 
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
 
  //テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青暗」ツ??、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ソテ」ツ?ェテ」ツ??
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;
 
  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
 
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
 
  // テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青?テ、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ッテ」ツ?ソテ」ツ?ェテ」ツ?陛」ツ?ェテ」ツ??
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
 
  // テァツキツ堙・ツ按?、ツクツ甘」ツ?ォpテ」ツ?古」ツ?づ」ツ?」テ」ツ?淌・ツ?エテ・ツ青?テ、ツクツ嘉ィツァツ津・ツスツ「テ・ツ??」ツ?ィテ」ツ?ソテ」ツ?ェテ」ツ??
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
 
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rorateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rorateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
 
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
		  (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
		  (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
 
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
		  ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
		  -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
 
 
class Plane3d{
public:
  Point3d normal_vector; //テヲツウツ陛ァツキツ堙」ツδ凖」ツつッテ」ツδ暗」ツδォ
  double d; // テ・ツケツウテゥツ敖「テヲツ鳴ケテァツィツ凝・ツシツ?normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
 
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
 
  //Verify AOJ 0115
  //テヲツウツ陛ァツキツ堙」ツδ凖」ツつッテ」ツδ暗」ツδォnormal_vectorテ」ツ?ィテ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ョテッツシツ妥ァツつケテ」ツ?凝」ツつ嬰テ」ツつ津ィツィツ暗ァツョツ療」ツ?凖」ツつ?
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
 
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツつケpテ」ツ?ョティツキツ敕ゥツ崢「テ」ツつ津ヲツアツづ」ツつ?」ツつ?
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//テ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ョテゥツ?ゥテ・ツスツ禿」ツ?ェテァツつケテ」ツつ津」ツ?、テ」ツ?湘」ツつ?
    return abs( dot(p-a,normal_vector) );
  }
 
  //テ・ツケツウテゥツ敖「テ、ツクツ甘」ツ?ァテ」ツつづ」ツ?」テ」ツ?ィテ」ツつづァツつケpテ」ツ?ィティツソツ妥」ツ??ァツつケテ」ツつ津ヲツアツづ」ツつ?」ツつ?
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
 
  //Verify AOJ 0115
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツキツ堙・ツ按?」ツ?古、ツコツ、テ・ツキツョテ」ツ?凖」ツつ凝」ツ??
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
 
  //Verify AOJ 0115
  //テ・ツケツウテゥツ敖「テ」ツ?ィテァツキツ堙・ツ按?」ツ?ョテ、ツコツ、テァツつケテ」ツつ津ヲツアツづ」ツつ?」ツつ?
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
 
};
 
// Verify AOJ 1289
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}

// Verify AOJ 1289
double distanceSP(Segment3d seg,Point3d p){
  double res = dot(seg.p[1]-seg.p[0],p-seg.p[0]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[0] );
  res = dot(seg.p[0]-seg.p[1],p-seg.p[1]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[1] );
  return distanceLP(seg,p);
}
 
// Verify AOJ 1289
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
 
// Verify AOJ 1289
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}

//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
 
//Verify AOJ 2081 
//l1,l2テ」ツ?古・ツケツウティツ。ツ古」ツ?ェテヲツ卍づ」ツ?ォテ」ツ?ッテ、ツスツソテァツ板ィテ」ツ?ァテ」ツ?催」ツ?ェテ」ツ??」ツ?ョテ」ツ?ァテヲツウツィテヲツ??
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // テ・ツケツウティツ。ツ古」ツ?ェテ・ツ?エテ・ツ青暗」ツ?ッテ、ツスツソテァツ板ィテ、ツクツ催・ツ渉ッ
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
 
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
 
  //テ」ツ?敕」ツつづ」ツ?敕」ツつＭ1,l2テ」ツ?古ァツ崢エテァツキツ堙」ツ?佚」ツつε」ツ?ェテ」ツ??
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      テ」ツ?禿」ツ?ョテ・ツ?エテ・ツ青暗」ツ?ッテヲツウツィテヲツ??
      テ」ツ?敕」ツつづ」ツ?敕」ツつづ、ツクツ偲」ツ?暗」ツつ嘉」ツつ古」ツ?淌ァツキツ堙・ツ按?」ツ?古ァツキツ堙・ツ按?」ツ?ォテ」ツ?ェテ」ツ?」テ」ツ?ヲテ」ツ??」ツ?ェテ」ツ??」ツ?ョテ」ツ?ァテ」ツ??、ツコツ、テ・ツキツョテ」ツ?凖」ツつ凝」ツ?凝」ツ?ゥテ」ツ??」ツ?凝」ツ?ッテ・ツ按、テ・ツョツ堙」ツ?ァテ」ツ?催」ツ?ェテ」ツ??
    */
    return false;
  }
 
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
 
  if( equals(tmp,0.0) ) return 0; // テァツ崢エテァツキツ堙」ツ?古・ツケツウティツ。ツ?
 
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}

bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}


int N;
Segment3d ururu_beam;
Point3d Circle[MAX];
double R[MAX];

inline void Input3d(Point3d &p){ cin >> p.x >> p.y >> p.z; }

inline void compute(){
  int skip = -1;
  bool update = true;
  while(update){
    update = false;
    Point3d tmp_p0,tmp_p1;
    int tmp_skip = -1;
    double tmp_dist = IINF;
    Vector3d vect = ( ururu_beam.p[1] - ururu_beam.p[0] ) / abs( ururu_beam.p[1] - ururu_beam.p[0] );
    Vector3d rvect = ( ururu_beam.p[0] - ururu_beam.p[1] ) / abs( ururu_beam.p[0] - ururu_beam.p[1] );
    ururu_beam.p[1] = ururu_beam.p[0] + vect * 500;
    rep(i,N){
      if( i == skip ) continue;

      double dist = distanceSP(ururu_beam,Circle[i]);
      if( !equals(dist,R[i]) && dist > R[i] ) continue;

      Point3d on_seg = project(ururu_beam,Circle[i]);

      dist = sqrt(pow(R[i],2.0)-norm(on_seg-Circle[i]));
      double x = R[i] * R[i] - norm(on_seg-Circle[i]);
      if( x == 0 ) dist = 0;
      else if( x < 0 ) continue;

      Point3d cp = on_seg + rvect * dist;
      Line3d line = Line3d(Circle[i],cp);

      dist = abs(ururu_beam.p[0]-cp);
      if( tmp_dist > dist ){
        tmp_p0 = cp, tmp_p1 = reflect(line,ururu_beam.p[0]);
        tmp_dist = dist;
        tmp_skip = i;
      }
      update = true;
    }
    if( update ){
      ururu_beam = Segment3d(tmp_p0,tmp_p1);
      skip = tmp_skip;
    }
  }
  printf("%.4f %.4f %.4f\n",ururu_beam.p[0].x,ururu_beam.p[0].y,ururu_beam.p[0].z);
}

int main(){
  while( cin >> N, N ){
    ururu_beam.p[0] = Point3d(0,0,0);
    Input3d(ururu_beam.p[1]);
    rep(i,N){
      Input3d(Circle[i]);
      cin >> R[i];
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1260
final_rank: 6

code_snippet: #include<bits/stdc++.h>
 
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)
#define EPS (1e-7)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define MAX 110
 
using namespace std;
 
//作成中 VerifyしたものにはVerifyと書いてある
 
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
 
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
 
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
 
  bool operator < (const Point3d& p)const{
    return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:z<p.z);
  }
 
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
 
};
 
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
  bool operator == (const Segment3d& seg)const{
    return p[0] == seg.p[0] && p[1] == seg.p[1];
  }
};
 
typedef Point3d Vector3d;
typedef Segment3d Line3d;
 
 
 
 
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
 
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
 
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
 
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
 
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
 
 
 
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
 
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
 
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
 
  //線分上にpがあった場合、三角形内とみなす
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;
 
  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
 
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
 
  // 線分上にpがあった場合,三角形内とはみなさない
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
 
  // 線分上にpがあった場合,三角形内とみなす
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
 
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rorateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rorateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
 
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
		  (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
		  (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
 
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
		  ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
		  -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
 
 
class Plane3d{
public:
  Point3d normal_vector; //法線ベクトル
  double d; // 平面方程式 normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
 
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
 
  //Verify AOJ 0115
  //法線ベクトルnormal_vectorと平面上の１点からdを計算する
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
 
  //平面と点pの距離を求める
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//平面上の適当な点をつくる
    return abs( dot(p-a,normal_vector) );
  }
 
  //平面上でもっとも点pと近い点を求める
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
 
  //Verify AOJ 0115
  //平面と線分が交差するか
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
 
  //Verify AOJ 0115
  //平面と線分の交点を求める
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
 
};
 
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}

double distanceSP(Segment3d seg,Point3d p){
  double res = dot(seg.p[1]-seg.p[0],p-seg.p[0]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[0] );
  res = dot(seg.p[0]-seg.p[1],p-seg.p[1]);
  if( !equals(res,0.0) && res < 0.0 ) return abs( p - seg.p[1] );
  return distanceLP(seg,p);
}
 
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
 
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}

//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
 
//Verify AOJ 2081 
//l1,l2が平行な時には使用できないので注意
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // 平行な場合は使用不可
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
 
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
 
  //そもそもl1,l2が直線じゃない
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      この場合は注意
      そもそも与えられた線分が線分になっていないので、交差するかどうかは判定できない
    */
    return false;
  }
 
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
 
  if( equals(tmp,0.0) ) return 0; // 直線が平行
 
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}

bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}


int N;
Segment3d ururu_beam;
Point3d Circle[MAX];
double R[MAX];

inline void Input3d(Point3d &p){ cin >> p.x >> p.y >> p.z; }

inline void compute(){
  int skip = -1;
  bool update = true;
  while(update){
    update = false;
    Point3d tmp_p0,tmp_p1;
    int tmp_skip = -1;
    double tmp_dist = IINF;
    Vector3d vect = ( ururu_beam.p[1] - ururu_beam.p[0] ) / abs( ururu_beam.p[1] - ururu_beam.p[0] );
    Vector3d rvect = ( ururu_beam.p[0] - ururu_beam.p[1] ) / abs( ururu_beam.p[0] - ururu_beam.p[1] );
    ururu_beam.p[1] = ururu_beam.p[0] + vect * 500;
    rep(i,N){
      if( i == skip ) continue;

      double dist = distanceSP(ururu_beam,Circle[i]);
      if( !equals(dist,R[i]) && dist > R[i] ) continue;

      Point3d on_seg = project(ururu_beam,Circle[i]);

      dist = sqrt(pow(R[i],2.0)-norm(on_seg-Circle[i]));
      double x = R[i] * R[i] - norm(on_seg-Circle[i]);
      if( x == 0 ) dist = 0;
      else if( x < 0 ) continue;

      Point3d cp = on_seg + rvect * dist;
      Line3d line = Line3d(Circle[i],cp);

      dist = abs(ururu_beam.p[0]-cp);
      if( tmp_dist > dist ){
        tmp_p0 = cp, tmp_p1 = reflect(line,ururu_beam.p[0]);
        tmp_dist = dist;
        tmp_skip = i;
      }
      update = true;
    }
    if( update ){
      ururu_beam = Segment3d(tmp_p0,tmp_p1);
      skip = tmp_skip;
    }
  }
  printf("%.4f %.4f %.4f\n",ururu_beam.p[0].x,ururu_beam.p[0].y,ururu_beam.p[0].z);
}

int main(){
  while( cin >> N, N ){
    ururu_beam.p[0] = Point3d(0,0,0);
    Input3d(ururu_beam.p[1]);
    rep(i,N){
      Input3d(Circle[i]);
      cin >> R[i];
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1260
final_rank: 6