#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <tuple>
#include <cmath>

using namespace std;
const double EPS = 1e-8;
const double INF = 1e10;

struct Point {
	double x, y;
	Point() : x(0), y(0) { }
	Point(double x, double y) : x(x), y(y) { }
	Point operator+(const Point &p) const { return Point(x + p.x, y + p.y); }
	Point operator-(const Point &p) const { return Point(x - p.x, y - p.y); }
	Point operator*(double s) const { return Point(x * s, y * s); }
	Point operator/(double s) const { return Point(x / s, y / s); }
	Point &operator+=(const Point &p){ x += p.x; y += p.y; return *this; }
	Point &operator-=(const Point &p){ x -= p.x; y -= p.y; return *this; }
	Point &operator*=(double s){ x *= s; y *= s; return *this; }
	Point &operator/=(double s){ x /= s; y /= s; return *this; }
	bool operator==(const Point &p) const { return x == p.x && y == p.y; }
	bool operator!=(const Point &p) const { return x != p.x || y != p.y; }
	bool operator<(const Point &p) const {
		return (x == p.x) ? (y < p.y) : (x < p.x);
	}
};
inline Point operator*(double s, const Point &p){ return p * s; }

inline double norm(const Point &p){ return p.x * p.x + p.y * p.y; }
inline double abs(const Point &p){ return sqrt(norm(p)); }
inline double arg(const Point &p){ return atan2(p.y, p.x); }
inline Point unit(const Point &p){ return p / abs(p); }
inline Point ortho(const Point &p){ return Point(-p.y, p.x); }
inline double cross(const Point &a, const Point &b){
	return a.x * b.y - a.y * b.x;
}
inline double dot(const Point &a, const Point &b){
	return a.x * b.x + a.y * b.y;
}
inline int ccw(const Point &a, const Point &b, const Point &c){
	const Point d = b - a, e = c - a;
	if(cross(d, e) > 0.0){ return 1; }
	if(cross(d, e) < 0.0){ return -1; }
	if(dot(d, e) < 0.0){ return 2; }
	if(abs(d) < abs(e)){ return -2; }
	return 0;
}

struct Line {
	Point a, b;
	Line() : a(), b() { }
	Line(const Point &a, const Point &b) : a(a), b(b) { }
	bool operator==(const Line &l) const { return a == l.a && b == l.b; }
	bool operator!=(const Line &l) const { return a != l.a || b != l.b; }
	bool operator<(const Line &l) const {
		return (a == l.a) ? (b < l.b) : (a < l.a);
	}
};

inline Point direction(const Line &l){ return unit(l.b - l.a); }
inline int is_parallel(const Line &a, const Line &b){
	// 0: not parallel, 1: parallel, -1: same line
	const double s = cross(direction(a), direction(b));
	if(s >= EPS){ return 0; }
	const double t = cross(direction(b), a.b - b.a);
	return (t >= EPS) ? 1 : -1;
}
inline Line bisect(const Point &a, const Point &b){
	const Point &p = (a + b) * 0.5;
	return Line(p, unit(ortho(b - a)));
}
inline Point projection(const Line &l, const Point &p){
	double t = dot(p - l.a, l.b - l.a) / norm(l.b - l.a);
	return l.a + t * (l.b - l.a);
}
inline Point reflection(const Line &l, const Point &p){
	return p + 2.0 * (projection(l, p) - p);
}
inline Point crossing_point(const Line &a, const Line &b){
	const double x = cross(a.b - a.a, b.b - b.a);
	const double y = cross(a.b - a.a, a.b - b.a);
	return Point(b.a + (y / x) * (b.b - b.a));
}

struct Segment : public Line {
	Segment() : Line() { }
	Segment(const Point &a, const Point &b) : Line(a, b) { }
};

inline bool intersect(const Segment &a, const Segment &b){
	if(ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) > 0){ return false; }
	if(ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) > 0){ return false; }
	return true;
}

typedef tuple<double, int> tdi;
typedef tuple<Segment, int, int> tsii;

double solve(
	int depth, int prev, const Point &s, const Point &t,
	const vector<Segment> &mirrors,
	vector<tsii> &imag_mirrors, vector<int> &history)
{
	const int n = mirrors.size(), m = imag_mirrors.size();
	const Segment st(s, t);
	for(int i = 0; i < n; ++i){
		if(i != prev){ imag_mirrors.push_back(tsii(mirrors[i], i, depth)); }
	}
	vector<tdi> crossing_order;
	for(int i = 0; i < imag_mirrors.size(); ++i){
		if(intersect(st, get<0>(imag_mirrors[i]))){
			const Point p = crossing_point(st, get<0>(imag_mirrors[i]));
			crossing_order.push_back(tdi(norm(p - s), i));
		}
	}
	sort(crossing_order.begin(), crossing_order.end());
	int reflected = 0;
	bool accept = true;
	for(int i = 0; i < crossing_order.size(); ++i){
		const tsii &mirror = imag_mirrors[get<1>(crossing_order[i])];
		const int level = get<2>(mirror);
		const int mask = (1 << level) - 1;
		if((reflected & mask) != mask){ continue; }
		if(reflected & (1 << level)){ continue; }
		if(level >= depth || history[level] != get<1>(mirror)){
			accept = false;
			break;
		}
		reflected |= (1 << level);
	}
	if(reflected != ((1 << depth) - 1)){ accept = false; }
	double answer = INF;
	if(accept){ answer = abs(t - s); }
	if(depth >= 5){
		imag_mirrors.resize(m);
		return answer;
	}
	for(int i = 0; i < n; ++i){
		if(i == prev){ continue; }
		vector<Segment> next_mirrors(n);
		for(int j = 0; j < n; ++j){
			next_mirrors[j] = Segment(
				reflection(mirrors[i], mirrors[j].a),
				reflection(mirrors[i], mirrors[j].b));
		}
		history.push_back(i);
		const Point next_t = reflection(mirrors[i], t);
		answer = min(answer, solve(
			depth + 1, i, s, next_t, next_mirrors, imag_mirrors, history));
		history.pop_back();
	}
	imag_mirrors.resize(m);
	return answer;
}

int main(){
	ios_base::sync_with_stdio(false);
	cout << setiosflags(ios::fixed) << setprecision(10);
	while(true){
		int n;
		cin >> n;
		if(n == 0){ break; }
		vector<Segment> mirrors(n);
		for(int i = 0; i < n; ++i){
			Segment &s = mirrors[i];
			cin >> s.a.x >> s.a.y >> s.b.x >> s.b.y;
		}
		Point s, t;
		cin >> s.x >> s.y >> t.x >> t.y;
		vector<tsii> imag_mirrors;
		vector<int> history;
		cout << solve(0, -1, s, t, mirrors, imag_mirrors, history) << endl;
	}
	return 0;
}

Measured memory_bytes: 1324