Problem:
Problem G:
Laser Beam Reflections
A laser beam generator, a target object and some mirrors are 
placed on a plane.
The mirrors stand upright on the plane,
and both sides of the mirrors are flat and can reflect beams.
To point the beam at the target,
you may set the beam to several directions because of different reflections.
Your job is to find the shortest beam path
from the generator to the target and answer the length of the path.
Figure G-1 shows examples of possible beam paths,
where the bold line represents the shortest one.
Figure G-1: Examples of possible paths
Input
The input consists of a number of datasets. The end of the input is indicated by a line containing a zero.
Each dataset is formatted as follows. 
Each value in the dataset except
n
is an integer no less than 0 and no more than 100.
n
PX
1
PY
1
QX
1
QY
1
...
PX
n
PY
n
QX
n
QY
n
TX
TY
LX
LY
The first line of a dataset contains an integer
n
(1 ≤
n
≤ 5),
representing the number of mirrors.
The following
n
lines list the arrangement of mirrors on the plane.
The coordinates
(
PX
i
,
PY
i
) and 
(
QX
i
,
QY
i
) represent
the positions of both ends of the mirror.
Mirrors are apart from each other.
The last two lines represent the target position (
TX
,
TY
)
and the position of the beam generator (
LX
,
LY
).
The positions of the target and the generator are apart from each other,
and these positions are also apart from mirrors.
The sizes of the target object and the beam generator are small enough to be ignored.
You can also ignore the thicknesses of mirrors.
In addition, you can assume the following conditions on the given datasets.
There is at least one possible path from the beam generator to the target.
The number of reflections along the shortest path is less than 6.
The shortest path does not cross or touch a plane containing a mirror
surface at any points within 0.001 unit distance from either end of the mirror.
Even if the beam could arbitrarily select reflection or passage 
when it reaches each plane containing a mirror surface
at a point within 0.001 unit distance from one of the mirror ends,
any paths from the generator to the target would not be 
shorter than the shortest path.
When the beam is shot from the generator in an arbitrary direction and 
it reflects on a mirror or passes the mirror within 0.001 unit distance from the mirror,
the angle
θ
formed by the beam and the mirror 
satisfies sin(
θ
) > 0.1, 
until the beam reaches the 6th reflection point (exclusive).
Figure G-1 corresponds to the first dataset of the Sample Input below.
Figure G-2 shows the shortest paths for the subsequent datasets of the Sample Input.
Figure G-2: Examples of the shortest paths
Output
For each dataset, output a single line containing the length of the shortest path from
the beam generator to the target.
The value should not have an error greater than 0.001.
No extra characters should appear in the output.
Sample Input
2
30 10 30 75
60 30 60 95
90 0
0 100
1
20 81 90 90
10 90
90 10
2
10 0
...(truncated)

Submitted solutions:

code_snippet: #include <iostream>
#include <algorithm>
#include <complex>
#include <vector>
#include <cmath>
#define sz(x) int((x).size())
#define mkp make_pair
#define frs first
#define scn second
#define phb push_back
#define ppb pop_back
using namespace std;

typedef complex< double > Point;
typedef complex< double > Vector;
typedef pair< Point, Point > Segment;
const double kInf = 1e10;
const double kEps = 1e-8;

int N;
Segment seg[5];
Point bg, ed;

double res;
vector< int > rfl;

void read();
void solve();

void dfs(int);
void find_path();

inline double cross(const Vector &u, const Vector &v) { return imag(conj(u) * v); }
inline double dot(const Vector &u, const Vector &v) { return real(conj(u) * v); }

inline bool flt(double x, double y) {
  return x + kEps < y;
}

inline bool fle(double x, double y) {
  return x < y + kEps;
}

inline bool feq(double x, double y) {
  return abs(x - y) < kEps;
}

int main() {
  cout.setf(ios::fixed), cout.precision(14);
  while (cin >> N, N)
    read(), solve();

  return 0;
}

void read() {
  int x1, y1, x2, y2;

  for (int i = 0; i < N; ++i) {
    cin >> x1 >> y1 >> x2 >> y2;
    seg[i] = mkp(Point(double(x1), double(y1)), Point(double(x2), double(y2)));
  }

  cin >> x1 >> y1 >> x2 >> y2;
  ed = Point(double(x1), double(y1));
  bg = Point(double(x2), double(y2));
}

void solve() {
  res = kInf;
  dfs(0);
  cout << res << "\n";
}

void dfs(int dpt) {
  if (dpt > 6)
    return;

  rfl.phb(-1);
  find_path();
  rfl.ppb();

  for (int i = 0; i < N; ++i) {
    if (!rfl.empty() && i == rfl.back())
      continue;

    rfl.phb(i);
    dfs(dpt + 1);
    rfl.ppb();
  }
}

void find_path() {
  Point vp = ed;

  for (int i = sz(rfl) - 2; i >= 0; --i) {
    double ra = arg((seg[rfl[i]].scn - seg[rfl[i]].frs) / (vp - seg[rfl[i]].frs));
    vp = seg[rfl[i]].frs + Vector(cos(2 * ra), sin(2 * ra)) * (vp - seg[rfl[i]].frs);
  }

  Point cp = bg, np;
  Vector lsr = vp - bg;
  double ln = 0.0;

//  for (int i = 0; i < sz(rfl); ++i)
//    cout << " " << rfl[i];
//  cout << "\n";
//  cout << " vp = " << vp << "\n";

  for (int i = 0; i < sz(rfl); ++i) {
    Vector v12, v34, v13, v31;
    double t, s, tt, ss;

    if (rfl[i] == -1) {
      if (!feq(cross(lsr, ed - cp), 0.0) || flt(dot(lsr, ed - cp), 0)) {
//        cout << "check gg:\n";
//        cout << "  cross(lsr, ed - cp) = " << cross(lsr, ed - cp) << "\n";
//        cout << "  dot(lsr, ed - cp) = " << dot(lsr, ed - cp) << "\n";
        return;
      }

      lsr = ed - cp, t = 1.0;
    }
    else {
      v12 = lsr, v34 = seg[rfl[i]].scn - seg[rfl[i]].frs;
      v13 = seg[rfl[i]].frs - cp, v31 = -v13;
      t = cross(v13, v34) / cross(v12, v34);
      s = cross(v31, v12) / cross(v34, v12);

      if (fle(t, 0.0) || fle(s, 0.0) || fle(1.0, s))
        return;
    }

//    cout << "  lsr = " << lsr << "\n";
//    cout << "  t = " << t << "\n";

    for (int j = 0; j < N; ++j)
      if (rfl[i] != j) {
        v12 = lsr, v34 = seg[j].scn - seg[j].frs;
        v13 = seg[j].frs - cp, v31 = -v13;
        tt = cross(v13, v34) / cross(v12, v34);
        ss = cross(v31, v12) / cross(v34, v12);

        if (!fle(tt, 0.0) && !fle(ss, 0.0) && !fle(1.0, ss)) {
          if (flt(tt, t))
            return;
        }
      }

//    cout << "  np = " << cp + t * v12 << "\n";

    np = cp + t * v12;
    ln += abs(np - cp);

    if (rfl[i] != -1) {
      double ra = arg((seg[rfl[i]].scn - np) / (cp - np));
      lsr *= Vector(cos(2 * ra), sin(2 * ra));
    }

    cp = np;
  }

  res = min(res, ln);
}
/*

5

72 77 7 10
45 99 77 77
4 81 10 54
17 96 12 73
52 57 56 70
41 93
74 21

0

243.1347

*/
accuracy: 1
time_ms: 50
memory_kb: 3944
final_rank: 19

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





namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa


namespace zawa {

namespace geometryR2 {

using Real = long double;

namespace internal {

Real EPS{1e-12};
constexpr i32 negative{-1};
constexpr i32 zero{};
constexpr i32 positive{1};

} // namespace internal

Real& Eps() {
    return internal::EPS;
}

i32 Sign(Real value) {
    if (value < -Eps()) return internal::negative;
    if (value > Eps()) return internal::positive;
    return internal::zero;
}

bool Zero(Real value) {
    return Sign(value) == internal::zero;
}

bool Positive(Real value) {
    return Sign(value) == internal::positive;
}

bool Negative(Real value) {
    return Sign(value) == internal::negative;
}

bool Equal(Real a, Real b) {
    return Zero(a - b);
}

bool Smaller(Real a, Real b) {
    return Negative(a - b);
}

bool Bigger(Real a, Real b) {
    return Positive(a - b);
}

Real Square(Real value) {
    return (Zero(value) ? value : value * value);
}

Real Sqrt(Real value) {
    assert(!Negative(value));
    return (Zero(value) ? value : sqrtl(value));
}

Real Abs(Real value) {
    return (Negative(value) ? -value : value);
}

} // namespace geometryR2
 
} // namespace zawa



namespace zawa {

namespace geometryR2 {

constexpr Real PI{acosl(-1)};
constexpr Real TAU{static_cast<Real>(2) * PI};

constexpr Real ArcToRadian(Real arc) {
    return (arc * PI) / static_cast<Real>(180);
}

constexpr Real RadianToArc(Real radian) {
    return (radian * static_cast<Real>(180)) / PI;
}

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

class Point {
private:
    Real x_{}, y_{};
public:
    /* constructor */
    Point() = default;
    Point(Real x, Real y) : x_{x}, y_{y} {}

    /* getter, setter */
    Real x() const {
        return x_;
    }
    Real& x() {
        return x_;
    }
    Real y() const {
        return y_;
    }
    Real& y() {
        return y_;
    }

    /* operator */
    Point& operator+=(const Point& rhs) {
        x_ += rhs.x();
        y_ += rhs.y();
        return *this;
    }
    friend Point operator+(const Point& lhs, const Point& rhs) {
        return Point{lhs} += rhs;
    }
    Point operator+() const {
        return *this;
    }
    Point& operator-=(const Point& rhs) {
        x_ -= rhs.x();
        y_ -= rhs.y();
        return *this;
    }
    friend Point operator-(const Point& lhs, const Point& rhs) {
        return Point{lhs} -= rhs;
    }
    Point operator-() const {
        return Point{} - *this;
    }
    Point& operator*=(Real k) {
        x_ *= k;
        y_ *= k;
        return *this;
    }
    friend Point operator*(Real k, const Point& p) {
        return Point{p} *= k;
    }
    friend Point operator*(const Point& p, Real k) {
        return Point{p} *= k;
    }
    Point& operator/=(Real k) {
        assert(!Zero(k));
        x_ /= k;
        y_ /= k;
        return *this;
    }
    friend Point operator/(Real k, const Point& p) {
        return Point{p} /= k;
    }
    friend Point operator/(const Point& p, Real k) {
        return Point{p} /= k;
    }
    friend bool operator==(const Point& lhs, const Point& rhs) {
        return Equal(lhs.x(), rhs.x()) and Equal(lhs.y(), rhs.y());
    }
    friend bool operator!=(const Point& lhs, const Point& rhs) {
        return !Equal(lhs.x(), rhs.x()) or !Equal(lhs.y(), rhs.y());
    }
    friend bool operator<(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and Smaller(lhs.y(), rhs.y()));
    }
    friend bool operator<=(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.x(), rhs.x()) or 
            (Equal(lhs.x(), rhs.x()) and (Smaller(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend bool operator>(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and Bigger(lhs.y(), rhs.y()));
    }
    friend bool operator>=(const Point& lhs, const Point& rhs) {
        return Bigger(lhs.x(), rhs.x()) or
            (Equal(lhs.x(), rhs.x()) and (Bigger(lhs.y(), rhs.y()) or Equal(lhs.y(), rhs.y())));
    }
    friend std::istream& operator>>(std::istream& is, Point& p) {
        is >> p.x_ >> p.y_;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << '(' << p.x_ << ',' << p.y_ << ')';
        return os;
    }
    
    /* member function */
    Real normSquare() const {
        return Square(x_) + Square(y_);
    }
    Real norm() const {
        return Sqrt(normSquare());
    }
    void normalize() {
        assert((*this) != Point{});
        (*this) /= norm(); 
    }
    Point normalized() const {
        Point res{*this};
        res.normalize();
        return res;
    }
    Point rotated(Real radian) const {
        return Point{
            x_ * cosl(radian) - y_ * sinl(radian),
            x_ * sinl(radian) + y_ * cosl(radian)
        };
    }
    void rotate(Real radian) {
        *this = rotated(radian); 
    }
    Point rotatedByArc(Real arc) const {
        return rotated(ArcToRadian(arc));
    }
    void rotateByArc(Real arc) {
        *this = rotatedByArc(arc);
    }
    Real argument() const {
        return (Negative(y_) ? TAU : static_cast<Real>(0)) + atan2l(y_, x_);
    }
    Real argumentByArc() const {
        return RadianToArc(argument());
    }

    /* friend function */
    friend Real Dot(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.x() + lhs.y() * rhs.y();
    }
    friend Real Cross(const Point& lhs, const Point& rhs) {
        return lhs.x() * rhs.y() - lhs.y() * rhs.x();
    }
    friend Real Argument(const Point& lhs, const Point& rhs) {
        return rhs.argument() - lhs.argument();
    }
    friend bool ArgComp(const Point& lhs, const Point& rhs) {
        return Smaller(lhs.argument(), rhs.argument());
    }
};

using Vector = Point;

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

enum RELATION {
    // p0 -> p1 -> p2の順で直線上に並んでいる
    ONLINE_FRONT = -2,
    // (p1 - p0) -> (p2 - p0)が時計回りになっている
    CLOCKWISE,
    // p0 -> p2 -> p1の順で直線上に並んでいる
    ON_SEGMENT,
    // (p1 - p0) -> (p2 - p0)が反時計回りになっている
    COUNTER_CLOCKWISE,
    // p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
    ONLINE_BACK
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
    if (Negative(Cross(a, b))) return CLOCKWISE;
    if (Negative(Dot(a, b))) return ONLINE_BACK;
    if (Smaller(a.normSquare(), b.normSquare())) return ONLINE_FRONT;
    return ON_SEGMENT;
};

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

Real Distance(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.norm();
}

Real DistanceSquare(const Point& p0, const Point& p1) {
    return Point{p1 - p0}.normSquare();
}

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

class Segment {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Segment() = default;
    Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
    Segment(Real x0, Real y0, Real x1, Real y1) : p0_{x0, y0}, p1_{x1, y1} {}

    /* getter setter */
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    bool straddle(const Segment& s) const {
        return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
    }
    Real length() const {
        assert(valid());
        return Distance(p0_, p1_);
    }
    Point midpoint() const {
        assert(valid());
        return p0_ + Vector{p1_ - p0_} / static_cast<Real>(2);
    }
};

} // namespace geometryR2

} // namespace zawa



namespace zawa {

namespace geometryR2 {

class Line {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Line() = default;
    Line(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}
    // y = ax + b 
    Line(Real a, Real b) : p0_{static_cast<Real>(0), b}, p1_{static_cast<Real>(1), a + b} {}

    /* getter, setter */
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* operator */
    friend bool operator==(const Line& l0, const Line& l1) {
        return Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l1.p0())) and Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l0.p0()));
    }
    friend bool operator!=(const Line& l0, const Line& l1) {
        return !Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l1.p0())) or !Zero(Cross(l0.p1() - l0.p0(), l1.p1() - l0.p0()));
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    Vector slope() const {
        assert(valid());
        return Vector{p1() - p0()}.normalized();
    }
};

} // namespace geometryR2

} // namespace zawa




namespace zawa {

namespace geometryR2 {

Point Projection(const Point& point, const Line& line) {
    assert(line.valid());
    Real coeff{Dot(line.p1() - line.p0(), point - line.p0()) / DistanceSquare(line.p0(), line.p1())};
    return coeff * line.p1() + (static_cast<Real>(1) - coeff) * line.p0();
}

} // namespace geometryR2

} // namespace zawa

namespace zawa {

namespace geometryR2 {

Point Reflection(const Point& point, const Line& line) {
    assert(line.valid());
    return -point + static_cast<Real>(2) * Projection(point, line);
}

} // namespace geometryR2

} // namespace zawa



namespace zawa {

namespace geometryR2 {

bool Intersect(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return s0.straddle(s1) and s1.straddle(s0);
}

} // namespace geometryR2

} // namespace zawa




namespace zawa {

namespace geometryR2 {

bool Parallel(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return Zero(Cross(s0.p1() - s0.p0(), s1.p1() - s1.p0()));
}

} // namespace geometryR2

} // namespace zawa


namespace zawa {

namespace geometryR2 {

Point CrossPoint(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    assert(Intersect(s0, s1));
    if (Parallel(s0, s1)) {
        if (s0.p0() == s1.p0()) {
            if (Relation(s0.p0(), s0.p1(), s1.p1()) == ONLINE_BACK) {
                return s0.p0();
            }
            else {
                assert(false);
            }
        }
        else if (s0.p0() == s1.p1()) {
            if (Relation(s0.p0(), s0.p1(), s1.p0()) == ONLINE_BACK) {
                return s0.p0();
            }
            else {
                assert(false);
            }
        }
        else if (s0.p1() == s1.p0()) {
            if (Relation(s0.p1(), s0.p0(), s1.p1()) == ONLINE_BACK) {
                return s0.p1();
            }
            else {
                assert(false);
            }
        }
        else if (s0.p1() == s1.p1()) {
            if (Relation(s0.p1(), s0.p0(), s1.p0()) == ONLINE_BACK) {
                return s0.p1();
            }
            else {
                assert(false);
            }
        }
        else {
            assert(false);
        }
    }
    else {
        Vector base{s0.p1() - s0.p0()};
        Real baseNorm{base.norm()};
        Real r1{Abs(Cross(base, s1.p0() - s0.p0())) / baseNorm};
        Real r2{Abs(Cross(base, s1.p1() - s0.p0())) / baseNorm};
        return s1.p0() + (s1.p1() - s1.p0()) * (r1 / (r1 + r2));
    }
}

} // namespace geometryR2

} // namespace zawa
using namespace zawa::geometryR2;
namespace ranges = std::ranges;
namespace views = std::views;
int N;
Segment S[5];
Point START, GOAL;
Real f(std::vector<int> walls) {
    std::vector<Segment> curWall(S, S + N); 
    Point curGoal = GOAL;
    std::vector<Segment> go;
    for (int i : walls) {
        const Segment cur = curWall[i];
        const Line curL{cur.p0(), cur.p1()};
        go.push_back(cur);
        curGoal = Reflection(curGoal, curL);
        for (int j = 0 ; j < N ; j++) {
            curWall[j].p0() = Reflection(curWall[j].p0(), curL);
            curWall[j].p1() = Reflection(curWall[j].p1(), curL);
        }
    }
    Segment light{START, curGoal};
    std::vector<Point> pos; // 必ず通る場所
    pos.push_back(START);
    for (const Segment& s : go) {
        if (Intersect(s, light)) {
            pos.push_back(CrossPoint(s, light));
        }
        else {
            return 1e30;
        }
    }
    pos.push_back(curGoal);
    curWall = std::vector<Segment>(S, S + N);
    for (int i = 0 ; i < std::ssize(pos) ; i++) {
        if (Relation(light.p0(), light.p1(), pos[i]) != ON_SEGMENT) return 1e300;
    }
    for (int i = 1 ; i + 1 < std::ssize(pos) ; i++) {
        if (Relation(pos[i - 1], pos[i + 1], pos[i]) != ON_SEGMENT) return 1e300;
    }
    // std::cout << "-----------------" << std::endl;
    // for (int i : walls) std::cout << i << ' ';
    // std::cout << " : ";
    // for (auto p : pos) std::cout << p << ' ';
    // std::cout << Distance(light.p0(), light.p1()) << std::endl;
    for (int i = 0 ; i + 1 < std::ssize(pos) ; i++) {
        const Segment cur{pos[i], pos[i + 1]};
        for (int j = 0 ; j < N ; j++) if (Intersect(curWall[j],  cur)) {
            // std::cout << "hit " << i << ' ' << j << ' ' << curWall[j].p0() << ',' << curWall[j].p1() << std::endl;
            if (i - 1 >= 0 and i - 1 < std::ssize(walls) and walls[i - 1] == j) continue;
            if (i < std::ssize(walls) and walls[i] == j) continue;
            return 1e30;
        }
        if (i < std::ssize(walls)) {
            const int idx = walls[i];
            const Line curL{curWall[idx].p0(), curWall[idx].p1()};
            for (int j = 0 ; j < N ; j++) {
                curWall[j].p0() = Reflection(curWall[j].p0(), curL);
                curWall[j].p1() = Reflection(curWall[j].p1(), curL);
            }
        }
    }
    // std::cout << "valid" << std::endl;
    return Distance(light.p0(), light.p1());
}
Real solve() {
    std::vector<int> walls;
    Real res = 1e30;
    auto dfs = [&](auto dfs, int i) -> void {
        res = std::min(res, f(walls));
        if (i == 6) return;
        for (int j = 0 ; j < N ; j++) if (walls.empty() or walls.back() != j) {
            walls.push_back(j);
            dfs(dfs, i + 1);
            walls.pop_back();
        }
    };
    dfs(dfs, 0);
    return res;
}
int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(5);
    while (true) {
        std::cin >> N;
        if (N == 0) break;
        for (int i = 0 ; i < N ; i++) {
            std::cin >> S[i].p0() >> S[i].p1();
        }
        std::cin >> GOAL >> START;
        std::cout << solve() << '\n';
    }
}
accuracy: 1
time_ms: 200
memory_kb: 3712
final_rank: 16

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

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

using T = long double;
const T eps = 1e-6;
using Point = complex<T>;
using Poly = vector<Point>;
#define X real()
#define Y imag()
template <typename T> inline bool eq(const T &a, const T &b) {
    return fabs(a - b) < eps;
}
bool cmp(const Point &a, const Point &b) {
    auto sub = [&](Point a) {
        return (a.Y < 0 ? -1 : (a.Y == 0 && a.X >= 0 ? 0 : 1));
    };
    if (sub(a) != sub(b))
        return sub(a) < sub(b);
    return a.Y * b.X < a.X * b.Y;
}
struct Line {
    Point a, b, dir;
    Line() {}
    Line(Point _a, Point _b) : a(_a), b(_b), dir(b - a) {}
    Line(T A, T B, T C) {
        if (eq(A, (T).0)) {
            a = Point(0, C / B), b = Point(1 / C / B);
        } else if (eq(B, (T).0)) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
};
struct Segment : Line {
    Segment() {}
    Segment(Point _a, Point _b) : Line(_a, _b) {}
};
struct Circle {
    Point p;
    T r;
    Circle() {}
    Circle(Point _p, T _r) : p(_p), r(_r) {}
};

istream &operator>>(istream &is, Point &p) {
    T x, y;
    is >> x >> y;
    p = Point(x, y);
    return is;
}
ostream &operator<<(ostream &os, Point &p) {
    os << fixed << setprecision(12) << p.X << ' ' << p.Y;
    return os;
}
Point unit(const Point &a) {
    return a / abs(a);
}
T dot(const Point &a, const Point &b) {
    return a.X * b.X + a.Y * b.Y;
}
T cross(const Point &a, const Point &b) {
    return a.X * b.Y - a.Y * b.X;
}
Point rot(const Point &a, const T &theta) {
    return Point(cos(theta) * a.X - sin(theta) * a.Y,
                 sin(theta) * a.X + cos(theta) * a.Y);
}
Point rot90(const Point &a) {
    return Point(-a.Y, a.X);
}
T arg(const Point &a, const Point &b, const Point &c) {
    double ret = acos(dot(a - b, c - b) / abs(a - b) / abs(c - b));
    if (cross(a - b, c - b) < 0)
        ret = -ret;
    return ret;
}

Point Projection(const Line &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Reflection(const Line &l, const Point &p) {
    return p + (Projection(l, p) - p) * (T)2.;
}
int ccw(const Point &a, Point b, Point c) {
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // ccw

    if (cross(b, c) < -eps)
        return -1; // cw

    if (dot(b, c) < 0)
        return 2; // c,a,b

    if (norm(b) < norm(c))
        return -2; // a,b,c

    return 0;      // a,c,b

}
bool isOrthogonal(const Line &a, const Line &b) {
    return eq(dot(a.b - a.a, b.b - b.a), (T).0);
}
bool isParallel(const Line &a, const Line &b) {
    return eq(cross(a.b - a.a, b.b - b.a), (T).0);
}
bool isIntersect(const Segment &a, const Segment &b) {
    return ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) <= 0 and
           ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) <= 0;
}
int isIntersect(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d > a.r + b.r + eps)
        return 4;
    if (eq(d, a.r + b.r))
        return 3;
    if (eq(d, abs(a.r - b.r)))
        return 1;
    if (d < abs(a.r - b.r) - eps)
        return 0;
    return 2;
}
T Dist(const Line &a, const Point &b) {
    Point c = Projection(a, b);
    return abs(c - b);
}
T Dist(const Segment &a, const Point &b) {
    if (dot(a.b - a.a, b - a.a) < eps)
        return abs(b - a.a);
    if (dot(a.a - a.b, b - a.b) < eps)
        return abs(b - a.b);
    return abs(cross(a.b - a.a, b - a.a)) / abs(a.b - a.a);
}
T Dist(const Segment &a, const Segment &b) {
    if (isIntersect(a, b))
        return (T).0;
    T res = min({Dist(a, b.a), Dist(a, b.b), Dist(b, a.a), Dist(b, a.b)});
    return res;
}
Point Intersection(const Line &a, const Line &b) {
    T d1 = cross(a.b - a.a, b.b - b.a);
    T d2 = cross(a.b - a.a, a.b - b.a);
    if (eq(d1, (T)0.) and eq(d2, (T)0.))
        return b.a;
    return b.a + (b.b - b.a) * (d2 / d1);
}

/**
 * @brief Geometry
 */

int main() {
while(1) {
    int N;
    cin >> N;
    if (N == 0) return 0;
    vector<Segment> S(N);
    rep(i,0,N) {
        long double px, py, qx, qy;
        cin >> px >> py >> qx >> qy;
        S[i] = Segment(Point(px,py), Point(qx,qy));
    }
    Point A, B;
    {
        long double ax, ay, bx, by;
        cin >> ax >> ay >> bx >> by;
        A = Point(ax,ay), B = Point(bx,by);
    }
    long double ANS;
    auto Solve = [&](vector<int> ord) -> void {
        Point D = B;
        rrep(_,0,ord.size()) {
            int i = ord[_];
            D = Reflection(S[i], D);
        }
        Point C = A;
        if (eq(C,D)) return;
        Point V = unit(D-C);
        for (int i : ord) {
            int next = -1;
            long double min = inf;
            Segment Beam(C, C + V * 10000.0L);
            rep(j,0,N) {
                if (!isIntersect(S[j], Beam)) continue;
                Point E = Intersection(S[j], Beam);
                if (eq(C,E)) continue;
                if (chmin(min, abs(C-E))) next = j;
            }
            if (next != i) return;
            {
                Point E = Intersection(S[next], Beam);
                C = E;
                V = Reflection(S[next], E+V) - E;
            }
        }
        Point W = (B-C)/V;
        if (W.real() < 0.0L) return;
        rep(i,0,N) {
            if (!ord.empty() && i == ord.back()) continue;
            Segment Beam(C,B);
            if (isIntersect(S[i], Beam)) return;
        }
        chmin(ANS, abs(D-A));
    };
    auto DFS = [&](auto self, vector<int> ord) -> void {
        if ((int)ord.size() >= 6) return;
        Solve(ord);
        rep(i,0,N) {
            if (!ord.empty() && ord.back() == i) continue;
            ord.push_back(i);
            self(self,ord);
            ord.pop_back();
        }
    };
    vector<int> ord = {};
    ANS = inf;
    DFS(DFS,ord);
    printf("%.12Lf\n", ANS);
}
}
accuracy: 1
time_ms: 20
memory_kb: 3436
final_rank: 7

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


using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-9, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}

Point operator*(const Point &p, const Real &d) {
  return Point(real(p) * d, imag(p) * d);
}

istream &operator>>(istream &is, Point &p) {
  Real a, b;
  is >> a >> b;
  p = Point(a, b);
  return is;
}

ostream &operator<<(ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

// a-b-c の角度のうち小さい方を返す
Real get_angle(const Point &a, const Point &b, const Point &c) {
  const Point v(b - a), w(c - b);
  Real alpha = atan2(v.imag(), v.real()), beta = atan2(w.imag(), w.real());
  if (alpha > beta) swap(alpha, beta);
  Real theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

namespace std {
bool operator<(const Point &a, const Point &b) {
  return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
}  // namespace std

struct Line {
  Point a, b;

  Line() = default;

  Line(Point a, Point b) : a(a), b(b) {}

  Line(Real A, Real B, Real C)  // Ax + By = C
  {
    if (eq(A, 0)) a = Point(0, C / B), b = Point(1, C / B);
    else if (eq(B, 0)) b = Point(C / A, 0), b = Point(C / A, 1);
    else a = Point(0, C / B), b = Point(C / A, 0);
  }

  friend ostream &operator<<(ostream &os, Line &p) { return os << p.a << " to " << p.b; }

  friend istream &operator>>(istream &is, Line &a) { return is >> a.a >> a.b; }
};

struct Segment : Line {
  Segment() = default;

  Segment(Point a, Point b) : Line(a, b) {}
};

using Segments = vector<Segment>;

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}

// 点の回転方向
int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS) return +1;   // "COUNTER_CLOCKWISE"
  if (cross(b, c) < -EPS) return -1;  // "CLOCKWISE"
  if (dot(b, c) < 0) return +2;       // "ONLINE_BACK"
  if (norm(b) < norm(c)) return -2;   // "ONLINE_FRONT"
  return 0;                           // "ON_SEGMENT"
}

Point projection(const Line &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}
Point projection(const Segment &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

// 反射
// 直線 l を対称軸として点 p  と線対称にある点を求める
Point reflection(const Line &l, const Point &p) {
  return p + (projection(l, p) - p) * 2.0;
}
Point reflection(const Segment &s, const Point &p) {
  return p + (projection(s, p) - p) * 2.0;
}

bool intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

Real distance(const Point &a, const Point &b) {
  return abs(a - b);
}

Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if (eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
  return m.a + (m.b - m.a) * B / A;
}
Point crosspoint(const Segment &l, const Segment &m) {
  return crosspoint(Line(l), Line(m));
}

template<class T>
bool chmin(T &a, const T &b) {if (a > b) {a = b; return 1;} return 0;}

Real check(vector<int> &ids, const vector<Segment> &mirror, const vector<Point> &ST)
{
  bool debug = false;
  
  int siz = ids.size();
  vector<Point> S(siz + 1), T(siz + 1);
  S[0] = ST[0];
  for (int i = 0; i < siz; ++i)
  {
    S[i+1] = reflection(mirror[ids[i]], S[i]);
  }
  T[siz] = ST[1];
  for (int i = siz - 1; i >= 0; --i)
  {
    T[i] = reflection(mirror[ids[i]], T[i+1]);
  }
  
  if (debug)
  {
    for (int i = 0; i <= siz; ++i)
    {
      cout << S[i] << " " << T[i] << endl;
    }
  }
  
  
  bool ret = true;
  for (int i = 0; i <= siz; ++i)
  {
    int id0 = -1, id1 = -2;
    if (i > 0) id0 = ids[i-1];
    if (i < siz) id1 = ids[i];
    
    Segment seg(S[i], T[i]);
    
    vector<pair<Real, int>> vec;
    Point base = S[i];
    vec.push_back({distance(S[i], base), -1});
    vec.push_back({distance(T[i], base), -2});
    for (int j = 0; j < mirror.size(); ++j)
    {
      if (intersect(seg, mirror[j]))
      {
        vec.push_back({distance(crosspoint(seg, mirror[j]), base), j});
        if (debug) cout << j << " " << crosspoint(seg, mirror[j]) << endl;
      }
    }
    
    sort(vec.begin(), vec.end());
    
    bool tmp = false;
    for (int j = 0; j + 1 < vec.size(); ++j)
    {
      auto [d0, i0] = vec[j];
      auto [d1, i1] = vec[j+1];
      if (i0 == id0 && i1 == id1) tmp = true;
      // if (i0 == id1 && i1 == id0) tmp = true;
    }
    ret &= tmp;
  }
  
  return (ret ? distance(S[0], T[0]) : 1e18);
}

void dfs(int depth, vector<int> &ids, const vector<Segment> &mirror, const vector<Point> &ST, Real &ans)
{
  assert((int)ids.size() == depth);
  
  chmin(ans, check(ids, mirror, ST));
  
  if (depth == 5) return;
  
  int N = mirror.size();
  for (int i = 0; i < mirror.size(); ++i)
  {
    ids.emplace_back(i);
    dfs(depth + 1, ids, mirror, ST, ans);
    ids.pop_back();
  }
  
  return;
}

bool is_end = false;

void solve()
{
  int N; cin >> N;
  if (N == 0)
  {
    is_end = true;
    return;
  }
  
  vector<Segment> mirror(N);
  for (int i = 0; i < N; ++i)
  {
    Real px, py, qx, qy; cin >> px >> py >> qx >> qy;
    mirror[i] = Segment(Point(px, py), Point(qx, qy));
  }
  Real sx, sy, tx, ty; cin >> sx >> sy >> tx >> ty;
  Point S(sx, sy), T(tx, ty);
  vector<Point> ST{S, T};
  
  Real ans = 1e18;
  vector<int> ids;
  dfs(0, ids, mirror, ST, ans);
  
  cout << fixed << setprecision(20);
  cout << ans << endl;
  
  return;
}

int main()
{
  while (!is_end)
  {
    solve();
  }
  
  return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3548
final_rank: 13

code_snippet: #pragma GCC ta g("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 510000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
//const int mod = 1e9 + 7;
const int mod = 998244353;

namespace geometry {
    // Point : 複素数型を位置ベクトルとして扱う
    // 実軸(real)をx軸、挙軸(imag)をy軸として見る
    using D = long double;
    using Point = complex<D>;
    const D EPS = 1e-7;
    const D PI = acosl(-1);

    inline bool equal(const D &a, const D &b) { return fabs(a - b) < EPS; }

    // 単位ベクトル(unit vector)を求める
    Point unitVector(const Point &a) { return a / abs(a); }

    // 法線ベクトル(normal vector)を求める
    // 90度回転した単位ベクトルをかける
    // -90度がよければPoint(0, -1)をかける
    Point normalVector(const Point &a) { return a * Point(0, 1); }

    // 内積(dot product) : a・b = |a||b|cosΘ
    D dot(const Point &a, const Point &b) {
        return (a.real() * b.real() + a.imag() * b.imag());
    }

    // 外積(cross product) : a×b = |a||b|sinΘ
    D cross(const Point &a, const Point &b) {
        return (a.real() * b.imag() - a.imag() * b.real());
    }

    // 点pを反時計回りにtheta度回転
    // thetaはラジアン！！！
    Point rotate(const Point &p, const D &theta) {
        return Point(cos(theta) * p.real() - sin(theta) * p.imag(),
                     sin(theta) * p.real() + cos(theta) * p.imag());
    }

    // ラジアン->度
    D radianToDegree(const D &radian) { return radian * 180.0 / PI; }

    // 度->ラジアン
    D degreeToRadian(const D &degree) { return degree * PI / 180.0; }

    // 点の回転方向
    // 点a, b, cの位置関係について(aが基準点)
    int ccw(const Point &a, Point b, Point c) {
        b -= a, c -= a;
        // 点a, b, c が
        // 反時計回りの時、
        if(cross(b, c) > EPS) return 1;
        // 時計回りの時、
        if(cross(b, c) < -EPS) return -1;
        // c, a, bがこの順番で同一直線上にある時、
        if(dot(b, c) < 0) return 2;
        // a, b, cがこの順番で同一直線上にある場合、
        if(norm(b) < norm(c)) return -2;
        // cが線分ab上にある場合、
        return 0;
    }

    // Line : 直線を表す構造体
    // b - a で直線・線分を表せる
    struct Line {
        Point a, b;
        Line() = default;
        Line(Point a, Point b) : a(a), b(b) {}
        // Ax+By=C
        Line(D A, D B, D C) {
            if(equal(A, 0)) {
                a = Point(0, C / B), b = Point(1, C / B);
            } else if(equal(B, 0)) {
                b = Point(C / A, 0), b = Point(C / A, 1);
            } else {
                a = Point(0, C / B), b = Point(C / A, 0);
            }
        }
    };

    // Segment : 線分を表す構造体
    // Lineと同じ
    struct Segment : Line {
        Segment() = default;

        Segment(Point a, Point b) : Line(a, b) {}
    };

    // Circle : 円を表す構造体
    // pが中心の位置ベクトル、rは半径
    struct Circle {
        Point p;
        D r;

        Circle() = default;

        Circle(Point p, D r) : p(p), r(r) {}
    };

    // 2直線の直交判定 : a⊥b <=> dot(a, b) = 0
    bool isOrthogonal(const Line &a, const Line &b) {
        return equal(dot(a.b - a.a, b.b - b.a), 0);
    }
    // 2直線の平行判定 : a//b <=> cross(a, b) = 0
    bool isParallel(const Line &a, const Line &b) {
        return equal(cross(a.b - a.a, b.b - b.a), 0);
    }

    // 点cが直線ab上にあるか
    bool isPointOnLine(const Point &a, const Point &b, const Point &c) {
        return isParallel(Line(a, b), Line(a, c));
    }

    // 点cが"線分"ab上にあるか
    bool isPointOnSegment(const Point &a, const Point &b, const Point &c) {
        // |a-c| + |c-b| <= |a-b| なら線分上
        return (abs(a - c) + abs(c - b) < abs(a - b) + EPS);
    }

    // 直線lと点pの距離を求める
    D distanceBetweenLineAndPoint(const Line &l, const Point &p) {
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 線分lと点pの距離を求める
    // 定義：点pから「線分lのどこか」への最短距離
    D distanceBetweenSegmentAndPoint(const Segment &l, const Point &p) {
        if(dot(l.b - l.a, p - l.a) < EPS) return abs(p - l.a);
        if(dot(l.a - l.b, p - l.b) < EPS) return abs(p - l.b);
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 直線s, tの交点の計算
    Point crossPoint(const Line &s, const Line &t) {
        D d1 = cross(s.b - s.a, t.b - t.a);
        D d2 = cross(s.b - s.a, s.b - t.a);
        if(equal(abs(d1), 0) && equal(abs(d2), 0)) return t.a;
        return t.a + (t.b - t.a) * (d2 / d1);
    }

    // 線分s, tの交点の計算
    Point crossPoint(const Segment &s, const Segment &t) {
        return crossPoint(Line(s), Line(t));
    }

    // 線分sと線分tが交差しているかどうか
    // bound:線分の端点を含むか
    bool isIntersect(const Segment &s, const Segment &t, bool bound) {
        return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) < bound &&
               ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) < bound;
    }

    // 線分sとtの距離
    D distanceBetweenSegments(const Segment &s, const Segment &t) {
        if(isIntersect(s, t, 1)) return (D)(0);
        D ans = distanceBetweenSegmentAndPoint(s, t.a);
        chmin(ans, distanceBetweenSegmentAndPoint(s, t.b));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.a));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.b));
        return ans;
    }

    // 射影(projection)
    // 直線(線分)lに点pから引いた垂線の足を求める
    Point projection(const Line &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    Point projection(const Segment &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    // 反射(reflection)
    // 直線lを対称軸として点pと線対称の位置にある点を求める
    Point reflection(const Line &l, const Point &p) {
        return p + (projection(l, p) - p) * (D)2.0;
    }

    // 2つの円の交差判定
    // 返り値は共通接線の数
    int isIntersect(const Circle &c1, const Circle &c2) {
        D d = abs(c1.p - c2.p);
        // 2つの円が離れている場合
        if(d > c1.r + c2.r + EPS) return 4;
        // 外接している場合
        if(equal(d, c1.r + c2.r)) return 3;
        // 内接している場合
        if(equal(d, abs(c1.r - c2.r))) return 1;
        // 内包している場合
        if(d < abs(c1.r - c2.r) - EPS) return 0;
        return 2;
    }

    // 2つの円の交点
    vector<Point> crossPoint(const Circle &c1, const Circle &c2) {
        vector<Point> res;
        int mode = isIntersect(c1, c2);
        // 2つの中心の距離
        D d = abs(c1.p - c2.p);
        // 2円が離れている場合
        if(mode == 4) return res;
        // 1つの円がもう1つの円に内包されている場合
        if(mode == 0) return res;
        // 2円が外接する場合
        if(mode == 3) {
            D t = c1.r / (c1.r + c2.r);
            res.emplace_back(c1.p + (c2.p - c1.p) * t);
            return res;
        }
        // 内接している場合
        if(mode == 1) {
            if(c2.r < c1.r - EPS) {
                res.emplace_back(c1.p + (c2.p - c1.p) * (c1.r / d));
            } else {
                res.emplace_back(c2.p + (c1.p - c2.p) * (c2.r / d));
            }
            return res;
        }
        // 2円が重なる場合
        D rc1 = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * d);
        D rs1 = sqrt(c1.r * c1.r - rc1 * rc1);
        if(c1.r - abs(rc1) < EPS) rs1 = 0;
        Point e12 = (c2.p - c1.p) / abs(c2.p - c1.p);
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, 1));
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, -1));
        return res;
    }

    // 点pが円cの内部(円周上も含む)に入っているかどうか
    bool isInCircle(const Circle &c, const Point &p) {
        D d = abs(c.p - p);
        return (equal(d, c.r) || d < c.r - EPS);
    }

    // 円cと直線lの交点
    vector<Point> crossPoint(const Circle &c, const Line &l) {
        vector<Point> res;
        D d = distanceBetweenLineAndPoint(l, c.p);
        // 交点を持たない
        if(d > c.r + EPS) return res;
        // 接する
        Point h = projection(l, c.p);
        if(equal(d, c.r)) {
            res.emplace_back(h);
            return res;
        }
        Point e = unitVector(l.b - l.a);
        D ph = sqrt(c.r * c.r - d * d);
        res.emplace_back(h - e * ph);
        res.emplace_back(h + e * ph);
        return res;
    }

    // 点pを通る円cの接線
    // 2本あるので、接点のみを返す
    vector<Point> tangentToCircle(const Point &p, const Circle &c) {
        return crossPoint(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
    }

    // 円の共通接線
    vector<Line> tangent(const Circle &a, const Circle &b) {
        vector<Line> ret;
        // 2円の中心間の距離
        D g = abs(a.p - b.p);
        // 円が内包されている場合
        if(equal(g, 0)) return ret;
        Point u = unitVector(b.p - a.p);
        Point v = rotate(u, PI / 2);
        for(int s : {-1, 1}) {
            D h = (a.r + b.r * s) / g;
            if(equal(h * h, 1)) {
                ret.emplace_back(a.p + (h > 0 ? u : -u) * a.r,
                                 a.p + (h > 0 ? u : -u) * a.r + v);

            } else if(1 - h * h > 0) {
                Point U = u * h, V = v * sqrt(1 - h * h);
                ret.emplace_back(a.p + (U + V) * a.r,
                                 b.p - (U + V) * (b.r * s));
                ret.emplace_back(a.p + (U - V) * a.r,
                                 b.p - (U - V) * (b.r * s));
            }
        }
        return ret;
    }

    // 多角形の面積を求める
    D PolygonArea(const vector<Point> &p) {
        D res = 0;
        int n = p.size();
        for(int i = 0; i < n - 1; i++) res += cross(p[i], p[i + 1]);
        res += cross(p[n - 1], p[0]);
        return res * 0.5;
    }

    // 凸多角形かどうか
    bool isConvex(const vector<Point> &p) {
        int n = p.size();
        int now, pre, nxt;
        for(int i = 0; i < n; i++) {
            pre = (i - 1 + n) % n;
            nxt = (i + 1) % n;
            now = i;
            if(ccw(p[pre], p[now], p[nxt]) == -1) return false;
        }
        return true;
    }

    // 凸包 O(NlogN)
    vector<Point> ConvexHull(vector<Point> &p) {
        int n = (int)p.size(), k = 0;
        sort(all(p), [](const Point &a, const Point &b) {
            return (real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b));
        });
        vector<Point> ch(2 * n);
        // 一直線上の3点を含める -> (< -EPS)
        // 含め無い -> (< EPS)
        for(int i = 0; i < n; ch[k++] = p[i++]) { // lower
            while(k >= 2 &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) { // upper
            while(k >= t &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        ch.resize(k - 1);
        return ch;
    }

    // 多角形gに点pが含まれているか?
    // 含まれる:2, 辺上にある:1, 含まれない:0
    int isContained(const vector<Point> &g, const Point &p) {
        bool in = false;
        int n = (int)g.size();
        for(int i = 0; i < n; i++) {
            Point a = g[i] - p, b = g[(i + 1) % n] - p;
            if(imag(a) > imag(b)) swap(a, b);
            if(imag(a) <= EPS && EPS < imag(b) && cross(a, b) < -EPS) in = !in;
            if(cross(a, b) == 0 && dot(a, b) <= 0) return 1;
        }
        return (in ? 2 : 0);
    }

    vector<Point> convex_cut(const vector<Point> &g, Line l){
        vector<Point> ret;
        for(int i=0; i<g.size(); i++){
            Point now = g[i], nxt = g[(i+1)%g.size()];
            if(ccw(l.a,l.b,now) != -1) ret.push_back(now);
            if(ccw(l.a,l.b,now) * ccw(l.a,l.b,nxt) < 0){
                ret.push_back(crossPoint(Line(now,nxt),l));
            }
        }
        return ret;
    }

    bool equal (const Point &a, const Point &b) {
        return equal(a.real(),b.real()) && equal(a.imag(),b.imag());
    }

    D circlesIntersectArea(Circle &a, Circle &b){
        double d = abs(a.p - b.p);
        if(d >= a.r + b.r - EPS) return 0; //2円が離れている
        auto R = minmax(a.r,b.r);
        if(d <= R.second - R.first + EPS) return R.first*R.first*pi; //円が円を内包する
        D theta1 = acos((d*d + a.r*a.r - b.r*b.r)/(2*a.r*d));
        D theta2 = acos((d*d + b.r*b.r - a.r*a.r)/(2*b.r*d));
        D ret = a.r*a.r*(theta1-cos(theta1)*sin(theta1)) + b.r*b.r*(theta2-cos(theta2)*sin(theta2));
        return ret;
    }
} // namespace geometry

using namespace geometry;

bool solve(){
	int n; cin >> n;
	if(!n) return false;
	vector<Point> P(n),Q(n);
	rep(i,n){
		int a,b,c,d; cin >> a >> b >> c >> d;
		P[i] = Point(a,b); Q[i] = Point(c,d);
	}
	Point S,G;
	{
		int a,b,c,d; cin >> a >> b >> c >> d;
		S = Point(a,b); G = Point(c,d);
	}

	D ans = inf;

	vector<int> mirrors;

	auto check = [&]() -> void {
		//debug(mirrors);
		bool f = true;
		int sz = mirrors.size();
		auto p = P, q = Q;
		auto s = S, g = G;
		vector<vector<Point>> ps(sz+1,vector<Point>(n));
		vector<vector<Point>> qs(sz+1,vector<Point>(n));
		rep(i,n){
			ps[0][i] = p[i];
			qs[0][i] = q[i];
		}
		D pre = 0;
		rep(i,sz){
			int id = mirrors[i];
			Line l(p[id],q[id]);
			rep(j,n){
				if(id != j){
					p[j] = reflection(l,p[j]);
					q[j] = reflection(l,q[j]);
				}
				ps[i+1][j] = p[j];
				qs[i+1][j] = q[j];
			}
			g = reflection(l,g);
		}
		Segment seg(s,g);
		D res = 0;
		for(int i=sz-1; i>=0; i--){
			seg = Segment(s,g);
			int id = mirrors[i];
			Line l(p[id],q[id]);
			vector<tuple<D,int,Point>> crosses;
			rep(j,n){
				Segment mir(ps[i+1][j],qs[i+1][j]);
				if(i<sz-1 && mirrors[i+1] == j) continue;
				if(isIntersect(seg,mir,true)){
					Point cr = crossPoint(seg,mir);
					crosses.emplace_back(abs(cr-g),j,cr);
				}
			}
			sort(all(crosses),[](tuple<D,int,Point> a, tuple<D,int,Point> b){
				return get<0>(a) < get<0>(b);
			});
			if(crosses.empty()){
				f = false; break;
			}
			if(get<1>(crosses[0]) != mirrors[i]){
				f = false; break;
			}
			res += get<0>(crosses[0]);
			g = get<2>(crosses[0]);
		}

		{
			vector<pair<D,int>> crosses;
			rep(j,n){
				Segment mir(ps[0][j],qs[0][j]);
				if(sz > 0 && mirrors[0] == j) continue;
				if(isIntersect(seg,mir,true)){
					Point cr = crossPoint(seg,mir);
					crosses.emplace_back(abs(cr-s),j);
				}
			}
			sort(all(crosses));
			if(!crosses.empty() && crosses[0].first <= abs(s-g) - eps){
				f = false;
			}
		}

		if(f) chmin(ans, res + abs(g-s));
	};

	auto dfs = [&](auto &&dfs, int now) -> void {
		if(now > 5) return;
		check();
		rep(i,n){
			if(!mirrors.empty() && mirrors.back() == i) continue;
			mirrors.push_back(i);
			dfs(dfs,now+1);
			mirrors.pop_back();
		}
	};
	dfs(dfs,0);
	
	printf("%.10Lf\n",ans);
	return true;
}

int main(){
	while(solve());
}
accuracy: 1
time_ms: 50
memory_kb: 3552
final_rank: 11

code_snippet: /*	author:  Kite_kuma
	created: 2021.11.02 17:19:16 */

#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;

#pragma region macros

#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define popcnt(n) __builtin_popcountll((long long)n)

#define REPname(a, b, c, d, e, ...) e
#define rep(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int Counter_in_rep_macro = 0; Counter_in_rep_macro < (x); ++Counter_in_rep_macro)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))

#define DREPname(a, b, c, d, e, ...) e
#define drep(...) DREPname(__VA_ARGS__, DREP3, DREP2, DREP1)(__VA_ARGS__)
#define DREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define DREP2(i, l, r) for(int i = (r)-1; i >= (l); --i)
#define DREP3(i, l, r, c) for(int i = (r)-1; i >= (l); i -= (c))

#pragma endregion

#pragma region aliases

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = std::vector<int>;
using vvi = std::vector<std::vector<int>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vll = std::vector<ll>;
using vvll = std::vector<vll>;
using vvvll = std::vector<vvll>;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;
template <class T = ll>
using V = std::vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
template <class T = ll>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T = ll>
using pqdn = std::priority_queue<T>;

#pragma endregion

#pragma region constants

const int inf = 1e9;
const long long INF = 1e18;
const long double pi = acos(-1);
const char dl = '\n';
const char sp = ' ';
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

const int mod_1000000007 = 1000000007;
const int mod_998244353 = 998244353;

#pragma endregion

#pragma region basic_operation

template <class T0, class T1, class T2>
inline bool in_range(T0 x, T1 lef, T2 rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool f = 1) { std::cout << (f ? "Yes" : "No") << '\n'; }
void No() { std::cout << "No\n"; }
void YES(bool f = 1) { std::cout << (f ? "YES" : "NO") << '\n'; }
void NO() { std::cout << "NO\n"; }

template <class T>
void drop(T answer) {
	std::cout << answer << '\n';
	exit(0);
}

void err(bool flag = true) {
	if(!flag) return;
	std::cout << -1 << '\n';
	exit(0);
}

template <class T>
void vout(std::vector<T> const &v, bool vertically = 0) {
	if(vertically) {
		for(auto const &a : v) {
			std::cout << a << '\n';
		}
		return;
	}
	for(auto it = v.begin(); it != v.end(); it++) {
		std::cout << (*it);
		if(it != v.end() - 1) {
			std::cout << ' ';
		}
	}
	std::cout << '\n';
	return;
}

inline void print() { std::cout << '\n'; }
template <class T>
inline void print(T x) {
	std::cout << x << '\n';
	return;
}
template <typename Head, typename... Tail>
void print(Head H, Tail... T) {
	std::cout << H << " ";
	print(T...);
}

template <class T>
void add(std::vector<T> &v, T val) {
	for(auto &a : v) a += val;
	return;
}

template <class T>
T dup(T a, T b) {
	assert(b != 0);
	return (a + b - 1) / b;
}

template <class T>
T greatest_lower_multiple(T x, T d) {
	if(d == 0) return 0;
	if(d < 0) d *= -1;
	T y = x % d;
	if(y < 0) y += d;
	return x - y;
}

template <class T>
T least_upper_multiple(T x, T d) {
	return -greatest_lower_multiple(-x, d);
}

long long POW(long long a, long long n) {
	long long res = 1;
	while(n > 0) {
		if(n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}

long long modpow(long long a, long long n, long long mod) {	 // a^n mod
	assert(n >= 0 && mod);
	if(mod == 1) return 0LL;
	long long res = 1;
	a %= mod;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res < 0 ? res + mod : res;
}

// return x which satisfies a * x % mod == gcd(a, mod)
// not (mod | a)
long long modinv(long long a, long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		std::swap(a, b);
		u -= t * v;
		std::swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

template <class T>
int lb(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::lower_bound(a.begin(), a.end(), x));
}
template <class T>
int ub(const std::vector<T> &a, const T x) {
	return std::distance(a.begin(), std::upper_bound(a.begin(), a.end(), x));
}
template <class T>
void unq_sort(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<int> press(std::vector<T> &a) {
	auto vec = a;
	unq_sort(vec);
	std::vector<int> ret;
	for(auto &v : a) ret.push_back(lb(vec, v));
	return ret;
}

#pragma endregion

#pragma region input
#define VEC(type, name, size) \
	vector<type> name(size);  \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHR(...)      \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DBL(...)        \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define TPL3(type0, type1, type2, name)   \
	std::tuple<type0, type1, type2> name; \
	scanner::INPUT(name);
#define TPL4(type0, type1, type2, type3, name)   \
	std::tuple<type0, type1, type2, type3> name; \
	scanner::INPUT(name);

namespace scanner {
template <class T>
void scan(T &a) {
	std::cin >> a;
}

template <class T, class L>
void scan(std::pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}

template <class T0, class T1, class T2>
void scan(std::tuple<T0, T1, T2> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	scan(t0);
	scan(t1);
	scan(t2);
	p = std::make_tuple(t0, t1, t2);
}

template <class T0, class T1, class T2, class T3>
void scan(std::tuple<T0, T1, T2, T3> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	T3 t3;
	scan(t0);
	scan(t1);
	scan(t2);
	scan(t3);
	p = std::make_tuple(t0, t1, t2, t3);
}

template <class T>
void scan(std::vector<T> &a) {
	for(auto &i : a) scan(i);
}

void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &... tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner

template <typename T1, typename T2>
std::istream &operator>>(std::istream &is, std::pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}
#pragma endregion

#pragma region debug

#pragma region output
template <typename T1, typename T2>
std::ostream &std::operator<<(std::ostream &os, const std::pair<T1, T2> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <class T>
std::ostream &std::operator<<(std::ostream &os, const std::vector<T> &v) {
	for(int i = 0; i < (int)v.size(); i++) {
		if(i) os << " ";
		os << v[i];
	}
	return os;
}
#pragma endregion

#pragma region view

namespace viewer {
void view(const long long e) {
	if(e == INF)
		std::cerr << "INF";
	else if(e == -INF)
		std::cerr << "-INF";
	else
		std::cerr << e;
}

void view(const int e) {
	if(e == inf)
		std::cerr << "inf";
	else if(e == -inf)
		std::cerr << "-inf";
	else
		std::cerr << e;
}

template <typename T>
void view(const T e) {
	std::cerr << e;
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << "(";
	view(p.first);
	std::cerr << ", ";
	view(p.second);
	std::cerr << ")";
}

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ")";
}

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p) {
	std::cerr << "(";
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ", ";
	view(std::get<3>(p));
	std::cerr << ")";
}

template <typename T>
void view(const std::set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::unordered_set<T> &s) {
	if(s.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<T> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(const auto &e : v) {
		view(e);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	std::cerr << "{\n";
	for(const auto &v : vv) {
		std::cerr << "\t";
		view(v);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	std::cerr << "{\n";
	for(const auto &c : v) {
		std::cerr << "\t(";
		view(c.first);
		std::cerr << ", ";
		view(c.second);
		std::cerr << ")\n";
	}
	std::cerr << "}";
}

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v) {
	if(v.empty()) {
		std::cerr << "{ }";
		return;
	}
	std::cerr << '{';
	for(const auto &t : v) {
		std::cerr << "\n\t";
		view(t);
		std::cerr << ",";
	}
	std::cerr << "\n}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m) {
	std::cerr << "{\n";
	for(const auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		std::cerr << "] : ";
		view(t.second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}
}  // namespace viewer

#pragma endregion

// when debugging : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	viewer::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "\b\b]\n";                                   \
	} while(0)
#define dump(x)                                      \
	do {                                             \
		std::cerr << __LINE__ << " " << #x << " : "; \
		viewer::view(x);                             \
		std::cerr << '\n';                           \
	} while(0)

#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

#pragma endregion

#pragma region geometry_light

using Real = long double;
using R = Real;
using Point = std::complex<Real>;
using Vec = Point;
const Real EPS = 1e-10, PI = acos(-1);

inline bool eq(const Real &a, const Real &b) { return fabs(b - a) < EPS; }
inline bool eq(const Point &a, const Point &b) { return fabs(b - a) < EPS; }
/*
	-1: a < b
	0 : a == b
	1 : a > b
*/
inline int compare(const Real &a, const Real &b) { return eq(a, b) ? 0 : a < b ? -1 : 1; }
inline int sign(const Real &a) { return fabs(a) < EPS ? 0 : a < 0 ? -1 : 1; }

namespace std {
const Point operator*(const Point &p, const Real &d) { return Point(real(p) * d, imag(p) * d); }
}  // namespace std

std::istream &operator>>(std::istream &is, Point &p) {
	Real a, b;
	is >> a >> b;
	p = Point(a, b);
	return is;
}
std::ostream &operator<<(std::ostream &os, Point &p) { return os << std::fixed << std::setprecision(10) << p.real() << " " << p.imag(); }

// rotate point 'p' for counter clockwise direction
const Point rotate(const Real &theta, const Point &p) {
	return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

const Real radian_to_degree(const Real &r) { return (r * 180.0 / PI); }

const Real degree_to_radian(const Real &d) { return (d * PI / 180.0); }

// get angle a-b-c (<pi)
const Real get_angle(const Point &a, const Point &b, const Point &c) {
	const Point v(a - b), w(c - b);
	Real theta = fabs(atan2(w.imag(), w.real()) - atan2(v.imag(), v.real()));
	return std::min(theta, 2 * PI - theta);
}

namespace std {
bool operator<(const Point &a, const Point &b) { return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag(); }
}  // namespace std

struct Line {
	Point a, b;

	Line() = default;

	Line(Point a, Point b) : a(a), b(b) {}

	Line(Real A, Real B, Real C)  // Ax + By = C
	{
		if(eq(A, 0))
			a = Point(0, C / B), b = Point(1, C / B);
		else if(eq(B, 0))
			b = Point(C / A, 0), b = Point(C / A, 1);
		else
			a = Point(0, C / B), b = Point(C / A, 0);
	}

	friend std::ostream &operator<<(std::ostream &os, Line &p) { return os << p.a << " -- " << p.b; }

	friend std::istream &operator>>(std::istream &is, Line &a) { return is >> a.a >> a.b; }
};

struct Segment : Line {
	Segment() = default;

	Segment(Point a, Point b) : Line(a, b) {}
};

struct Circle {
	Point p;
	Real r;

	Circle() = default;

	Circle(Point p, Real r) : p(p), r(r) {}
};

using Points = std::vector<Point>;
using Polygon = std::vector<Point>;
using Segments = std::vector<Segment>;
using Lines = std::vector<Line>;
using Circles = std::vector<Circle>;

const Real cross(const Point &a, const Point &b) { return real(a) * imag(b) - imag(a) * real(b); }
const Real dot(const Point &a, const Point &b) { return real(a) * real(b) + imag(a) * imag(b); }

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
const int ccw(const Point &a, Point b, Point c) {
	b = b - a, c = c - a;
	if(cross(b, c) > EPS) return +1;		// "COUNTER_CLOCKWISE"
	if(cross(b, c) < -EPS) return -1;		// "CLOCKWISE"
	if(dot(b, c) < -EPS) return +2;			// "ONLINE_BACK"
	if(norm(b) + EPS < norm(c)) return -2;	// "ONLINE_FRONT"
	return 0;								// "ON_SEGMENT"
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool parallel(const Line &a, const Line &b) { return eq(cross(a.b - a.a, b.b - b.a), 0.0); }

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool orthogonal(const Line &a, const Line &b) { return eq(dot(a.a - a.b, b.a - b.b), 0.0); }

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
Point projection(const Line &l, const Point &p) {
	double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p) {
	double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + (l.a - l.b) * t;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
Point reflection(const Line &l, const Point &p) { return projection(l, p) * 2.0 - p; }

int intersect(const Line &l, const Point &p) { return int(abs(ccw(l.a, l.b, p)) != 1); }

int intersect(const Line &l, const Line &m) {
	if(intersect(l, m.a) && intersect(l, m.b)) return -1;
	return int(abs(cross(l.b - l.a, m.b - m.a)) > EPS);
}

int intersect(const Segment &s, const Point &p) { return int(ccw(s.a, s.b, p) == 0); }

int intersect(const Line &l, const Segment &s) {
	if(intersect(l, s.a) && intersect(l, s.b)) return -1;
	return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < EPS;
}

Real distance(const Line &l, const Point &p);

int intersect(const Circle &c, const Line &l) {
	Real d = c.r - distance(l, c.p);
	return fabs(d) < EPS ? 1 : d > 0. ? 2 : 0;
}

int intersect(const Circle &c, const Point &p) { return int(abs(abs(p - c.p) - c.r) < EPS); }

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B
int intersect(const Segment &s, const Segment &t) {
	if(eq(s.a, s.b)) return intersect(t, s.a);
	if(intersect(Line(s), t.a) && intersect(Line(s), t.b) &&
	   std::max(std::min(s.a, s.b), std::min(t.a, t.b)) < std::min(std::max(s.a, s.b), std::max(t.a, t.b)))
		return -1;
	return int(ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0);
}

int intersect(const Circle &c, const Segment &l) {
	const Point h = projection(l, c.p);
	if(norm(h - c.p) - c.r * c.r > EPS) return 0;
	auto d1 = abs(c.p - l.a), d2 = abs(c.p - l.b);
	if(compare(d1, c.r) == -1 && compare(d2, c.r) == -1) return 0;
	if(d1 < c.r - EPS && d2 > c.r - EPS || d1 > c.r - EPS && d2 < c.r - EPS) return 1;
	return dot(l.a - h, l.b - h) < 0 ? 2 : 0;
}

Real distance(const Point &a, const Point &b);

int number_of_common_tangents(const Circle &c1, const Circle &c2) {
	Real r1 = std::min(c1.r, c2.r), r2 = std::max(c1.r, c2.r), d = distance(c1.p, c2.p);
	int com = compare(r1 + r2, d);
	return com == 1 ? compare(d + r1, r2) + 1 : 3 - com;
	// if(c1.r < c2.r) swap(c1, c2);
	// Real d = abs(c1.p - c2.p);
	// if(compare(c1.r + c2.r, d) == -1) return 4;
	// if(eq(c1.r + c2.r, d)) return 3;
	// if(compare(c1.r - c2.r, d) == -1) return 2;
	// return int(eq(c1.r - c2.r, d));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A&lang=jp
int intersect(const Circle &c1, const Circle &c2) { return 2 - abs(2 - number_of_common_tangents(c1, c2)); }

Real distance(const Point &a, const Point &b) { return abs(a - b); }

Real distance(const Line &l, const Point &p) { return abs(p - projection(l, p)); }

Real distance(const Line &l, const Line &m) { return intersect(l, m) ? 0 : distance(l, m.a); }

Real distance(const Segment &s, const Point &p) {
	Point r = projection(s, p);
	return intersect(s, r) ? distance(r, p) : std::min(abs(s.a - p), abs(s.b - p));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
Real distance(const Segment &a, const Segment &b) {
	if(intersect(a, b)) return 0;
	return std::min({distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b)});
}

Real distance(const Line &l, const Segment &s) {
	if(intersect(l, s)) return 0;
	return std::min(distance(l, s.a), distance(l, s.b));
}

Point crosspoint(const Line &l, const Line &m) {
	Real A = cross(l.b - l.a, m.b - m.a);
	Real B = cross(l.b - l.a, l.b - m.a);
	if(eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
	return m.a + (m.b - m.a) * B / A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C
Point crosspoint(const Segment &l, const Segment &m) { return crosspoint(Line(l), Line(m)); }

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
std::pair<Point, Point> crosspoint(const Circle &c, const Line l) {
	Point pr = projection(l, c.p);
	if(eq(distance(l, c.p), c.r)) return {pr, pr};
	Vec v = (l.b - l.a) / abs(l.b - l.a) * sqrt(c.r * c.r - norm(pr - c.p));
	return make_pair(pr - v, pr + v);
	// Vec e = (l.b - l.a) / abs(l.b - l.a);
	// double base = sqrt(c.r * c.r - norm(pr - c.p));
	// return {pr - e * base, pr + e * base};
}

std::pair<Point, Point> crosspoint(const Circle &c, const Segment &l) {
	if(intersect(c, l) == 2) return crosspoint(c, Line(l.a, l.b));
	auto ret = crosspoint(c, Line(l.a, l.b));
	if(dot(l.a - ret.first, l.b - ret.first) < EPS)
		ret.second = ret.first;
	else
		ret.first = ret.second;
	return ret;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
std::pair<Point, Point> crosspoint(const Circle &c1, const Circle &c2) {
	Real d = abs(c1.p - c2.p);
	Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));  // cosine theorem
	Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
	Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
	Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
	return make_pair(p1, p2);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F
// "点 p を通る円 c の接線"の接点2つ
std::pair<Point, Point> tangent(const Circle &c1, const Point &p2) {
	return crosspoint(c1, Circle(p2, sqrt(norm(c1.p - p2) - c1.r * c1.r)));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_G
// 円 c1, c2 の共通接線
Lines tangent(Circle c1, Circle c2) {
	Lines ret;
	if(c1.r < c2.r) std::swap(c1, c2);
	Real g = norm(c1.p - c2.p);
	if(eq(g, 0)) return ret;
	Vec u = (c2.p - c1.p) / Real(sqrt(g));
	Vec v = rotate(PI * 0.5, u);
	for(int s : {-1, 1}) {
		Real h = (c1.r + s * c2.r) / sqrt(g);
		if(eq(1 - h * h, 0)) {
			ret.emplace_back(c1.p + u * c1.r, c1.p + (u + v) * c1.r);
		} else if(1 - h * h > 0) {
			Point uu = u * h, vv = v * sqrt(1 - h * h);
			ret.emplace_back(c1.p + (uu + vv) * c1.r, c2.p - (uu + vv) * c2.r * s);
			ret.emplace_back(c1.p + (uu - vv) * c1.r, c2.p - (uu - vv) * c2.r * s);
		}
	}
	return ret;
}

#pragma endregion

Segment ref_seg(const Segment &mirror, const Segment &obj) {
	return Segment(reflection(Line(mirror), obj.a), reflection(Line(mirror), obj.b));
}

R solve(int mirror_count) {
	Segments mirrors;
	Point destination;
	{
		V<pair<Point, Point>> edges;
		rep(mirror_count) {
			Point p, q;
			cin >> p >> q;
			edges.emplace_back(p, q);
		}
		Point p;
		cin >> p;
		Point q;
		cin >> q;
		destination = q - p;
		foa(t, edges) { mirrors.emplace_back(t.first - p, t.second - p); }
	}

	V<Segments> images = {mirrors};
	vi yari;

	const Point center(0, 0);

	auto is_valid = [&](Point goal, int reflect) {
		Segment path(center, goal);
		V<tuple<R, int, int>> crs;
		const R dist_goal = abs(goal);

		debug(goal);

		rep(refl, reflect + 1) {
			rep(mrid, mirror_count) {
				// debug(refl, mrid);
				if(intersect(images[refl][mrid], path)) {
					{
						auto seg = images[refl][mrid];
						debug(seg.a, seg.b);
					}
					const R dist = abs(crosspoint(images[refl][mrid], path));
					if(dist > dist_goal) continue;
					crs.emplace_back(dist, refl, mrid);

					if(yari == vi{0}) debug(dist, refl, mrid);
				}
			}
		}
		// debug("ok");
		sort(all(crs));
		int cs = crs.size();
		int phase = 0;
		rep(i, cs) {
			R dist;
			int ref, id;
			tie(dist, ref, id) = crs[i];

			if(ref != phase) {
				continue;
			}
			debug(ref, reflect);
			if(ref > 0) {
				if(yari[ref - 1] == id) continue;
			}
			if(ref < reflect) {
				if(yari[ref] == id) {
					phase++;
					continue;
				}
			}
			return false;
		}
		return phase == reflect;
	};

	R ans = INF;
	auto dfs = [&](auto dfs, Point goal, int reflect = 0) -> void {
		// debug(goal, reflect);
		const auto tmp_mirrors = images[reflect];
		// debug(goal, reflect);
		// debug(goal, reflect);
		if(is_valid(goal, reflect)) {
			debug(yari);
			chmin(ans, distance(center, goal));
			debug(ans);
		}
		// debug("ok");
		if(reflect < 5) {
			rep(nxt_mirror, mirror_count) {
				Segments nxtset;

				// debug("ok");
				foa(m, tmp_mirrors) { nxtset.push_back(ref_seg(tmp_mirrors[nxt_mirror], m)); }
				// debug("ok");

				images.push_back(nxtset);
				yari.push_back(nxt_mirror);

				dfs(dfs, reflection(Line(tmp_mirrors[nxt_mirror]), goal), reflect + 1);
				// debug("ok");

				yari.pop_back();
				images.pop_back();
			}
		}
		return;
	};

	dfs(dfs, destination);

	return ans;
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout << std::fixed << std::setprecision(15);
	srand((unsigned)time(NULL));

	int n;
	while(cin >> n && n) {
		cout << solve(n) << dl;
	}

	return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 3628
final_rank: 15

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

// template {{{
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

#define  range(i, l, r) for (i64 i = (i64)(l); i < (i64)(r); (i) += 1)
#define rrange(i, l, r) for (i64 i = (i64)(r) - 1; i >= (i64)(l); (i) -= 1)

#define  whole(f, x, ...) ([&](decltype((x)) container) { return (f)(  begin(container),  end(container), ## __VA_ARGS__); })(x)
#define rwhole(f, x, ...) ([&](decltype((x)) container) { return (f)( rbegin(container), rend(container), ## __VA_ARGS__); })(x)

#define debug(x) cerr << "(" << __LINE__ << ")" << #x << ": " << (x) << endl

constexpr i32 inf   = 1001001001;
constexpr i64 infll = 1001001001001001001ll;

constexpr i32 dx[] = {0, -1, 1, 0, -1, 1, -1, 1}; 
constexpr i32 dy[] = {-1, 0, 0, 1, -1, -1, 1, 1};

struct IoSetup { IoSetup(i32 x = 15){ cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(x); cerr << fixed << setprecision(x); } } iosetup;

template <typename T = i64> T input() { T x; cin >> x; return x; }

template <typename T> ostream &operator<<(ostream &os, vector<T> &v) { range(i, 0, v.size()) { os << v[i] << (i + 1 != (int)v.size() ? " " : ""); } return os; } 
template <typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in : v) is >> in; return is; }

template <typename T1, typename T2> ostream &operator<<(ostream &os, pair<T1, T2> p) { os << "(" << p.first << ", " << p.second << ")"; return os; }
template <typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { is >> p.first >> p.second; return is; }

template <typename T> vector<T> make_vector(size_t a, T b) { return vector<T>(a, b); }
template <typename... Ts> auto make_vector(size_t a, Ts... ts) { return vector<decltype(make_vector(ts...))>(a, make_vector(ts...)); }

template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }
// }}}

// base
namespace geometry {
  using namespace std;
  using real_number = long double;

  const real_number PI = acosl(-1);

  inline static real_number &eps() {
    static real_number EPS = 1e-10;
    return EPS;
  }

  static void set_eps(real_number EPS) {
    eps() = EPS;
  }

  inline int sign(real_number r) {
    set_eps(1e-10);
    if (r < -eps()) return -1;
    if (r > +eps()) return +1;
    return 0;
  }

  inline bool equals(real_number r1, real_number r2) {
    return sign(r1 - r2) == 0;
  }
}

// point
namespace geometry {
  using point = complex< real_number >;
  using points = vector< point >;

  istream &operator>>(istream &is, point &p) {
    real_number x, y;
    is >> x >> y;
    p = point(x, y);
    return is;
  }

  ostream &operator<<(ostream &os, const point &p) {
    return os << p.real() << " " << p.imag();
  }

  point operator*(const point &p, const real_number &k) {
    return point(p.real() * k, p.imag() * k);
  }

  point rotate(const real_number &theta, const point &p) {
    return point(cos(theta) * p.real() + sin(-theta) * p.imag(),
                 sin(theta) * p.real() + cos(-theta) * p.imag());
  }

  bool equals(const point &a, const point &b) {
    return equals(a.real(), b.real()) and equals(a.imag(), b.imag());
  }
}

// line 
namespace geometry {
  struct line {
    point a, b;

    line() = default;
    line(point a, point b) : a(a), b(b) {}
  };

  using lines = vector< line >;
}

// segment
namespace geometry {
  struct segment : line {
    segment() = default;
    using line::line;
  };

  using segments = vector< segment >;
}

// product
namespace geometry {
  real_number cross(const point &a, const point &b) {
    return a.real() * b.imag() - a.imag() * b.real();
  }

  real_number dot(const point &a, const point &b) {
    return a.real() * b.real() + a.imag() * b.imag();
  }
}

// projection
namespace geometry {
  point projection(const line &l, const point &p) {
    real_number t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
  }
}

namespace geometry {
  point reflection(const line &l, const point &p) {
    return p + (projection(l, p) - p) * 2;
  }
}

// cross point
namespace geometry {
  point cross_point_ll(const line &l1, const line &l2) {
    real_number a = cross(l1.b - l1.a, l2.b - l2.a);
    real_number b = cross(l1.b - l1.a, l1.b - l2.a);
    if (equals(a, 0) && equals(b, 0)) return l2.a;
    return l2.a + (l2.b - l2.a) * b / a;
  }
}

// ccw
namespace geometry {
  constexpr int COUNTER_CLOCKWISE = +1;
  constexpr int CLOCKWISE         = -1;
  constexpr int ONLINE_BACK       = +2; // c-a-b
  constexpr int ONLINE_FRONT      = -2; // a-b-c
  constexpr int ON_SEGMENT        =  0; // a-c-b
  int ccw(const point &a, point b, point c) {
    b = b - a, c = c - a;
    if (sign(cross(b, c)) == +1) return COUNTER_CLOCKWISE;
    if (sign(cross(b, c)) == -1) return CLOCKWISE;
    if (sign(dot(b, c)) == -1) return ONLINE_BACK;
    if (norm(b) < norm(c)) return ONLINE_FRONT;
    return ON_SEGMENT;
  }
}

// intersect
namespace geometry {
  bool is_intersect(const segment &s1, const segment &s2) {
    return ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) <= 0 &&
           ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) <= 0;
  }
}

namespace geometry {
  real_number distance_sp(const segment &s, const point &p) {
    point pr = projection(s, p);
    if (ccw(s.a, s.b, pr) == 0) return abs(pr - p);
    return min(abs(s.a - p), abs(s.b - p));
  }
}
using namespace geometry;

int n;
segments segs;
point l, t;

real_number calculate(const vector< int > &idxs) {
  if (idxs.size() == 0) {
    segment s(l, t);
    for (auto &seg : segs) {
      if (is_intersect(s, seg)) return inf;
    }

    return abs(l - t);
  }

  vector< segments > us;
  us.emplace_back(segs);

  vector< point > ts;
  ts.emplace_back(t);

  for (auto &i : idxs) {
    segments ss = us.back();
    point nt = ts.back();

    line refl = ss[i];
    for (auto &[a, b] : ss) {
      a = reflection(refl, a);
      b = reflection(refl, b);
    }
    nt = reflection(refl, nt);

    us.emplace_back(ss);
    ts.emplace_back(nt);
  }

  real_number res = abs(l - ts.back());

  segment shortest(l, ts.back());
  vector< int > uku(1, -1);
  for (auto &i : idxs) uku.emplace_back(i);
  uku.emplace_back(-1);

  range(i, 1, uku.size()) {
    if (uku[i] != -1 and not is_intersect(shortest, segs[uku[i]])) return inf;

    point nxt_a = (uku[i] == -1 ? t : cross_point_ll(shortest, segs[uku[i]]));
    segment s(shortest.a, nxt_a);
    range(j, 0, n) {
      if (j == uku[i - 1] or j == uku[i]) continue;
      if (is_intersect(s, segs[j])) return inf;
    }

    shortest.a = nxt_a;
    if (i + 1 != (int)uku.size()) shortest.b = reflection(segs[uku[i]], shortest.b);
  }

  return res;
}

real_number dfs(int depth, vector< int > &idxs) {
  real_number res = inf;

  if (depth >= 6) return res;
  range(i, 0, n) {
    if (not idxs.empty() and idxs.back() == i) continue;
    idxs.emplace_back(i);
    chmin(res, dfs(depth + 1, idxs));
    idxs.pop_back();
  }

  chmin(res, calculate(idxs));
  
  return res;
}

void solve(int n) {
  segs.clear();
  range(i, 0, n) {
    point a, b;
    cin >> a >> b;

    segs.emplace_back(a, b);
  }

  cin >> t >> l;

  vector< int > idxs;
  cout << dfs(0, idxs) << endl;
}

signed main() {
  while (cin >> n, n) {
    solve(n);
  }
}
accuracy: 1
time_ms: 100
memory_kb: 3420
final_rank: 9

code_snippet: #include<bits/stdc++.h> 
using namespace std;
using ll=long long int;
//using Int=__int128;
#define ALL(A) A.begin(),A.end()
template<typename T1,typename T2> bool chmin(T1 &a,T2 b){if(a<=b)return 0; a=b; return 1;}
template<typename T1,typename T2> bool chmax(T1 &a,T2 b){if(a>=b)return 0; a=b; return 1;}
template<typename T> constexpr int bitUP(T x,int a){return (x>>a)&1;}
//→　↓　←　↑ 
int dh[4]={0,1,0,-1}, dw[4]={1,0,-1,0};
//右上から時計回り
//int dh[8]={-1,0,1,1,1,0,-1,-1}, dw[8]={1,1,1,0,-1,-1,-1,0};
//long double EPS = 1e-6;
//long double PI = acos(-1);
//const ll INF=(1LL<<62);
const int MAX=(1<<30);
constexpr ll MOD=1000000000+7;
//constexpr ll MOD=998244353;


inline void bin101(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(20);
}

using Graph=vector<vector<int>>;

template<typename T >
struct edge {
	int to;
	T cost;
	edge()=default;
	edge(int to, T cost) : to(to), cost(cost) {}

};
template<typename T>
using WeightGraph=vector<vector<edge<T>>>;

//要素数n 初期値x
template<typename T>
inline vector<T> vmake(size_t n,T x){
	return vector<T>(n,x);
}

//a,b,c,x data[a][b][c] 初期値x
template<typename... Args>
auto vmake(size_t n,Args... args){
	auto v=vmake(args...);
	return vector<decltype(v)>(n,move(v));
}

////////////////////////////
// マクロや型
////////////////////////////

using DD=long double;

const DD EPS=1e-9;
const DD INF=1e50;
const DD PI=acosl(-1.0);
#define EQ(a,b) (abs( (a) - (b) )<EPS) //a==b
#define LS(a,b) ( (a)+EPS<(b) ) //a<b
#define GR(a,b) ( (a)>(b)+EPS ) //a>b
#define LE(a,b) ( (a)<(b)+EPS ) //a<=b
#define GE(a,b) ( (a)>(b)-EPS ) //a>=b

#define X real()
#define Y imag()


//点
using Point=complex<DD>;
istream &operator>>(istream &is, Point &p) {
  DD x,y;
  is>>x>>y;
  p=Point(x,y);
  return is;
}

//点a→点bの線分
//aとbが等しい時、色々バグるから注意!
struct Segment{
    Point a,b;
    Segment()=default;
    Segment(Point a,Point b) :a(a),b(b){}
    Segment(DD ax,DD ay,DD bx,DD by):a(ax,ay),b(bx,by){}
    Segment(DD r,Point a) :a(a),b(a+polar((DD)1.0,r)){} 
};
using Line=Segment;

//円
struct Circle{
    Point p;
    DD r;
    Circle()=default;
    Circle(Point p,DD r):p(p),r(r){}
};

using Polygon=vector<Point>;

////////////////////////////
// 基本計算
////////////////////////////

//度→ラジアン
inline DD torad(const DD deg){return deg*PI/180;}
//ラジアン→度
inline DD todeg(const DD rad){return rad*180/PI;}
//内積 |a||b|cosθ
inline DD dot(const Point &a,const Point &b){return (conj(a)*b).X;}
//外積 |a||b|sinθ
inline DD cross(const Point &a,const Point &b){return (conj(a)*b).Y;}
//ベクトルpを反時計回りにtheta(ラジアン)回転
Point rotate(const Point &p,const DD theta){return p*Point(cos(theta),sin(theta));}

//余弦定理 cos(角度abc(ラジアン))を返す
//長さの対応に注意 ab:辺abの長さ
//verify:https://codeforces.com/gym/102056/problem/F
DD cosine_formula(const DD ab,const DD bc,const DD ca){
    return (ab*ab+bc*bc-ca*ca)/(2*ab*bc);
}

inline bool xy_sort(const Point &a,const Point &b){
    if(a.X+EPS<b.X) return true;
    if(EQ(a.X,b.X) && a.Y+EPS<b.Y) return true;
    return false;
}
inline bool yx_sort(const Point &a,const Point &b){
    if(a.Y+EPS<b.Y) return true;
    if(EQ(a.Y,b.Y) && a.X+EPS<b.X) return true;
    return false;
}
namespace std{
    inline bool operator<(const Point &a,const Point &b)noexcept{
        return xy_sort(a,b);
    }
}
//DDの比較関数
//map<DD,vector<pii>,DDcom>
struct DDcom{
    bool operator()(const DD a, const DD b) const noexcept {
        return a+EPS<b;
    }
};


////////////////////////////
// 平行や直交
////////////////////////////

bool isOrthogonal(const Point &a,const Point &b){
    return EQ(dot(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isOrthogonal(const Segment &s,const Segment &t){
    return EQ(dot(s.a-s.b,t.a-t.b),0.0);
}
bool isParallel(const Point &a,const Point &b){
    return EQ(cross(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isParallel(const Segment &s,const Segment &t){
    return EQ(cross(s.a-s.b,t.a-t.b),0);
}
//線分a→bに対して点cがどの位置にあるか
//反時計回り:1　時計回り:-1 直線上(a,b,c:-2 a,c,b:0 c,a,b:2)
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
//線分a→bの端点にcがあるなら0と判定されるはず
int ccw(const Point &a,Point b,Point c){
    if(EQ(abs(b-c),0) or EQ(abs(a-c),0)) return 0;
    b-=a;c-=a;
    if(cross(b,c)>EPS) return 1;
    if(cross(b,c)<-EPS) return -1;
    if(dot(b,c)<-EPS) return 2;
    if(LS(norm(b),norm(c))) return -2;
    return 0;
}

////////////////////////////
// 射影と反射
////////////////////////////

//射影
//直線lに点pから垂線を引いたときの交点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
Point project(const Point &p,const Line &l){
    Point base=l.b-l.a;
    DD r=dot(p-l.a,base)/norm(base);
    return l.a+base*r;
}
//反射
//直線lに対して点pと対称な点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
Point reflect(const Point &p,const Line &l){
    return p+(project(p,l)-p)*(DD)2.0;
}
//反射
//直線lに対して線分sと対称な線分(直線でも使える)
//verify:
Segment reflect(const Segment &s,const Line &l){
    return Segment(reflect(s.a,l) , reflect(s.b,l));
}

////////////////////////////
// 点との距離
////////////////////////////

//点と直線の距離
DD DistPL(const Point &p,const Line &l){
    return abs(cross(l.b-l.a,p-l.a))/abs(l.b-l.a);
}
//点と線分の距離
DD DistPS(const Point &p,const Segment &s){
    if( dot(s.b-s.a,p-s.a)<0.0 ) return abs(p-s.a);
    if( dot(s.a-s.b,p-s.b)<0.0 ) return abs(p-s.b);
    return DistPL(p,s);
}

////////////////////////////
// 線分と直線
////////////////////////////

//線分a-b,c-dは交差するか?
//接する場合も交差すると判定
//接する場合は交差しないとするなら<=を<に変換
bool intersect(const Point &a,const Point &b,const Point &c,const Point &d){
    return(ccw(a,b,c)*ccw(a,b,d)<=0 && ccw(c,d,a)*ccw(c,d,b)<=0);
}
//線分s,tは交差するか？
//接する場合も交差すると判定
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B&lang=ja
//接する場合は交差しないとするならintersectの<=を<に変換
bool intersect(const Segment &s,const Segment &t){
    return intersect(s.a,s.b,t.a,t.b);
}
// 2直線の交点
// 線分の場合はintersectをしてから使う
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C&lang=ja
Point crossPoint(const Line &s,const Line &t){
    Point base=t.b-t.a;
    DD d1=cross(base,t.a-s.a);
    DD d2=cross(base,s.b-s.a);
    if(EQ(d1,0) and EQ(d2,0)) return s.a; //同じ直線
    if(EQ(d2,0)) assert(false); //交点がない
    return s.a+d1/d2*(s.b-s.a);
}
//線分と線分の距離
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D&lang=ja
DD Dist(const Segment &s,const Segment &t){
    if(intersect(s,t)) return 0.0;
    return min(min(DistPS(t.a,s),DistPS(t.b,s)),min(DistPS(s.a,t),DistPS(s.b,t)) );
}
bool issame(const Line &l,const Line &m){
    if (GR(abs(cross(m.a - l.a, l.b - l.a)),0) ) return false;
    if (GR(abs(cross(m.b - l.a, l.b - l.a)),0) ) return false;
    return true;
}

////////////////////////////
// 円
////////////////////////////
//直線lと円Cの交点
//l.aにより近い方がindexが小さい
//veirfy:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
vector<Point> crossPointLC(const Line &l,const Circle &c){
    vector<Point> ret;
    if(GR(DistPL(c.p,l),c.r)) return ret; //交点がないとき、空ベクトルを返す
    Point pr=project(c.p,l);
    Point e=(l.b-l.a)/(abs(l.b-l.a));
    DD base=sqrt(c.r*c.r-norm(pr-c.p));
    ret.push_back(pr-e*base);
    ret.push_back(pr+e*base);
    if(EQ(DistPL(c.p,l),c.r)) ret.pop_back(); //接するとき
    return ret;
}
//線分sと円cの交点
//交点がないときは空ベクトルを返す
//線分の端が交わる場合も交点とみなす
//s.aにより近い方がindexが小さい
vector<Point> crossPointSC(const Segment &s,const Circle &c){
    vector<Point> ret;
    if(DistPS(c.p,s)>c.r+EPS) return ret;
    auto koho=crossPointLC(s,c);
    for(auto p:koho){
        if(ccw(s.a,s.b,p)==0 or EQ(abs(p-s.a),0) or EQ(abs(p-s.b),0)) ret.push_back(p);
    }
    return ret;
}

//円aと円bの共通接線の数
//離れている:4 外接:3 交わる:2 内接:1 内包:0
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A
int intersect(const Circle &a,const Circle &b){
    DD d=abs(a.p-b.p);
    if(GR(d,a.r+b.r)) return 4;
    if(EQ(d,a.r+b.r)) return 3;
    if(EQ(d,abs(a.r-b.r))) return 1;
    if(LS(d,abs(a.r-b.r))) return 0;
    return 2;
}

//円aと円bの交点
//交点がないときは空ベクトルを返す
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
vector<Point> crossPoint(const Circle &a,const Circle &b){
    vector<Point> ret;
    if(GR(abs(a.p-b.p),a.r+b.r)) return ret;
    DD d=abs(a.p-b.p);
    DD s=acosl((a.r*a.r+d*d-b.r*b.r)/(2*a.r*d)); //0~π
    DD t=arg(b.p-a.p);
    if(EQ(a.r+b.r,d)) ret.push_back(a.p+polar(a.r,t));
    else ret.push_back(a.p+polar(a.r,t+s)),ret.push_back(a.p+polar(a.r,t-s));
    return ret;
}

//点pから円cに接線を引いたときの接点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F&lang=ja
vector<Point> TanLine(const Point &p,const Circle &c){
    vector<Point> ret;
    DD d=abs(p-c.p);
    if(LS(d,c.r)) return ret; //pがcの内部にある場合
    if(EQ(d,c.r)){
        ret.push_back(p);
        return ret; //円の線上にある場合
    } 
    return crossPoint(c,Circle(p,sqrt(d*d-c.r*c.r)));
}

//円a,bの共通接線
//https://www.slideshare.net/kujira16/ss-35861169
//Line.aは円aと接線の交点
//(接線と円bの交点)と(接線と円aの交点)が違う場合はLine.bは(接線と円bの交点)
//一致する場合は円aの中心からLine.aに向かうベクトルを反時計回りに90度回転したものを
//Line.aに足したもの
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_G
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2201
vector<Line> TanLine(const Circle &a,const Circle &b){
    DD d=abs(a.p-b.p);
    vector<Line> ret;
    //外接線
    if(intersect(a,b)>=2){
        if(EQ(a.r,b.r)){
            Point up=polar(a.r,arg(b.p-a.p)+PI/2);
            ret.emplace_back(a.p+up,b.p+up);
            ret.emplace_back(a.p-up,b.p-up);
        }else{
            Point q=(a.p*b.r-b.p*a.r)/(b.r-a.r);
            auto as=TanLine(q,a);
            auto bs=TanLine(q,b);
            assert(as.size()==2 and bs.size()==2);
            for(int i=0;i<2;i++){
                ret.emplace_back(as[i],bs[i]);
            }
        }
    }else if(intersect(a,b)==1){ //内接する場合
        Point dir;
        if(a.r>b.r) dir=polar(a.r,arg(b.p-a.p));
        else dir=polar(a.r,arg(a.p-b.p));
        ret.emplace_back(a.p+dir,a.p+dir+rotate(dir,PI/2));
    }
    //内接線
    if(GR(abs(a.p-b.p),a.r+b.r)){ //円が離れている場合
        Point q=a.p+(b.p-a.p)*a.r/(a.r+b.r);
        auto as=TanLine(q,a);
        auto bs=TanLine(q,b);
        assert(as.size()==2 and bs.size()==2);
        for(int i=0;i<2;i++){
            ret.emplace_back(as[i],bs[i]);
        }
    }else if(EQ(d,a.r+b.r)){ //円が接している場合
        Point dir=polar(a.r,arg(b.p-a.p));
        ret.emplace_back(a.p+dir,a.p+dir+rotate(dir,PI/2));
    }
    return ret;
}
//２つの円の共通部分の面積
//参考: https://tjkendev.github.io/procon-library/python/geometry/circles_intersection_area.html
//verify: https://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=6005736#1
DD Area(const Circle &c1,const Circle &c2){
    DD cd=abs(c1.p-c2.p);
    if(LE(c1.r+c2.r,cd)) return 0; //円が離れている

    if(LE(cd,abs(c1.r-c2.r))) //片方の円が他方を包んでいる
        return min(c1.r,c2.r)*min(c1.r,c2.r)*PI;

    DD theta1=acosl(cosine_formula(c1.r,cd,c2.r));
    DD theta2=acosl(cosine_formula(c2.r,cd,c1.r));

    return c1.r*c1.r*theta1+c2.r*c2.r*theta2-c1.r*cd*sin(theta1);
}


////////////////////////////
// 三角形
////////////////////////////

//ヘロンの公式　三角形の面積を返す
//三角形が成立するか(平行ではないか)を忘れずに
DD Heron(const DD ad,const DD bd,const DD cd){
    DD s=(ad+bd+cd)/2;
    return sqrt(s*(s-ad)*(s-bd)*(s-cd));
}
//三角形の外接円
//isParallel()を使って三角形が成立するか(平行ではないか)を忘れずに
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_C
Circle CircumscribedCircle(const Point &a,const Point &b,const Point &c){
    Point bc=(b+c)/(DD)2.0;
    Line aa(bc,bc+rotate(c-b,PI/2));
    Point ab=(a+b)/(DD)2.0;
    Line cc(ab,ab+rotate(b-a,PI/2));
    Point p=crossPoint(aa,cc);
    return Circle(p,abs(a-p));
}
//三角形の内接円
//isParallel()を使って三角形が成立するか(平行ではないか)を忘れずに
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_B
Circle InCircle(const Point &a,const Point &b,const Point &c){
    Line aa(a,a+polar((DD)1.0,(arg(b-a)+arg(c-a))/(DD)2.0));
    Line bb(b,b+polar((DD)1.0,(arg(a-b)+arg(c-b))/(DD)2.0));
    Point p=crossPoint(aa,bb);
    return Circle(p,DistPL(p,Line(a,b)));
}

////////////////////////////
// 多角形
////////////////////////////

//点pが多角形gに対してどの位置にあるか
//中:2 辺上:1 外:0
//凸多角形である必要ない
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_C
int contains(const Point &p,const vector<Point> &g){
    int n=(int)g.size();
    int x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(EQ(cross(a,b),0) && dot(a,b)<EPS) return 1;
        if(a.Y>b.Y) swap(a,b);
        if(a.Y<EPS && EPS<b.Y && cross(a,b)>EPS) x=!x;
    }
    return (x?2:0);
}
//凸性判定
//多角形gは凸か？
//gは反時計回りでも時計回りでもいい
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_B
bool isConvex(const vector<Point> &g){
    int n=(int)g.size();
    if(n<=3) return true;
    int flag=0;
    int t;
    for(int i=0;i<n;i++){
        Point a(g[(i+1)%n]-g[i]),b(g[(i+2)%n]-g[i]);
        if(cross(a,b)>EPS) t=1;
        else if(cross(a,b)<-EPS) t=-1;
        else continue;
        if(flag==-t) return false;
        flag=t;
    }
    return true;
}

//凸包　アンドリューのアルゴリズム
//O(NlogN)
//反時計回りの多角形を返す
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_A
vector<Point> ConvexHull(vector<Point> s,const bool on_edge){
    int j;
    if(on_edge) j=-1;
    else j=1;
    int sz=(int)s.size();
    if(sz<3) return s;
    sort(s.begin(),s.end(),yx_sort);

    int n=0;
    vector<Point> res(2*sz);
    for(int i=0;i<sz;i++){
        while(n>=2 && cross(res[n-1]-res[n-2],s[i]-res[n-2])<EPS*j){
            n--;
        }
        res[n]=s[i];
        n++;
    }
    int t=n+1;
    for(int i=sz-2;i>=0;i--){
        while(n>=t && cross(res[n-1]-res[n-2],s[i]-res[n-2])<EPS*j){
            n--;
        }
        res[n]=s[i];
        n++;
    }
    res.resize(n-1);
    return res;
}

//多角形g(凸でなくてもいい)の符号付き面積
//反時計回りの多角形なら正の値を返す　時計回りなら負
//O(N)
//https://imagingsolution.net/math/calc_n_point_area/
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_A
DD Area(const vector<Point> &g){
    DD ret=0.0;
    int n=(int)g.size();
    for(int i=0;i<n;i++){
        ret+=cross(g[i],g[(i+1)%n]);
    }
    return ret/2.0;
}

//凸多角形gを直線lで切断
//直線の左側(向きを考慮)にできる凸多角形を返す
//多角形gが反時計回りならば、反時計回りで返す(時計回りなら時計回り)
//直線上の頂点を含む線分の交点は含めてない
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
vector<Point> ConvexCut(const vector<Point> &g,const Line &l){
    vector<Point> ret;
    int gz=(int)g.size();
    for(int i=0;i<gz;i++){
        Point now=g[i],next=g[(i+1)%gz];
        if(ccw(l.a,l.b,now)!=-1) ret.push_back(now);
        if(EQ(DistPL(now,l),0) or EQ(DistPL(next,l),0)) continue;
        if(ccw(l.a,l.b,now)*ccw(l.a,l.b,next)<0){
            ret.push_back(crossPoint(Line(now,next),l));
        }
    }
    return ret;
}
//部品
inline DD calc(const Point &a,const Point &b,const DD &r,const bool triangle){
    if(triangle) return cross(a,b);
    else return r*r*arg(b/a);
}
//部品
DD calcArea(const DD &r,const Point &a,const Point &b){
    if(EQ(abs(a-b),0)) return 0;
    bool ina=(abs(a)<r+EPS);
    bool inb=(abs(b)<r+EPS);
    if(ina && inb) return cross(a,b);
    auto cr=crossPointSC(Segment(a,b),Circle(Point(0,0),r));
    if(cr.empty()) return calc(a,b,r,false);
    auto s=cr[0],t=cr.back();
    return calc(s,t,r,true)+calc(a,s,r,ina)+calc(t,b,r,inb);
}
//円と多角形の共通部分の面積
//多角形が反時計回りならば正の値を返す
//凸多角形でなくても大丈夫
//http://drken1215.hatenablog.com/entry/2020/02/02/091000
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_H&lang=ja
DD Area(const Circle &c,const vector<Point> &g){
    DD ret=0.0;
    int gz=g.size();
    if(gz<=2) return ret;
    for(int i=0;i<gz;i++){
        Point a=g[i]-c.p,b=g[(i+1)%gz]-c.p;
        ret+=calcArea(c.r,g[i]-c.p,g[(i+1)%gz]-c.p);
    }
    return ret/2.0;
}

//点と多角形の距離
//点が多角形の中にあるなら0
DD Dist(const Point &a,const vector<Point> &b){
	if(b.size()==1) return abs(a-b[0]);
	if(contains(a,b)>=1) return 0.0L;
	DD ret=INF;
	for(int i=0;i<b.size();i++){
		chmin(ret,DistPS(a,Segment(b[i],b[(i+1)%b.size()])));
	}
	return ret;
}

//多角形と多角形の距離
//どちらかが内側に入っていたら0
//全ての線分の組み合わせの距離を求めて、その最小が答え
//O(size(a)*size(b))
//sizeが1の時は点との距離になる
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2827
DD Dist(const vector<Point> &a,const vector<Point> &b){
	DD ret=INF;
	if(a.size()==1) return Dist(a[0],b);
	if(b.size()==1) return Dist(b[0],a);

	if(contains(a[0],b)>=1) return 0.0L;
	if(contains(b[0],a)>=1) return 0.0L;

	for(int i=0;i<a.size();i++){
		for(int j=0;j<b.size();j++){
			Segment sa(a[i],a[(i+1)%a.size()]);
			Segment sb(b[j],b[(j+1)%b.size()]);
			chmin(ret,Dist(sa,sb));
		}
	}
	return ret;
}

////////////////////////////
// 最近(遠)点間距離
////////////////////////////
//部品
DD RecClosetPair(const vector<Point>::iterator it,const int n){
    if(n<=1) return INF;
    int m=n/2;
    DD x=it[m].X;
    DD d=min(RecClosetPair(it,m),RecClosetPair(it+m,n-m));
    inplace_merge(it,it+m,it+n,yx_sort);
    vector<Point> v;
    for(int i=0;i<n;i++){
        if(abs(it[i].X-x)>=d) continue;
        for(int j=0;j<v.size();j++){
            DD dy=it[i].Y-v[(int)v.size()-1-j].Y;
            if(dy>=d) break;
            DD dx=it[i].X-v[(int)v.size()-1-j].X;
            d=min(d,sqrt(dx*dx+dy*dy));
        }
        v.push_back(it[i]);
    }
    return d;
}
//最近点対の距離
//点が1つのときINFを返す
//O(NlogN)
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_5_A
DD ClosetPair(vector<Point> g){
    sort(g.begin(),g.end(),xy_sort);
    return RecClosetPair(g.begin(),g.size());
}

//最遠頂点間
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_B
DD Diameter(vector<Point> g){
    g=ConvexHull(g,1);
    int gz=g.size();
    int m=0,M=0;
    for(int i=1;i<gz;i++){
        if(g[i].Y<g[m].Y) m=i;
        if(g[i].Y>g[M].Y) M=i;
    }
    DD ret=0;
    int sm=m,sM=M;
    while(m!=sM || M!=sm){
        ret=max(ret,norm(g[m]-g[M]));
        if(cross(g[(m+1)%gz]-g[m],g[(M+1)%gz]-g[M])<0) m=(m+1)%gz;
        else M=(M+1)%gz;
    }
    return sqrt(ret);
}
//動的凸包
//辺上にある点は含めない
//verify:https://atcoder.jp/contests/geocon2013/tasks/geocon2013_c
struct DynamicConvex{
	set<Point> up,down;
	DynamicConvex(){}
 
	bool isContain(set<Point> &pol,Point p){
		if(pol.size()==0) return false;
		if(pol.size()==1){
			Point q=*begin(pol);
			return EQ(q.X,p.X) and GE(q.Y,p.Y);
		}
		assert(pol.size()>=2);
        auto left=begin(pol);
        auto right=(--end(pol));
        if(LS(p.X,left->X) or GR(p.X,right->X)) return false;
        
        
        auto q1=pol.upper_bound(Point(p.X,INF));
        if(q1==end(pol)){
            return GE(right->Y,p.Y);
        }
        auto q2=q1--; //q1が範囲外になるのは最初に弾いてる
        return GE(cross(p-*q1,*q2-*q1),0.0);
	}
    bool isContain(Point p){
        if(not isContain(up,p)) return false;
        if(not isContain(down,Point(p.X,-p.Y))) return false;
        return true;
    }
 
	void add(set<Point> &pol,Point p){
		if(pol.size()==0){
			pol.insert(p);
			return;
		}
		if(pol.size()==1){
            Point q=*begin(pol);
			if(EQ(q.X,p.X)){
                pol.clear();
                pol.insert(max(p,q));
			}else{
				pol.insert(p);
			}
            return;
		}
        assert(pol.size()>=2);
        if(isContain(pol,p)) return;
        //left
        auto q1=pol.upper_bound(Point(p.X,INF));
        if(q1!=begin(pol)){
            q1--;
            while(pol.size()>=1 and q1!=begin(pol)){
                auto q2=q1--;
                if(GR(cross(*q2-p,*q1-p),0)) break;
                pol.erase(q2);
            }
        }
        //right
        q1=pol.lower_bound(Point(p.X,-INF));
        if(q1!=end(pol)){
            while(pol.size()>1 and q1!=--end(pol)){
                auto q2=q1++;
                if(GR(cross(*q1-p,*q2-p),0.0)) break;
                pol.erase(q2);
            }
        }
        pol.insert(p);
	}
 
	void add(Point p){
		add(up,p);
		add(down,Point(p.X,-p.Y)); //upと同じように処理をしたいから
	}
};

//垂直二等分線
//p-↑-q こんなかんじ
//voronoiで使う
Line bisector(const Point &p, const Point &q) {
    Point c=(p+q)/DD(2.0);
    Point v=rotate(q-p,PI/2);
    v/=abs(v);
    return Line(c-v,c+v);
}

//ボロノイ図
//pol:全体 ps:点の集合 id:中心となる点の添字 pp:中心となる点
//計算量: pol.size()*ps.size()
//verify: https://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=6005648#1
vector<Point> voronoi(Polygon pol,const vector<Point> &ps,int id=-1,const Point pp=Point()){
    Point p;
    if(id!=-1) p=ps[id];
    else p=pp;
    for(size_t i=0;i<ps.size();i++){
        if(i==id) continue;
        Line l=bisector(p,ps[i]);
        pol=ConvexCut(pol,l);
    }
    return pol;
}
int N;
vector<Segment> mirror;
Point start,goal;
DD ans=INF;
vector<int> v;

void dfs(int depth){
    if(depth<5){
        for(int i=0;i<N;i++){
            v.push_back(i);
            dfs(depth+1);
            if(v.back()==-1) v.pop_back();
            v.pop_back();
        }
    }
    //試す
//goalを線対称に移動
    auto g=goal;
    auto m=mirror;
    for(int i=0;i<v.size();i++){
        g=reflect(g,m[v[i]]);
        for(int j=0;j<N;j++){
            if(j==v[i]) continue;
            m[j]=reflect(m[j],m[v[i]]);
        }
    }
    Segment s(start,g);
    DD dis=abs(s.a-s.b);
    if(dis>ans) return;
    v.push_back(-1);
    m=mirror;
    if(v.size()==3 and v[0]==0 and v[1]==1 ){
        //cerr<<-1<<endl;
    }
    if(v.size()==1){
        //cerr<<-1<<endl;
    }
    for(size_t i=0;i<v.size();i++){
        DD t=INF;
        if(v[i]==-1) t=abs(s.a-s.b);
        int id=-1;
        for(size_t j=0;j<N;j++){
            if(not intersect(s,m[j])) continue;
            if(i and v[i-1]==j) continue;
            auto x=crossPoint(s,m[j]);
            if(chmin(t,abs(s.a-x))){
                id=j;
            }
        }
        if(id!=v[i]) return;
        if(id==-1){
            ans=dis;
            return;
        }
        s.a=crossPoint(s,m[id]);
        for(size_t j=0;j<N;j++){
            if(id==j) continue;
            m[j]=reflect(m[j],m[id]);
        }
    }
}

void solve(){
while(true){
    ans=INF;
    cin>>N;
    if(N==0) return;
    mirror.resize(N);

    for(int i=0;i<N;i++){
        cin>>mirror[i].a>>mirror[i].b;
    }
    cin>>start>>goal;
    dfs(0);
    if(v.size())v.pop_back();
    cout<<ans<<endl;
}
}

int main(){
    bin101();
    int T=1;
    //cin>>T;
    while(T--) solve();
}
accuracy: 1
time_ms: 300
memory_kb: 3544
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=15,INF=1<<29;

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-8;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

bool intersect(Point p1,Point p2,Point p3,Point p4){
    return(ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0&&ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}

bool intersect(Segment s1,Segment s2){
    return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

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

double getDistanceSP(Segment s,Point 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);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

double ans=INF;
int N;
Point s,t;
vector<Segment> S;
vector<int> use;

void solve(){
    if(si(use)==6) return;
    vector<Segment> now=S;
    Point g=t;
    for(int a:use){
        Line l=now[a];
        for(int i=0;i<si(now);i++){
            now[i].p1=reflect(l,now[i].p1);
            now[i].p2=reflect(l,now[i].p2);
        }
        g=reflect(l,g);
    }
    Segment keiro={s,g};
    now=S;
    g=t;
    Point last=s;
    bool ok=true;
    for(int i=0;i<si(use);i++){
        int a=use[i];
        if(!intersect(Segment{last,keiro.p2},now[a])){
            ok=false;
            break;
        }
        Point M=getCrossPointS(Segment{last,keiro.p2},now[a]);
        for(int j=0;j<N;j++){
            if(j==a) continue;
            if(i&&j==use[i-1]) continue;
            if(intersect(Segment{last,M},now[j])){
                ok=false;
                break;
            }
        }
        if(!ok) break;
        Line l=now[a];
        for(int j=0;j<si(now);j++){
            now[j].p1=reflect(l,now[j].p1);
            now[j].p2=reflect(l,now[j].p2);
        }
        g=reflect(l,g);
        last=M;
    }
    for(int j=0;j<N;j++){
        if(si(use)&&j==use.back()) continue;
        if(intersect(Segment{last,keiro.p2},now[j])){
            ok=false;
            break;
        }
    }
    if(ok) chmin(ans,getDistance(keiro.p1,keiro.p2));
    
    for(int i=0;i<N;i++){
        if(si(use)&&use.back()==i) continue;
        use.push_back(i);
        solve();
        use.pop_back();
    }
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        cin>>N;
        if(N==0) break;
        ans=INF;
        S.resize(N);
        for(int i=0;i<N;i++) cin>>S[i].p1.x>>S[i].p1.y>>S[i].p2.x>>S[i].p2.y;
        cin>>s.x>>s.y>>t.x>>t.y;
        solve();
        cout<<fixed<<setprecision(25)<<ans<<endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3512
final_rank: 8

code_snippet: #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#include<deque>
#include<iomanip>
#include<tuple>
#include<cassert>
#include<set>
#include<complex>
#include<numeric>
#include<functional>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long int LL;
typedef pair<int,int> P;
typedef pair<LL,LL> LP;
const int INF=1<<30;
const LL MAX=1e9+7;

void array_show(int *array,int array_n,char middle=' '){
	for(int i=0;i<array_n;i++)printf("%d%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(LL *array,int array_n,char middle=' '){
	for(int i=0;i<array_n;i++)printf("%lld%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(vector<int> &vec_s,int vec_n=-1,char middle=' '){
	if(vec_n==-1)vec_n=vec_s.size();
	for(int i=0;i<vec_n;i++)printf("%d%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
void array_show(vector<LL> &vec_s,int vec_n=-1,char middle=' '){
	if(vec_n==-1)vec_n=vec_s.size();
	for(int i=0;i<vec_n;i++)printf("%lld%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
template<typename T> ostream& operator<<(ostream& os,const vector<T>& v1){
	int n=v1.size();
	for(int i=0;i<n;i++){
		if(i)os<<" ";
		os<<v1[i];
	}
	return os;
}
template<typename T1,typename T2> ostream& operator<<(ostream& os,const pair<T1,T2>& p){
	os<<p.first<<" "<<p.second;
	return os;
}
template<typename T> istream& operator>>(istream& is,vector<T>& v1){
	int n=v1.size();
	for(int i=0;i<n;i++)is>>v1[i];
	return is;
}
template<typename T1,typename T2> istream& operator>>(istream& is,pair<T1,T2>& p){
	is>>p.first>>p.second;
	return is;
}

namespace geometory{
	const double eps=1e-9;
}

template<typename T> T cross_product(complex<T> ca,complex<T> cb){
    return (conj(ca)*cb).imag();
}

template<typename T> T inner_product(complex<T> ca,complex<T> cb){
    return (conj(ca)*cb).real();
}

template<typename T> class Line{

	int sign(T a)const{
		if(abs(a)<geometory::eps)return 0;
		if(a<0)return -1;
		else return 1;
	}

public:
    complex<T> st,en;
	bool segment=true;

	Line(){}
	Line(complex<T> a,complex<T> b):st(a),en(b){}
	Line(T x1,T y1,T x2,T y2){
		st=complex<T>(x1,y1);
		en=complex<T>(x2,y2);
	}
	Line(pair<T,T> p1,pair<T,T> p2){
		st=complex<T>(p1.first,p1.second);
		en=complex<T>(p2.first,p2.second);
	}

    T length()const{
        return abs(en-st);
    }

	complex<T> direction()const{
		complex<T> a=en-st;
		return a/abs(a);
	}

	complex<T> mirror(const complex<T> pos)const{
		complex<T> dir=direction();
		complex<T> a=pos-st;
		complex<T> b=2*inner_product(dir,a)*dir;
		return st+b-a;
	}

	Line mirror(const Line& line)const{
		return Line(mirror(line.st),mirror(line.en));
	}

	int is_parallel(const Line& line)const{
		//0: not parallel
		//1: parallel without direction
		//2: parallel with direction
		complex<T> c1=en-st,c2=line.en-line.st;
		if(abs(cross_product(c1,c2))>abs(c1)*abs(c2)*geometory::eps)return 0;
		if(inner_product(c1,c2)>0)return 2;
		else return 1;
	}

	T distance(const complex<T>& point)const{
		complex<T> cl=en-st;
		T a=cl.imag(),b=-cl.real();
		T c=-(a*st.real()+b*st.imag());
		T d=abs(a*point.real()+b*point.imag()+c)/abs(cl);
		if(!segment)return d;
		return min({abs(point-st),abs(point-en),d});
	}

	bool in(const complex<T>& point)const{
		return distance(point)<geometory::eps;
	}

	bool different_side(const complex<T>& p1,const complex<T>& p2)const{
		return sign(cross_product(en-st,p1-st))*sign(cross_product(en-st,p2-st))==-1;
	}
	bool different_side(const Line& line)const{
		return different_side(line.st,line.en);
	}

	int is_cross(const Line& line)const{
		//0: not cross
		//1: cross outside
		//2: cross end point
		//3: cross inside
		if(is_parallel(line))return 0;
		if(in(line.st) || in(line.en))return 2;
		if(line.in(st) || line.in(en))return 2;
		if(different_side(line) && line.different_side(st,en)){
			return 3;
		}
		return 1;
	}

	T distance(const Line& line)const{
		if(is_cross(line)>=2)return 0;//want to change when use straight line
		if(!line.segment)return min(line.distance(st),line.distance(en));
		return min(distance(line.st),distance(line.en));
	}

	complex<T> cross_point(const Line& line)const{
		assert(!is_parallel(line));
		complex<T> d=direction();
		T a=cross_product(d,line.st-st)/cross_product(d,line.en-line.st);
		return line.st-(line.en-line.st)*a;
	}
};

namespace sol{
	int n,m;

	void solve(){
		const int N=6;
		int i,j,k;
		int a,b,c,d;
		int sx,sy,gx,gy;
		double da,db;
		complex<double> p1,p2,p3,p4;
		vector<Line<double>> vl;
		vector<int> vi(N);
		while(cin>>n){
			if(n==0)return;
			vl.clear();
			for(i=0;i<n;i++){
				cin>>a>>b>>c>>d;
				vl.push_back(Line<double>(a,b,c,d));
			}
			cin>>sx>>sy>>gx>>gy;
			complex<double> sp(sx,sy),gp(gx,gy);
			double s=1e9;
			for(vi.assign(N,-1);;vi[0]++){
				for(i=0;i<N-1;i++){
					if(vi[i]==n)vi[i]=-1,vi[i+1]++;
				}
				if(vi.back()==n)break;
				int sz=N;
				for(i=0;i<N;i++){
					if(sz==N && vi[i]==-1)sz=i;
					if(sz!=N && vi[i]!=-1)break;
					if(i && vi[i-1]==vi[i] && vi[i]!=-1)break;
				}
				if(i<N)continue;
				p1=gp;
				for(i=sz-1;i>=0;i--){
					p1=vl[vi[i]].mirror(p1);
				}
				p2=sp;
				Line l1(p2,p1);
				da=abs(p2-p1);
				for(i=0;i<sz;i++){
					a=vi[i];
					if(l1.is_cross(vl[a])!=3)break;
					p3=l1.cross_point(vl[a]);
					for(j=0;j<n;j++){
						if(a==j)continue;
						if(l1.is_cross(vl[j])!=3)continue;
						p4=l1.cross_point(vl[j]);
						if(abs(p2-p4)<abs(p2-p3))break;
					}
					if(j<n)break;
					p1=vl[a].mirror(p1);
					l1=Line(p3,p1);
					p2=p3;
				}
				if(i<sz)continue;
				for(i=0;i<n;i++){
					if(l1.is_cross(vl[i])==3)break;
				}
				if(i<n)continue;
				s=min(s,da);
			}
			cout<<fixed<<setprecision(10)<<s<<endl;
		}
	}
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
	sol::solve();
}
accuracy: 1
time_ms: 50
memory_kb: 3580
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double INF = 10000;
const double EPS = 0.00001;
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator +(point P){
    return point(x + P.x, y + P.y);
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
  point operator *(double k){
    return point(x * k, y * k);
  }
  point operator /(double k){
    return point(x / k, y / k);
  }
};
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dist(point P, point Q){
  return abs(Q - P);
}
point rotate90(point P){
  return point(-P.y, P.x);
}
double dot(point P, point Q){
  return P.x * Q.x + P.y * Q.y;
}
double cross(point P, point Q){
  return P.x * Q.y - P.y * Q.x;
}
struct line{
  point A, B;
  line(){
  }
  line(point A, point B): A(A), B(B){
  }
};
point vec(line L){
  return L.B - L.A;
}
point projection(point P, line L){
  return L.A + vec(L) / abs(vec(L)) * dot(P - L.A, vec(L)) / abs(vec(L));
}
point reflection(point P, line L){
  point H = projection(P, L);
  return H * 2 - P;
}
bool on_segment(point P, line L){
  return dot(P - L.A, vec(L)) > -EPS && dot(P - L.B, vec(L)) < EPS;
}
bool is_parallel(line L1, line L2){
  return abs(cross(vec(L1), vec(L2))) <= EPS;
}
point line_intersection(line L1, line L2){
  return L1.A + vec(L1) * cross(L2.A - L1.A, vec(L2)) / cross(vec(L1), vec(L2));
}
void dfs(vector<vector<int>> &A, vector<int> &c, int n){
  A.push_back(c);
  if (c.size() < 5){
    for (int i = 0; i < n; i++){
      c.push_back(i);
      dfs(A, c, n);
      c.pop_back();
    }
  }
}
int main(){
  cout << fixed << setprecision(20);
  while (true){
    int n;
    cin >> n;
    if (n == 0){
      break;
    }
    vector<line> L(n);
    for (int i = 0; i < n; i++){
      cin >> L[i].A.x >> L[i].A.y >> L[i].B.x >> L[i].B.y;
    }
    point T, S;
    cin >> T.x >> T.y >> S.x >> S.y;
    vector<vector<int>> A;
    vector<int> c;
    dfs(A, c, n);
    int cnt = A.size();
    double ans = INF;
    for (int i = 0; i < cnt; i++){
      int sz = A[i].size();
      point T2 = T;
      for (int j = sz - 1; j >= 0; j--){
        T2 = reflection(T2, L[A[i][j]]);
      }
      if (dist(S, T2) > EPS){
        point P = S, Q = T2;
        bool ok = true;
        for (int j = 0; j <= sz; j++){
          line C(P, Q);
          vector<double> next(n, INF);
          for (int k = 0; k < n; k++){
            if (!is_parallel(C, L[k])){
              point X = line_intersection(C, L[k]);
              if (on_segment(X, L[k])){
                if (dot(Q - P, X - P) > EPS){
                  next[k] = dist(P, X);
                }
              }
            }
          }
          if (j < sz){
            if (next[A[i][j]] == INF){
              ok = false;
            }
            for (int k = 0; k < n; k++){
              if (next[k] < next[A[i][j]] - EPS){
                ok = false;
              }
            }
            if (!ok){
              break;
            }
            point P2 = line_intersection(C, L[A[i][j]]);
            line M(P2, P2 + rotate90(vec(L[A[i][j]])));
            Q = reflection(P, M);
            P = P2;
          } else {
            double d = dist(P, T);
            for (int k = 0; k < n; k++){
              if (next[k] < d){
                ok = false;
              }
            }
            if (dot(T - P, Q - P) < -EPS){
              ok = false;
            }
          }
        }
        if (ok){
          ans = min(ans, dist(S, T2));
        }
      }
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 20
memory_kb: 3308
final_rank: 4

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}

//点を直線で反転
Point rev_lp(Line l, Point p) {
	Point h = proj(l, p);
	return h + h - p;
}
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

int n;
void solve() {
	vector<Line> l(n);
	rep(i, n) {
		int a, b, c, d; cin >> a >> b >> c >> d;
		l[i] = { {(ld)a,(ld)b},{(ld)c,(ld)d} };
	}
	Point s, g;
	int x, y; cin >> x >> y;
	s = { (ld)x,(ld)y };
	cin >> x >> y;
	g = { (ld)x,(ld)y };

	vector<Line> cur = l;
	vector<int> ms;

	vector<int> ad(7);
	rep1(i, 6) {
		ad[i] = ad[i - 1] + n - 1;
		if (i == 1)ad[i]++;
	}
	ld ans = INF;
	function<void(int)> dfs = [&](int depth) {
		if (depth == 6)return;
		//next depth
		int len = n - 1;
		if (depth == 0)len++;
		rep(i, len) {
			Line b = cur[ad[depth] + i];
			rep(j, len)if (i != j) {
				Line nl = cur[ad[depth] + j];
				nl.a = rev_lp(b, nl.a);
				nl.b = rev_lp(b, nl.b);
				cur.push_back(nl);
			}
			if (depth > 0) {
				Line ex = cur[ad[depth - 1] + ms.back()];
				ex.a = rev_lp(b, ex.a);
				ex.b = rev_lp(b, ex.b);
				cur.push_back(ex);
			}
			ms.push_back(i);
			Point memo = g;
			g = rev_lp(b, g);
			dfs(depth + 1);
			ms.pop_back();
			rep(j, n - 1)cur.pop_back();
			g = memo;
		}

		// okかどうか
		Line ml = { s,g };
		vector<Point> cs;
		cs.push_back(s);
		bool valid = true;
		rep(i, ms.size()) {
			Line l = cur[ad[i] + ms[i]];
			if (!isis_ss(l, ml)) {
				valid = false; break;
			}
			cs.push_back(is_ll(l, ml));
		}
		if (!valid)return;
		cs.push_back(g);
		rep(i, cs.size() - 1) {
			Line ml = { cs[i],cs[i + 1] };
			int len = n; if (i > 0)len--;
			rep(j, len) {
				if (i < ms.size() && j == ms[i])continue;
				Line tl = cur[ad[i] + j];
				if (isis_ss(ml, tl)) {
					valid = false; break;
				}
			}
		}
		if (valid) {
			ld dist = abs(g - s);
			ld distsum = 0;
			rep(i, cs.size() - 1) {
				distsum += abs(cs[i] - cs[i + 1]);
			}
			if (abs(dist - distsum) > eps)return;
			ans = min(ans, dist);
			//cout << dist << "\n";
		}
	};
	dfs(0);
	cout << ans << "\n";

}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//expr();
	//int t; cin >> t;rep(i,t)
	while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3540
final_rank: 10

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

#define REP(i,n) for(int i = 0;i < (n);i++)
#define FOR(i,m,n) for(int i = (m);i<(n);i++)
#define REPR(i,n) for(int i = (n)-1;i>=0;i--)
#define all(x) (x).begin(),(x).end()
template <typename T1, typename T2> inline void chmin(T1 & a, T2 b) { if (a > b) a = b; }
template <typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }


//#define TEST

#ifdef TEST
void debug_out(){cerr<<endl;}
template<typename Head,typename... Tail>
void debug_out(Head H,Tail... T){
    cerr<< " "<<(H);
    debug_out(T...);
}
#define DEBUG(...) cerr<<"["<<#__VA_ARGS__<<"]:",debug_out(__VA_ARGS__)
#else
#define DEBUG(...) 42
#endif


const double PI = acos(-1);
const double EPS = 1e-8;
const double INF = 1e5;
typedef complex<double> point;

point operator*(const point &p, const double &d) {
    return point(real(p) * d, imag(p) * d);
}
namespace std {
    bool operator<(const point &a, const point &b) {
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
    }
}  // namespace std

//直線or線分
struct Line : public vector<point> {
    int id;
    Line(const point &a, const point &b,int id):id(id) {
        push_back(a);
        push_back(b);
    }
    Line(const point &a,const point &b){
        push_back(a);
        push_back(b);
        id = -1;
    }
    Line()=default;
};
typedef vector<Line> Lines;

point direction(const point &p) {  //同じ向きの単位ベクトル
    return p / abs(p);
}
point orthogonal(const point &p) {  //法線ベクトル
    return point(-imag(p), real(p));
}
double cross(const point &a, const point &b) {
    return real(a) * imag(b) - imag(a) * real(b);
}
double dot(const point &a, const point &b) {
    return real(a) * real(b) + imag(a) * imag(b);
}
int ccw(point a, point b, point c) {
    b = b - a;
    c = c - a;
    if (cross(b, c) > EPS) return +1;   // counter clockwise
    if (cross(b, c) < -EPS) return -1;  // clockwise
    if (dot(b, c) < -EPS) return +2;    // c--a--b on line
    if (norm(b) < norm(c)) return -2;   // a--b--c on line
    return 0;
}

//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
    return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS ||  // non-parallel
           abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS;    // same line
}
bool intersectLS(const Line &l, const Line &s) {
    return cross(l[1] - l[0], s[0] - l[0]) *  // s[0] is left of l
               cross(l[1] - l[0], s[1] - l[0]) <
           EPS;  // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
    return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
    if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS) return false;
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}

bool intersectSP(const Line &s, const point &p) {
    // verified on 2020/04/03
    // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}
bool isOnSegment(const Line &s, const Line &t) {
    if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) ||
        intersectSP(t, s[1]))
        return true;
    else
        return false;
}
bool isSamePoint(const point &p1, const point &p2) { return abs(p1 - p2) < EPS; }
bool connectSS(const Line &s, const Line &t) {
    REP(i, 2) REP(j, 2) {
        if (s[i] == t[j]) return true;
    }
    return false;
}
bool intersectSS(const Line &s, const Line &t) {
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
           ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}
//端点が線分上に乗っている場合はfalseにする
bool intersectSS_strict(const Line &s, const Line &t) {
    if (isOnSegment(s, t)) return false;
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
           ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

//距離,交点
//射影 直線lにpから下した垂線との交点
point projection(
    const Line &l,
    const point &
        p) {  // verified on 2020/04/03
              // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
    return l[0] + (l[0] - l[1]) * t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) { return p + (projection(l, p) - p) * 2; }
double distancePP(const point &a, const point &b) { return sqrt(norm(a - b)); }
double distanceLP(const Line &l, const point &p) { return abs(p - projection(l, p)); }
double distanceLL(const Line &l, const Line &m) {
    return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
    if (intersectLS(l, s)) return 0;
    return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
    const point r = projection(s, p);
    if (intersectSP(s, r)) return abs(r - p);
    return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) {
    // verified on 2020/04/03
    // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    if (intersectSS(s, t)) return 0;
    return min({distanceSP(s, t[0]), distanceSP(s, t[1]), distanceSP(t, s[0]),
                distanceSP(t, s[1])});
}
point crosspoint(const Line &l, const Line &m) {
    double A = cross(l[1] - l[0], m[1] - m[0]);
    double B = cross(l[1] - l[0], l[1] - m[0]);
    if (abs(A) < EPS && abs(B) < EPS) return m[0];  // same line
    if (abs(A) < EPS) assert(false);                // Precondition not satisfied
    return m[0] + B / A * (m[1] - m[0]);
}
//double dist(point &p1, point &p2) { return abs(p1 - p2); }


const int MAX_COUNT = 6;
int N;
Line mirrors[10];

//鏡の順番
void dfs(int cnt,int k,int las,vector<vector<int>>&ret,vector<int>res){
    if(k==cnt){
        ret.push_back(res);return;
    }
    REP(i,N){
        if(i!=las){
            res.push_back(i);
            dfs(cnt,k+1,i,ret,res);
            res.pop_back();
        }
    }
}

bool solve(){
    cin>>N;
    if(N==0)return false;
    REP(i,N){
        int a,b,c,d;cin>>a>>b>>c>>d;
        mirrors[i]=Line(point(a,b),point(c,d),i);
    }
    int sx,sy,gx,gy;
    cin>>gx>>gy>>sx>>sy;
    const point S(sx,sy),G(gx,gy);
    double ans = INF;
    vector<double>cand;
    DEBUG(abs(S-G));
    //反射回数
    REP(K,6){
        vector<vector<int>>vp;//鏡の順番
        vector<int>tmp;
        dfs(K,0,-1,vp,tmp);
        DEBUG(K);
        for(auto p:vp){
            REP(i,K){
                //DEBUG(i,p[i]);
            }
            bool ok = true;
            point G2 = G;
            REPR(i,K)G2=reflection(mirrors[p[i]],G2);
            //DEBUG(G2,abs(S-G2));
            double res = 0;
            if(abs(abs(S-G2)-243.134)<0.1){
                DEBUG(G,abs(S-G2));
                DEBUG(K);
                REP(i,K){
                    DEBUG(p[i],mirrors[p[i]][0],mirrors[p[i]][1]);
                }
            }
            //else continue;
            point dir=direction(G2-S);
            Line l(S,S+dir*INF);
            //Sから発射したビームがp[0],p[1],...,Gの順にぶつかるか判定
            //DEBUG(G2);
            point s = S;
            REP(i,K){
                //p[i]に最初に衝突するか
                vector<pair<double,int>>dist_id;
                REP(j,N)if(intersectSS_strict(l,mirrors[j])){
                    if(intersectSP(mirrors[j],s))continue;
                    point crs = crosspoint(l,mirrors[j]);
                    double dist = abs(crs-s);
                    dist_id.emplace_back(dist,j);
                }
                sort(all(dist_id));
                //DEBUG(dist_id.size());
                REP(j,dist_id.size()){
                    //DEBUG(dist_id[j].second,dist_id[j].first);
                }
                if(dist_id.size()==0||dist_id[0].second!=p[i]){ok=false;break;}

                point s2 = reflection(mirrors[p[i]],s);
                point crs = crosspoint(l,mirrors[p[i]]);
                res+=abs(s-crs);
                dir = direction(crs-s2);
                s = crosspoint(l,mirrors[p[i]]);
                l[0]=s,l[1]=s+dir*INF;
            }
            //if(!ok)continue;
            //sからGに最初に衝突するか
            if(!intersectSP(l,G))ok=false;
            dir=direction(G-s);
            l[0]=s,l[1]=s+dir*INF;
            double d_sG=abs(s-G);
            REP(i,N)if(intersectSS_strict(l,mirrors[i])){
                if(intersectSP(mirrors[i],s))continue;
                point crs = crosspoint(mirrors[i],l);
                double dist = abs(crs-s);
                if(dist<d_sG){ok=false;break;}
            }
            res+=abs(G2-s);
            if(ok){
                DEBUG(K);
                REP(i,K){
                    DEBUG(p[i],mirrors[p[i]][0],mirrors[p[i]][1]);
                }
                DEBUG(abs(S-G2));
                cand.push_back(abs(S-G2));
                chmin(ans,abs(S-G2));
            }
        }

    }
    sort(all(cand));
    #ifdef TEST
    for(auto d:cand)cerr<<d<<" ";
    cerr<<endl;
    #endif
    cout<<fixed<<setprecision(10)<<ans<<endl;

    return true;
}

signed main(){
    while(solve()){

    }
}
accuracy: 1
time_ms: 50
memory_kb: 3276
final_rank: 5

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

using namespace std;

#define REP(i, n) for (int i=0; i<(n); ++i)
#define RREP(i, n) for (int i=(int)(n)-1; i>=0; --i)
#define FOR(i, a, n) for (int i=(a); i<(n); ++i)
#define RFOR(i, a, n) for (int i=(int)(n)-1; i>=(a); --i)

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()

#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<<endl;

template<class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[";
  REP(i, SZ(v)) {
    if (i) os << ", ";
    os << v[i];
  }
  return os << "]";
}

template<class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << " " << p.second << ")";
}

template<class T>
bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template<class T>
bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 1e9 + 7;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;

/**
 * @brief
 * 二次元幾何
 * @author habara-k
 * @date 2020/05/05
 */

using Real = double;
const Real PI = acos(-1);

using Point = complex<Real>;
namespace std {
  bool operator<(const Point& a, const Point& b) {
    if (a.real() == b.real()) return a.imag() < b.imag();
    return a.real() < b.real();
  }
}

struct Line {
  Point a, b;
  Line() {}
  Line(const Point& a, const Point& b) : a(a), b(b) {}
  friend ostream& operator<<(ostream& os, const Line& l) {
    return os << "[" << l.a << "," << l.b << "]";
  }
};

struct Segment : Line {
  Segment() {}

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

inline bool eq(Real a, Real b) { return abs(b - a) < eps; }

Real radian_to_degree(Real r) {
  return r * 180.0 / PI;
}

Real degree_to_radian(Real d) {
  return d * PI / 180.0;
}

Point rotate(const Point &p, Real theta) {
  return p * polar((Real)1.0, theta);
}

Real cross(const Point& a, const Point& b) {
  return a.real() * b.imag() - a.imag() * b.real();
}

Real dot(const Point& a, const Point& b) {
  return a.real() * b.real() + a.imag() * b.imag();
}


/**
* @brief 点p の直線l への射影を求める.
*/
Point projection(const Line& l, const Point& p) {
  Real A = dot(l.b - l.a, p - l.a),
      B = dot(l.a - l.b, p - l.b);
  return (A * l.b + B * l.a) / (A + B);
}

/**
* @brief 2直線の並行判定
*/
bool parallel(const Line& l1, const Line& l2) {
  return eq(cross(l1.a - l1.b, l2.a - l2.b), 0.0);
}

/**
* @brief 2直線の直行判定
*/
bool orthogonal(const Line& l1, const Line& l2) {
  return eq(dot(l1.a - l1.b, l2.a - l2.b), 0.0);
}


/**
* @brief 有向線分と点の位置関係
* @param[in] a, b, c: 線分a->b, 点c
* @return 線分a->b からみて, 点c がどこにあるか.
*/
const int COUNTER_CLOCKWISE = 1,
    CLOCKWISE = -1,
    ONLINE_BACK = 2,
    ONLINE_FRONT = -2,
    ON_SEGMENT = 0;
int ccw(const Point& a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > eps) return COUNTER_CLOCKWISE;
  if (cross(b, c) < -eps) return CLOCKWISE;
  if (dot(b, c) < 0) return ONLINE_BACK;
  if (norm(b) < norm(c)) return ONLINE_FRONT;
  return ON_SEGMENT;
}


/**
* @brief 直線と点の交差判定
*/
bool intersected(const Line& l, const Point& p) {
  return abs(ccw(l.a, l.b, p)) != 1;
}

/**
* @brief 線分と点の交差判定
*/
bool intersected(const Segment& s, const Point& p) {
  return ccw(s.a, s.b, p) == 0;
}

/**
* @brief 直線と線分の交差判定
*/
bool intersected(const Line& l, const Segment& s) {
  return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps;
}

/**
* @brief 2つの線分の交差判定
*/
bool intersected(const Segment& s1, const Segment& s2) {
  return ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) <= 0 and
         ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) <= 0;
}


/**
* @brief 2直線の交点
*/
Point crosspoint(const Line& l1, const Line& l2) {
  Real A = cross(l2.a - l1.a, l2.b - l1.a),
      B = cross(l2.b - l1.b, l2.a - l1.b);
  return (A * l1.b + B * l1.a) / (A + B);
}


/**
* @brief 直線と点の距離
*/
Real distance(const Line& l, const Point& p) {
  return abs(p - projection(l, p));
}

/**
* @brief 線分と点の距離
*/
Real distance(const Segment& s, const Point& p) {
  Point r = projection(s, p);
  if (intersected(s, r)) return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

/**
* @brief 直線と線分の距離
*/
Real distance(const Line &l, const Segment &s) {
  if (intersected(l, s)) return 0;
  return min(distance(l, s.a), distance(l, s.b));
}

/**
* @brief 2つの線分の距離
*/
Real distance(const Segment& s1, const Segment& s2) {
  if (intersected(s1, s2)) return 0.0;
  return min({ distance(s1, s2.a), distance(s1, s2.b),
               distance(s2, s1.a), distance(s2, s1.b) });
}


struct Circle {
  Point p;
  Real r;
  Circle() {}
  Circle(const Point& p, Real r) : p(p), r(r) {}
};


/**
* @brief 2つの円の交点の数
*/
int intersected(Circle c1, Circle c2) {
  if (c1.r < c2.r) swap(c1, c2);
  Real d = abs(c1.p - c2.p);
  if (c1.r + c2.r < d) return 4;
  if (eq(c1.r + c2.r, d)) return 3;
  if (c1.r - c2.r < d) return 2;
  if (eq(c1.r - c2.r, d)) return 1;
  return 0;
}

/**
* @brief 円と直線の交点のペア
* @details 交差することを確認してから呼ぶこと.
*/
pair<Point,Point> crosspoint(const Circle& c, const Line& l) {
  Real h = distance(l, c.p);
  Point p = projection(l, c.p);
  if (eq(h, c.r)) return { p, p };
  Point u = l.a - l.b; u /= abs(u);
  Real d = sqrt(c.r * c.r - h * h);
  return { p + u * d, p - u * d };
}

/**
* @brief 2つの円の交点のペア
* @details 交差することを確認してから呼ぶこと.
*/
pair<Point,Point> crosspoint(const Circle& c1, const Circle& c2) {
  Real d = abs(c2.p - c1.p), t = arg(c2.p - c1.p);
  Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
  return { c1.p + polar(c1.r, t + a),
           c1.p + polar(c1.r, t - a) };
}

/**
* @brief 点p, 円c に対し, pを通るcの接線を返す(c上の2点のペアで返す).
* @details 点p が円c の外側にあることを確認してから呼ぶこと.
*/
pair<Point,Point> tangent(const Point& p, const Circle& c) {
  return crosspoint(c, Circle(p, sqrt(norm(p - c.p) - c.r * c.r)));
};

/**
* @brief 2つの円に共通する接線を返す(最大4本).
* @details 点p が円c の外側にあることを確認してから呼ぶこと.
*/
vector<Line> common_tangent(const Circle& c1, const Circle& c2) {
  vector<Line> lines;
  Point u = c2.p - c1.p;
  Real d = abs(u);
  if (eq(d, 0.0)) return lines;
  u /= d;
  for (Real s : { -1, 1 }) {
    // s = -1: 同じ側に2つの円があるとき.
    // s =  1: 反対側に2つの円があるとき.
    Real h = (c1.r + s * c2.r) / d;
    if (eq(abs(h), 1.0)) {
      // 2つの円が接しているとき.
      lines.emplace_back(
          c1.p + u * h * c1.r,
          c1.p + u * h * c1.r + rotate(u, PI / 2.0));
    } else if (abs(h) < 1) {
      // 2本の接線が引けるとき.
      Real a = acos(h);
      lines.emplace_back(
          c1.p + u * polar(c1.r, a),
          c2.p - s * u * polar(c2.r, a));
      lines.emplace_back(
          c1.p + u * polar(c1.r, -a),
          c2.p - s * u * polar(c2.r, -a));
    }
  }
  return lines;
}

using PDD = pair<double, double>;

int n;
vector<PDD> p, q;
double tx, ty, lx, ly;
double ans = INF;

Point hanten(Segment l, Point p2) {
  double dx = l.a.real(), dy = l.a.imag();
  auto para = complex<double>(dx, dy);
  l.a -= para;
  l.b -= para;
  p2 -= para;

  double theta = atan2(l.b.imag(), l.b.real());
  double a11 = cos(2*theta), a12 = sin(2*theta), a21 = sin(2*theta), a22 = -cos(2*theta);

  p2 = {a11 * p2.real() + a12 * p2.imag(), a21 * p2.real() + a22 * p2.imag()};

  p2 += para;
  l.b += para;
  l.a += para;
  return p2;
}

bool operator<(const Segment &s1, const Segment &s2) {
  if(s1.a == s2.a) {
    return s1.b < s2.b;
  } else {
    return s1.a < s2.a;
  }
}

void check(vi &v) {
  int sz = SZ(v);
  Point st = Point(lx, ly);

  vector<vector<Segment>> lv(sz+1, vector<Segment>(n));
  REP(i, n) {
    lv[0][i] = Segment(Point(p[i].first, p[i].second), Point(q[i].first, q[i].second));
  }
  vector<Point> t(sz+1);
  t[0] = Point(tx, ty);
  REP(i, sz) {
    REP(j, n) {
      auto a = hanten(lv[i][v[i]], lv[i][j].a);
      auto b = hanten(lv[i][v[i]], lv[i][j].b);
      lv[i+1][j] = Segment(a, b);
    }
    t[i+1] = hanten(lv[i][v[i]], t[i]);
  }

  Segment l = Segment(st, t[sz]);
  Point now = t[sz];
  bool ok = true;
  //cout << t << endl;
  double val = abs(st - t[sz]);
  for(int i=sz-1;i>=0;--i) {
    bool res = intersected(l, lv[i+1][v[i]]);
    if(res) {
      Point nxt = crosspoint(l, lv[i+1][v[i]]);
      l = Segment(nxt, now);
      REP(j, n) {
        if(v[i] != j && (i == sz-1 || v[i+1] != j)) {
          res &= !intersected(l, lv[i+1][j]);
        }
      }
      if(!res) {
        ok = false;
        break;
      }
      l = Segment(st, nxt);
      now = nxt;
    } else {
      ok = false;
      break;
    }
  }

  bool res = true;
  REP(j, n) {
    if(SZ(v) == 0 || v[0] != j) {
      res &= !intersected(l, lv[0][j]);
    }
  }
  if(!res) ok = false;
  //cout << v << endl;
  //cout << ok << ":" << val << endl;
  if(ok) {
    chmin(ans, val);
  }
}

void junban(int k, vi &v) {
  if(k == 5) {
    check(v);
  } else {
    if(k > 0) check(v);
    REP(i, n) {
      if(k > 0 && v.back() == i) continue;
      v.push_back(i);
      junban(k+1, v);
      v.pop_back();
    }
  }
}

bool solve() {
  cin >> n;
  if(n == 0) {
    return false;
  }
  p.resize(n);
  q.resize(n);
  REP(i, n) {
    cin >> p[i].first >> p[i].second;
    cin >> q[i].first >> q[i].second;
  }

  cin >> tx >> ty >> lx >> ly;
  ans = INF;

  vi v;
  check(v);
  junban(0, v);
  cout << ans << endl;

  return true;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);

  while(solve()) {}

  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3864
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;




struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

	double x,y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	Point p[2];
};

int N;
double ans;
Line line[5];
Point start,goal;

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}


Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

Point calc_Reflection_Point(double x1,double y1,double x2,double y2,double xp,double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}

double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}


void calc(vector<int> V){

	Point GOAL = goal;
	Line work[5];
	for(int i = 0; i < N; i++){

		work[i] = line[i];
	}

	//goalの最終位置を計算
	for(int i = 0; i < V.size(); i++){
		for(int k = 0; k < N; k++){
			if(k == V[i])continue;
			work[k].p[0] = calc_Reflection_Point(work[V[i]],work[k].p[0]);
			work[k].p[1] = calc_Reflection_Point(work[V[i]],work[k].p[1]);
		}

		GOAL = calc_Reflection_Point(work[V[i]],GOAL);
	}

	for(int i = 0; i < N; i++){

		work[i] = line[i];
	}

	int last;
	double sum = 0;

	Point from = start;

	for(int i = 0; i < V.size(); i++){

		last = V[i];
		Line tmp_line = Line(from,GOAL);

		if(!is_Cross(tmp_line,work[V[i]])){
			return;
		}

		Point cross_point = calc_Cross_Point(tmp_line,work[V[i]]);

		tmp_line.p[0] = from;
		tmp_line.p[1] = cross_point;

		for(int k = 0; k < N; k++){ //使わない鏡も見る
			if(k == V[i] || (i > 0 && k == V[i-1]))continue;
			if(is_Cross(tmp_line,work[k])){
				return;
			}
		}

		sum += calc_dist(from,cross_point);

		for(int k = 0; k < N; k++){
			if(k == V[i])continue;
			work[k].p[0] = calc_Reflection_Point(work[V[i]],work[k].p[0]);
			work[k].p[1] = calc_Reflection_Point(work[V[i]],work[k].p[1]);
		}

		from = cross_point;
	}

	Line final = Line(from,GOAL);

	for(int k = 0; k < N; k++){
		if(k == last)continue;
		if(is_Cross(final,work[k])){
			return;
		}
	}

	sum += calc_dist(from,GOAL);

	ans = min(ans,sum);
}


void func(){

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}
	scanf("%lf %lf",&goal.x,&goal.y);
	scanf("%lf %lf",&start.x,&start.y);

	ans = BIG_NUM;
	vector<int> V;

	//0
	calc(V);

	vector<int> A,B,C,D,E;

	for(int a = 0; a < N; a++){
		A.clear();
		A.push_back(a);
		calc(A);
		for(int b = 0; b < N; b++){
			if(b == a)continue;
			B.clear();
			B.push_back(a);
			B.push_back(b);
			calc(B);
			for(int c = 0; c < N; c++){
				if(c == b)continue;
				C.clear();
				C.push_back(a);
				C.push_back(b);
				C.push_back(c);
				calc(C);
				for(int d = 0; d < N; d++){
					if(d == c)continue;
					D.clear();
					D.push_back(a);
					D.push_back(b);
					D.push_back(c);
					D.push_back(d);
					calc(D);
					for(int e = 0; e < N; e++){
						if(e == d)continue;
						E.clear();
						E.push_back(a);
						E.push_back(b);
						E.push_back(c);
						E.push_back(d);
						E.push_back(e);
						calc(E);
					}
				}
			}
		}
	}

	printf("%.10lf\n",ans);
}

int main(){

	while(true){
		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3264
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b)) < EPS)
const double PI = asinl(1) * 2;

// COUNTER CLOCKWISE
static const int CCW_COUNTER_CLOCKWISE = 1;
static const int CCW_CLOCKWISE = -1;
static const int CCW_ONLINE_BACK = 2;
static const int CCW_ONLINE_FRONT = -2;
static const int CCW_ON_SEGMENT = 0;

// intercsect of circles
static const int ICC_SEPERATE = 4;
static const int ICC_CIRCUMSCRIBE = 3;
static const int ICC_INTERSECT = 2;
static const int ICC_INSCRIBE = 1;
static const int ICC_CONTAIN = 0;

struct Point{
  double x,y;
  Point(){}
  Point(double x,double y) :x(x),y(y){}
  Point operator+(Point p) {return Point(x+p.x,y+p.y);}
  Point operator-(Point p) {return Point(x-p.x,y-p.y);}
  Point operator*(double k){return Point(x*k,y*k);}
  Point operator/(double k){return Point(x/k,y/k);}
  double norm(){return x*x+y*y;}
  double abs(){return sqrt(norm());}

  bool operator < (const Point &p) const{
    return x!=p.x?x<p.x:y<p.y;
    //grid-point only
    //return !equals(x,p.x)?x<p.x:!equals(y,p.y)?y<p.y:0;
  }

  bool operator == (const Point &p) const{
    return fabs(x-p.x)<EPS && fabs(y-p.y)<EPS;
  }
};

struct EndPoint{
  Point p;
  int seg,st;
  EndPoint(){}
  EndPoint(Point p,int seg,int st):p(p),seg(seg),st(st){}
  bool operator<(const EndPoint &ep)const{
    if(p.y==ep.p.y) return st<ep.st;
    return p.y<ep.p.y;
  }
};

istream &operator >> (istream &is,Point &p){
  is>>p.x>>p.y;
  return is;
}

ostream &operator << (ostream &os,Point p){
  os<<fixed<<setprecision(12)<<p.x<<" "<<p.y;
  return os;
}

bool sort_x(Point a,Point b){
  return a.x!=b.x?a.x<b.x:a.y<b.y;
}

bool sort_y(Point a,Point b){
  return a.y!=b.y?a.y<b.y:a.x<b.x;
}

typedef Point Vector;
typedef vector<Point> Polygon;

istream &operator >> (istream &is,Polygon &p){
  for(int i=0;i<(int)p.size();i++) is>>p[i];
  return is;
}

struct Segment{
  Point p1,p2;
  Segment(){}
  Segment(Point p1, Point p2):p1(p1),p2(p2){}
};
typedef Segment Line;

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

struct Circle{
  Point c;
  double r;
  Circle(){}
  Circle(Point c,double r):c(c),r(r){}
};

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

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

Point orth(Point p){return Point(-p.y,p.x);}

bool isOrthogonal(Vector a,Vector b){
  return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
  return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
  return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
  return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
  return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
  return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
  Vector base=s.p2-s.p1;
  double r=dot(p-s.p1,base)/norm(base);
  return s.p1+base*r;
}

Point reflect(Segment s,Point p){
  return p+(project(s,p)-p)*2.0;
}

double arg(Vector p){
  return atan2(p.y,p.x);
}

Vector polar(double a,double r){
  return Point(cos(r)*a,sin(r)*a);
}

int ccw(Point p0,Point p1,Point p2);
bool intersectSS(Point p1,Point p2,Point p3,Point p4);
bool intersectSS(Segment s1,Segment s2);
bool intersectPS(Polygon p,Segment l);
int intersectCC(Circle c1,Circle c2);
bool intersectSC(Segment s,Circle c);
double getDistanceLP(Line l,Point p);
double getDistanceSP(Segment s,Point p);
double getDistanceSS(Segment s1,Segment s2);
Point getCrossPointSS(Segment s1,Segment s2);
Point getCrossPointLL(Line l1,Line l2);
Polygon getCrossPointCL(Circle c,Line l);
Polygon getCrossPointCC(Circle c1,Circle c2);
int contains(Polygon g,Point p);
Polygon andrewScan(Polygon s);
Polygon convex_hull(Polygon ps);
double diameter(Polygon s);
bool isConvex(Polygon p);
double area(Polygon s);
Polygon convexCut(Polygon p,Line l);
Line bisector(Point p1,Point p2);
Vector translate(Vector v,double theta);
vector<Line> corner(Line l1,Line l2);
vector< vector<int> >
segmentArrangement(vector<Segment> &ss, Polygon &ps);

int ccw(Point p0,Point p1,Point p2){
  Vector a = p1-p0;
  Vector b = p2-p0;
  if(cross(a,b) > EPS) return CCW_COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS) return CCW_CLOCKWISE;
  if(dot(a,b) < -EPS) return CCW_ONLINE_BACK;
  if(a.norm()<b.norm()) return CCW_ONLINE_FRONT;
  return CCW_ON_SEGMENT;
}

bool intersectSS(Point p1,Point p2,Point p3,Point p4){
  return (ccw(p1,p2,p3)*ccw(p1,p2,p4) <= 0 &&
          ccw(p3,p4,p1)*ccw(p3,p4,p2) <= 0 );
}

bool intersectSS(Segment s1,Segment s2){
  return intersectSS(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool intersectPS(Polygon p,Segment l){
  int n=p.size();
  for(int i=0;i<n;i++)
    if(intersectSS(Segment(p[i],p[(i+1)%n]),l)) return 1;
  return 0;
}

int intersectCC(Circle c1,Circle c2){
  if(c1.r<c2.r) swap(c1,c2);
  double d=abs(c1.c-c2.c);
  double r=c1.r+c2.r;
  if(equals(d,r)) return ICC_CIRCUMSCRIBE;
  if(d>r) return ICC_SEPERATE;
  if(equals(d+c2.r,c1.r)) return ICC_INSCRIBE;
  if(d+c2.r<c1.r) return ICC_CONTAIN;
  return ICC_INTERSECT;
}

bool intersectSC(Segment s,Circle c){
  return getDistanceSP(s,c.c)<=c.r;
}

int intersectCS(Circle c,Segment s){
  if(norm(project(s,c.c)-c.c)-c.r*c.r>EPS) return 0;
  double d1=abs(c.c-s.p1),d2=abs(c.c-s.p2);
  if(d1<c.r+EPS&&d2<c.r+EPS) return 0;
  if((d1<c.r-EPS&&d2>c.r+EPS)||(d1>c.r+EPS&&d2<c.r-EPS)) return 1;
  Point h=project(s,c.c);
  if(dot(s.p1-h,s.p2-h)<0) return 2;
  return 0;
}

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

double getDistanceSP(Segment s,Point 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);
}

double getDistanceSS(Segment s1,Segment s2){
  if(intersectSS(s1,s2)) return 0.0;
  return min(min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
             min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}

Point getCrossPointSS(Segment s1,Segment s2){
  for(int k=0;k<2;k++){
    if(getDistanceSP(s1,s2.p1)<EPS) return s2.p1;
    if(getDistanceSP(s1,s2.p2)<EPS) return s2.p2;
    swap(s1,s2);
  }
  Vector base=s2.p2-s2.p1;
  double d1=abs(cross(base,s1.p1-s2.p1));
  double d2=abs(cross(base,s1.p2-s2.p1));
  double t=d1/(d1+d2);
  return s1.p1+(s1.p2-s1.p1)*t;
}

Point getCrossPointLL(Line l1,Line l2){
  double a=cross(l1.p2-l1.p1,l2.p2-l2.p1);
  double b=cross(l1.p2-l1.p1,l1.p2-l2.p1);
  if(abs(a)<EPS&&abs(b)<EPS) return l2.p1;
  return l2.p1+(l2.p2-l2.p1)*(b/a);
}

Polygon getCrossPointCL(Circle c,Line l){
  Polygon ps;
  Point pr=project(l,c.c);
  Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
  if(equals(getDistanceLP(l,c.c),c.r)){
    ps.emplace_back(pr);
    return ps;
  }
  double base=sqrt(c.r*c.r-norm(pr-c.c));
  ps.emplace_back(pr+e*base);
  ps.emplace_back(pr-e*base);
  return ps;
}

Polygon getCrossPointCS(Circle c,Segment s){
  Line l(s);
  Polygon res=getCrossPointCL(c,l);
  if(intersectCS(c,s)==2) return res;
  if(res.size()>1u){
    if(dot(l.p1-res[0],l.p2-res[0])>0) swap(res[0],res[1]);
    res.pop_back();
  }
  return res;
}


Polygon getCrossPointCC(Circle c1,Circle c2){
  Polygon p(2);
  double d=abs(c1.c-c2.c);
  double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
  double t=arg(c2.c-c1.c);
  p[0]=c1.c+polar(c1.r,t+a);
  p[1]=c1.c+polar(c1.r,t-a);
  return p;
}

// IN:2 ON:1 OUT:0
int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Point a=g[i]-p,b=g[(i+1)%n]-p;
    if(fabs(cross(a,b)) < EPS && dot(a,b) < EPS) return 1;
    if(a.y>b.y) swap(a,b);
    if(a.y < EPS && EPS < b.y && cross(a,b) > EPS ) x = !x;
  }
  return (x?2:0);
}

Polygon andrewScan(Polygon s){
  Polygon u,l;
  if(s.size()<3) return s;
  sort(s.begin(),s.end());
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);
  for(int i=2;i<(int)s.size();i++){
    for(int n=u.size();
        n>=2&&ccw(u[n-2],u[n-1],s[i])!=CCW_CLOCKWISE;
        n--){
      u.pop_back();
    }
    u.push_back(s[i]);
  }
  for(int i=s.size()-3;i>=0;i--){
    for(int n=l.size();
        n>=2&&ccw(l[n-2],l[n-1],s[i])!=CCW_CLOCKWISE;
        n--){
      l.pop_back();
    }
    l.push_back(s[i]);
  }
  reverse(l.begin(),l.end());
  for(int i=u.size()-2;i>=1;i--) l.push_back(u[i]);
  return l;
}

Polygon convex_hull(Polygon ps){
  int n=ps.size();
  sort(ps.begin(),ps.end(),sort_y);
  int k=0;
  Polygon qs(n*2);
  for(int i=0;i<n;i++){
    while(k>1&&cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0) k--;
    qs[k++]=ps[i];
  }
  for(int i=n-2,t=k;i>=0;i--){
    while(k>t&&cross(qs[k-1]-qs[k-2],ps[i]-qs[k-1])<0) k--;
    qs[k++]=ps[i];
  }
  qs.resize(k-1);
  return qs;
}

double diameter(Polygon s){
  Polygon p=s;
  int n=p.size();
  if(n==2) return abs(p[0]-p[1]);
  int i=0,j=0;
  for(int k=0;k<n;k++){
    if(p[i]<p[k]) i=k;
    if(!(p[j]<p[k])) j=k;
  }
  double res=0;
  int si=i,sj=j;
  while(i!=sj||j!=si){
    res=max(res,abs(p[i]-p[j]));
    if(cross(p[(i+1)%n]-p[i],p[(j+1)%n]-p[j])<0.0){
      i=(i+1)%n;
    }else{
      j=(j+1)%n;
    }
  }
  return res;
}

bool isConvex(Polygon p){
  bool f=1;
  int n=p.size();
  for(int i=0;i<n;i++){
    int t=ccw(p[(i+n-1)%n],p[i],p[(i+1)%n]);
    f&=t!=CCW_CLOCKWISE;
  }
  return f;
}

double area(Polygon s){
  double res=0;
  for(int i=0;i<(int)s.size();i++){
    res+=cross(s[i],s[(i+1)%s.size()])/2.0;
  }
  return res;
}

double area(Circle c1,Circle c2){
  double d=abs(c1.c-c2.c);
  if(c1.r+c2.r<=d+EPS) return 0;
  if(d<=abs(c1.r-c2.r)){
    double r=min(c1.r,c2.r);
    return PI*r*r;
  }
  double res=0;
  for(int k=0;k<2;k++){
    double rc=(d*d+c1.r*c1.r-c2.r*c2.r)/(2*d*c1.r);
    double th=acosl(rc)*2;
    res+=(th-sinl(th))*c1.r*c1.r/2;
    swap(c1,c2);
  }
  return res;
}

Polygon convexCut(Polygon p,Line l){
  Polygon q;
  for(int i=0;i<(int)p.size();i++){
    Point a=p[i],b=p[(i+1)%p.size()];
    if(ccw(l.p1,l.p2,a)!=-1) q.push_back(a);
    if(ccw(l.p1,l.p2,a)*ccw(l.p1,l.p2,b)<0)
      q.push_back(getCrossPointLL(Line(a,b),l));
  }
  return q;
}

Line bisector(Point p1,Point p2){
  Circle c1=Circle(p1,abs(p1-p2)),c2=Circle(p2,abs(p1-p2));
  Polygon p=getCrossPointCC(c1,c2);
  if(cross(p2-p1,p[0]-p1)>0) swap(p[0],p[1]);
  return Line(p[0],p[1]);
}

Vector translate(Vector v,double theta){
  Vector res;
  res.x=cos(theta)*v.x-sin(theta)*v.y;
  res.y=sin(theta)*v.x+cos(theta)*v.y;
  return res;
}

vector<Line> corner(Line l1,Line l2){
  vector<Line> res;
  if(isParallel(l1,l2)){
    double d=getDistanceLP(l1,l2.p1)/2.0;
    Vector v1=l1.p2-l1.p1;
    v1=v1/v1.abs()*d;
    Point p=l2.p1+translate(v1,90.0*(PI/180.0));
    double d1=getDistanceLP(l1,p);
    double d2=getDistanceLP(l2,p);
    if(abs(d1-d2)>d){
      p=l2.p1+translate(v1,-90.0*(PI/180.0));
    }
    res.push_back(Line(p,p+v1));
  }else{
    Point p=getCrossPointLL(l1,l2);
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    v1=v1/v1.abs();
    v2=v2/v2.abs();
    res.push_back(Line(p,p+(v1+v2)));
    res.push_back(Line(p,p+translate(v1+v2,90.0*(PI/180.0))));
  }
  return res;
}

Polygon tangent(Circle c1,Point p2){
  Circle c2=Circle(p2,sqrt(norm(c1.c-p2)-c1.r*c1.r));
  Polygon p=getCrossPointCC(c1,c2);
  sort(p.begin(),p.end());
  return p;
}

vector<Line> tangent(Circle c1,Circle c2){
  vector<Line> ls;
  if(c1.r<c2.r) swap(c1,c2);
  double g=norm(c1.c-c2.c);
  if(equals(g,0)) return ls;
  Point u=(c2.c-c1.c)/sqrt(g);
  Point v=orth(u);
  for(int s=1;s>=-1;s-=2){
    double h=(c1.r+s*c2.r)/sqrt(g);
    if(equals(1-h*h,0)){
      ls.emplace_back(c1.c+u*c1.r,c1.c+(u+v)*c1.r);
    }else if(1-h*h>0){
      Point uu=u*h,vv=v*sqrt(1-h*h);
      ls.emplace_back(c1.c+(uu+vv)*c1.r,c2.c-(uu+vv)*c2.r*s);
      ls.emplace_back(c1.c+(uu-vv)*c1.r,c2.c-(uu-vv)*c2.r*s);
    }
  }

  return ls;
}

double closest_pair(Polygon &a,int l=0,int r=-1){
  if(r<0){
    r=a.size();
    sort(a.begin(),a.end(),sort_x);
  }
  if(r-l<=1) return abs(a[0]-a[1]);
  int m=(l+r)>>1;
  double x=a[m].x;
  double d=min(closest_pair(a,l,m),closest_pair(a,m,r));
  inplace_merge(a.begin()+l,a.begin()+m,a.begin()+r,sort_y);

  Polygon b;
  for(int i=l;i<r;i++){
    if(fabs(a[i].x-x)>=d) continue;
    for(int j=0;j<(int)b.size();j++){
      double dy=a[i].y-next(b.rbegin(),j)->y;
      if(dy>=d) break;
      d=min(d,abs(a[i]-*next(b.rbegin(),j)));
    }
    b.emplace_back(a[i]);
  }
  return d;
}

vector<vector<int> >
segmentArrangement(vector<Segment> &ss, Polygon &ps){
  int n=ss.size();
  for(int i=0;i<n;i++){
    ps.emplace_back(ss[i].p1);
    ps.emplace_back(ss[i].p2);
    for(int j=i+1;j<n;j++)
      if(intersectSS(ss[i],ss[j]))
        ps.emplace_back(getCrossPointSS(ss[i],ss[j]));
  }
  sort(ps.begin(),ps.end());
  ps.erase(unique(ps.begin(),ps.end()),ps.end());

  vector<vector<int> > G(ps.size());
  for(int i=0;i<n;i++){
    vector<pair<double,int> > ls;
    for(int j=0;j<(int)ps.size();j++)
      if(getDistanceSP(ss[i],ps[j])<EPS)
        ls.emplace_back(make_pair(norm(ss[i].p1-ps[j]),j));

    sort(ls.begin(),ls.end());
    for(int j=0;j+1<(int)ls.size();j++){
      int a=ls[j].second,b=ls[j+1].second;
      G[a].emplace_back(b);
      G[b].emplace_back(a);
    }
  }
  for(auto &v:G){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
  }
  return G;
}

int manhattan_intersection(vector<Segment> ss,const int INF){
  const int BTM = 0;
  const int LFT = 1;
  const int RGH = 2;
  const int TOP = 3;

  int n=ss.size();
  vector<EndPoint> ep;
  for(int i=0;i<n;i++){
    if(ss[i].p1.y==ss[i].p2.y){
      if(ss[i].p1.x>ss[i].p2.x) swap(ss[i].p1,ss[i].p2);
      ep.emplace_back(ss[i].p1,i,LFT);
      ep.emplace_back(ss[i].p2,i,RGH);
    }else{
      if(ss[i].p1.y>ss[i].p2.y) swap(ss[i].p1,ss[i].p2);
      ep.emplace_back(ss[i].p1,i,BTM);
      ep.emplace_back(ss[i].p2,i,TOP);
    }
  }
  sort(ep.begin(),ep.end());

  set<int> bt;
  bt.insert(INF);

  int cnt=0;
  for(int i=0;i<n*2;i++){
    if(ep[i].st==TOP){
      bt.erase(ep[i].p.x);
    }else if(ep[i].st==BTM){
      bt.emplace(ep[i].p.x);
    }else if(ep[i].st==LFT){
      auto b=bt.lower_bound(ss[ep[i].seg].p1.x);
      auto e=bt.upper_bound(ss[ep[i].seg].p2.x);
      cnt+=distance(b,e);
    }
  }

  return cnt;
}

double area(Polygon ps,Circle c){
  if(ps.size()<3u) return 0;
  function<double(Circle, Point, Point)> dfs=
    [&](Circle c,Point a,Point b){
      Vector va=c.c-a,vb=c.c-b;
      double f=cross(va,vb),res=0;
      if(equals(f,0.0)) return res;
      if(max(abs(va),abs(vb))<c.r+EPS) return f;
      Vector d(dot(va,vb),cross(va,vb));
      if(getDistanceSP(Segment(a,b),c.c)>c.r-EPS)
        return c.r*c.r*atan2(d.y,d.x);
      auto u=getCrossPointCS(c,Segment(a,b));
      if(u.empty()) return res;
      if(u.size()>1u&&dot(u[1]-u[0],a-u[0])>0) swap(u[0],u[1]);
      u.emplace(u.begin(),a);
      u.emplace_back(b);
      for(int i=1;i<(int)u.size();i++)
        res+=dfs(c,u[i-1],u[i]);
      return res;
    };
  double res=0;
  for(int i=0;i<(int)ps.size();i++)
    res+=dfs(c,ps[i],ps[(i+1)%ps.size()]);
  return res/2;
}


struct Precision{
  Precision(){
    cout<<fixed<<setprecision(12);
  }
}precision_beet;


template<typename F>
struct FixPoint : F{
  FixPoint(F&& f):F(forward<F>(f)){}
  template<typename... Args>
  decltype(auto) operator()(Args&&... args) const{
    return F::operator()(*this,forward<Args>(args)...);
  }
};
template<typename F>
inline decltype(auto) MFP(F&& f){
  return FixPoint<F>{forward<F>(f)};
}

//INSERT ABOVE HERE
signed main(){
  int n;
  while(cin>>n,n){
    vector<Segment> ss(n);
    for(int i=0;i<n;i++)
      cin>>ss[i].p1>>ss[i].p2;
    Point s,t;
    cin>>s>>t;

    double ans=1e18;
    vector<int> vs(7);
    MFP([&](auto dfs,int x)->void{
          const int DEBUG = 0;
          {
            int flg=1;

            Point p(s),q(t);
            for(int i=x-1;i>=0;i--)
              q=reflect(ss[vs[i]],q);

            if(DEBUG){
              cout<<q<<":"<<abs(p-q)<<endl;
            }

            double res=0;
            for(int i=0;i<x;i++){
              if(DEBUG){
                cout<<i<<":i:"<<getDistanceSS(Segment(p,q),ss[vs[i]])<<endl;
                cout<<p<<" "<<q<<endl;
              }

              flg&=getDistanceSS(Segment(p,q),ss[vs[i]])<EPS;
              if(!flg) break;
              Point pp=p;
              p=getCrossPointSS(Segment(p,q),ss[vs[i]]);
              res+=abs(p-pp);

              for(int j=0;j<n;j++){
                if(j==vs[i]) continue;
                if(i&&j==vs[i-1]) continue;
                flg&=getDistanceSS(Segment(pp,p),ss[j])>EPS;
              }

              q=reflect(ss[vs[i]],q);
            }

            if(DEBUG){
              cout<<p<<" "<<q<<endl;
              cout<<"flg:"<<flg<<endl;
            }

            for(int j=0;j<n;j++)
              if(x==0||j!=vs[x-1]) flg&=getDistanceSS(Segment(p,q),ss[j])>EPS;

            res+=abs(p-q);
            if(flg) chmin(ans,res);

            if(DEBUG){
              cout<<res<<endl;
              for(int i=0;i<x;i++) cout<<vs[i]<<" ";
              cout<<endl;
              cout<<endl;
            }
          }

          if(x==7) return;
          for(int i=0;i<n;i++){
            vs[x]=i;
            dfs(x+1);
          }
        })(0);
    cout<<ans<<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 680
memory_kb: 3324
final_rank: 20

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

using ll=long long;
#define int ll

#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,b) rng(i,0,b)
#define gnr(i,a,b) for(int i=int(b)-1;i>=a;i--)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define eb emplace_back
#define a first
#define b second
#define bg begin()
#define ed end()
#define all(x) x.bg,x.ed
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif

template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}

template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;

using pi=pair<int,int>;
using vi=vc<int>;

template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.a<<","<<p.b<<"}";
}

template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}

using ld=long double;
using cm=complex<ld>;
#define x real()
#define y imag()
const ld eps=1e-8;
const ld PI=acos(ld(-1));
int sgn(ld a){return a<-eps?-1:(a>eps?1:0);}
ld dot(cm a,cm b){return a.x*b.x+a.y*b.y;}
ld crs(cm a,cm b){return a.x*b.y-a.y*b.x;}
ld crs(cm a,cm b,cm c){return crs(b-a,c-a);}
int ccw(cm a,cm b){return sgn(crs(a,b));}
int ccw(cm a,cm b,cm c){return ccw(b-a,c-a);}
auto cmcmp=[](cm a,cm b){
	int s=sgn(a.x-b.x);
	if(s)return s<0;
	else return sgn(a.y-b.y)<0;
};
bool cmeq(cm a,cm b){
	return sgn(a.x-b.x)==0&&sgn(a.y-b.y)==0;
};
//(-pi,0](0,pi]
int argtype(cm a){
	if(sgn(a.y)==0)return a.x<0?1:0;
	return a.y<0?0:1;
}
int argcmp(cm a,cm b){
	int at=argtype(a),bt=argtype(b);
	if(at!=bt)return at<bt?-1:1;
	return -ccw(a,b);
};
//(-2)[a,-1](0)[b,1](2)
int bet(cm a,cm b,cm c){
	cm d=b-a;
	ld e=dot(d,c-a);
	if(sgn(e)<=0)return sgn(e)-1;
	return sgn(e-norm(d))+1;
}

using ln=pair<cm,cm>;
cm dir(ln a){return a.b-a.a;}
cm eval(ln a,ld b){return a.a+dir(a)*b;}
int bet(ln a,cm b){return bet(a.a,a.b,b);}
int ccw(ln a,cm b){return ccw(a.a,a.b,b);}
cm proj(ln a,cm b){
	cm c=dir(a);
	return a.a+c*dot(c,b-a.a)/norm(c);
}
cm refl(ln a,cm b){
	return ld(2)*proj(a,b)-b;
}
//AOJ0153
ld dsp(ln a,cm b){
	cm c=proj(a,b);
	if(abs(bet(a.a,a.b,c))<=1)return abs(b-c);
	return min(abs(b-a.a),abs(b-a.b));
}
//AOJ1157
//0-no,1-yes(endpoint),2-yes(innner),3-overelap
int iss(ln a,ln b){
	int c1=ccw(a.a,a.b,b.a),c2=ccw(a.a,a.b,b.b);
	int d1=ccw(b.a,b.b,a.a),d2=ccw(b.a,b.b,a.b);
	if(c1||c2||d1||d2)return 1-max(c1*c2,d1*d2);
	int f=bet(a.a,a.b,b.a),g=bet(a.a,a.b,b.b);
	if(max(f,g)==-2||min(f,g)==2)return 0;
	return 3;
}
//AOJ1033
cm cll(ln a,ln b){
	return eval(a,crs(b.a,b.b,a.a)/crs(dir(a),dir(b)));
}

signed main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	
	while(1){
		int n;cin>>n;
		if(n==0)break;
		vc<ln> ms;
		rep(i,n){
			ld a,b,c,d;cin>>a>>b>>c>>d;
			ms.eb(cm(a,b),cm(c,d));
		}
		cm s,t;
		{
			ld a,b;cin>>a>>b;
			s=cm(a,b);
		}
		{
			ld a,b;cin>>a>>b;
			t=cm(a,b);
		}
		auto chk=[&](ln a){
			for(auto l:ms)
				if(iss(l,a)==2)return false;
			return true;
		};
		double ans=1e9;
		auto upd=[&](vi idx){
			vc<ln> cur=ms,r;
			cm g=t;
			for(auto i:idx){
				r.pb(cur[i]);
				ln w=cur[i];
				for(auto&l:cur)
					l=ln(refl(w,l.a),refl(w,l.b));
				g=refl(w,g);
			}
			vc<cm> ps{s};
			for(auto l:r){
				if(iss(ln(s,g),l)==2)
					ps.pb(cll(ln(s,g),l));
				else
					return;
			}
			ps.pb(g);
			dmp(idx);
			dmp(ps);
			rep(i,ps.size()-2)
				if(bet(ps[i],ps[i+2],ps[i+1]))
					return;
			rep(i,r.size())
				rng(j,ps.size()-1-i,ps.size())
					ps[j]=refl(r[r.size()-1-i],ps[j]);
			dmp(idx);
			rep(i,ps.size()-1)
				if(!chk(ln(ps[i],ps[i+1])))
					return;
			dmp(idx);
			chmin(ans,abs(g-s));
		};
		function<void(vi)>dfs=[&](vi idx){
			upd(idx);
			if(idx.size()<6){
				int last=-1;
				if(idx.size())last=idx.back();
				rep(i,n)if(i!=last){
					vi nx=idx;
					nx.pb(i);
					dfs(nx);
				}
			}
		};
		dfs({});
		cout<<ans<<endl;
	}
}
accuracy: 1
time_ms: 610
memory_kb: 3308
final_rank: 18

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;
using ld = double;
using Point =  complex<ld>;
const ld eps = 1e-9;
const ld pi = acos(-1.0);

bool eq(ld a, ld b) {
	return (abs(a - b) < eps);
}

bool cmp(Point x,Point y){
	if(eq(x.real(),y.real()))return x.imag()<y.imag();
	return x.real()<y.real();
}

bool eqq(Point x,Point y){
	return eq(x.real(),y.real())&&eq(x.imag(),y.imag());
}
//内積
ld dot(Point a, Point b) {
	return real(conj(a)*b);
}
//外積
ld cross(Point a, Point b) {
	return imag(conj(a)*b);
}


//線分
//直線にするなら十分通い２点を端点とすればよい
class Line {
public:
	Point a, b;
};
//円
class Circle {
public:
	Point p;
	ld r;
};
//3点の位置関係
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//a,b,cが反時計回り
	if (cross(b, c) < -eps)return -1;//a,b,cが時計回り
	if (dot(b, c) < 0)return 2;//c,a,bの順に一直線
	if (norm(b) < norm(c))return -2;//a,b,cの順に一直線
	return 0;//a,c,bの順に一直線
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a)*cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
bool isis_ss(Line s, Line t) {
	if (isis_sp(s, t.a) || isis_sp(s, t.b) || isis_sp(t, s.a) || isis_sp(t, s.b))return true;
	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}

Point cont(Line l,Point p){
    Point h = proj(l,p);
    return 2.0*h-p;
}
Line seg[10];
Point st,gl;
int m;
ld solve(vector<int>&v){
    int n=v.size();
    Point g=gl;
    for(int i=n-1;i>=0;--i){
        g=cont(seg[v[i]],g);
    }
    vector<Point> root;
    root.push_back(st);
    rep(i,n){
        if(!isis_ss(Line{root.back(),g},seg[v[i]]))return longinf;
        root.push_back(is_ll(Line{root.back(),g},seg[v[i]]));
        g=cont(seg[v[i]],g);
    }
    root.push_back(gl);
    ld ans=0;
    rep(i,n+1){
        rep(j,m){
            if(i<n&&v[i]==j)continue;
            if(i>0&&v[i-1]==j)continue;
            if(isis_ss(Line{root[i],root[i+1]},seg[j]))return longinf;
        }
        ans+=abs(root[i+1]-root[i]);
    }
    return ans;
}



void solve(){
    rep(i,m){
        double x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        seg[i]={Point(x1,y1),Point(x2,y2)};
    }
    
    double x,y;
    cin>>x>>y;
    st=Point(x,y);
    cin>>x>>y;
    gl=Point(x,y);
    ld ans=longinf;
    rep(i,6){
        int all=pow(m,i);
        rep(j,all){
            vector<int> v;
            int mask=j;
            rep(k,i){
                v.push_back(mask%m);
                mask/=m;
            }
            bool ok=true;
            rep(k,i-1){
                if(v[k]==v[k+1])ok=false;
            }
            if(ok)ans=min(ans,solve(v));
        }
    }
    cout<<ans<<endl;
}
int main(){
    cout<<fixed<<setprecision(12);
    while(cin>>m,m!=0)solve();
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3408
final_rank: 6

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : VP{
    L(const P& a, const P& b){ resize(2); at(0)=a; at(1)=b; }
    L(){ resize(2); }
};

namespace std{
	bool operator < (const P &a, const P &b){
		return (a.X!=b.X)? a.X<b.X : a.Y<b.Y;
	}
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}

int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) <-EPS) return -1; //cw
    if(dot(b,c) < EPS) return +2; //c-a-b
    if(norm(b) < norm(c)) return -2; //a-b-c
    return 0; //a-c-b
}
bool intersectSS(const L& s, const L& t){
    return ( ccw(s[0],s[1],t[0]) *ccw(s[0],s[1],t[1]) <= 0 ) &&
        ( ccw(t[0],t[1],s[0]) *ccw(t[0],t[1],s[1]) <= 0 );
}
bool strictItsSS(const L& s, const L& t){
    return ( ccw(s[0],s[1],t[0]) *ccw(s[0],s[1],t[1]) == -1 ) &&
        ( ccw(t[0],t[1],s[0]) *ccw(t[0],t[1],s[1]) == -1);
}

P projection(const L& l, const P& p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L& l, const P& p) {
  return p + 2.0*(projection(l, p) -p);
}
 
P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B /A *(m[1]-m[0]);
}
bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}


vector<int> idx(10, -1);
double solve(int step, int end, P s, P g, vector<vector<L> > &wall){
    if(step==end){
    	VP cp(step+2);
    	cp[0]=s; cp[step+1]=g;
        L ray(s,g);
        bool flag = true;
        for(int i=1; i<=step; i++){
            if(!isParallel(ray, wall[i][idx[i]]) && strictItsSS(ray, wall[i][idx[i]])){
                cp[i] = crosspointLL(ray, wall[i][idx[i]]);
            }else{
            	flag = false;
            	break;
            }
        }
        if(flag){
        	for(int i=0; i<=step; i++){
        		if((s<g && cp[i+1]<cp[i]) || (g<s && cp[i]<cp[i+1])){
        			flag = false;
        			break;
        		}
        	}
        }
        
        if(flag){
        	for(int i=0; i<=step; i++){
        		L cut_ray(cp[i], cp[i+1]);
        		for(int j=0; j<(int)wall[0].size(); j++){
        			if(j==idx[i] || j==idx[i+1]) continue;
        			if(intersectSS(cut_ray, wall[i][j])){
        				flag = false;
        				break;
        			}
        		}
        	}
        }
        
        if(flag){
            return abs(g-s);
        }else{
            return INF;
        }
    }
    
    double ans = INF;
    for(int i=0; i<(int)wall[0].size(); i++){
        if(idx[step]==i) continue;
        idx[step+1] = i;
        for(int j=0; j<(int)wall[0].size(); j++){
            wall[step+1][j] = L(reflection(wall[step][i], wall[step][j][0]), reflection(wall[step][i], wall[step][j][1]));
        }
        ans = min(ans, solve(step+1, end, s, reflection(wall[step][i], g), wall));
        idx[step+1] = -1;
    }
    return ans;
}

double search(P s, P g, vector<vector<L> > &wall){
    double ans = INF;
    for(int i=0; i<6; i++){
        ans = min(ans, solve(0,i,s,g,wall));
    }
    return ans;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;
        
        vector<vector<L> > wall(6, vector<L>(n));
        for(int i=0; i<n; i++){
            for(int j=0; j<2; j++){
                double x,y;
                cin >> x >> y;
                wall[0][i][j] = P(x,y);
            }
        }
        double sx,sy,gx,gy;
        cin >> gx >> gy >> sx >> sy;
        P s(sx,sy), g(gx, gy);

        cout << fixed;
        cout << setprecision(10);
        cout << search(s,g,wall) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3244
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef complex<double> P;
typedef pair<P,P> L;

const double EPS = 1e-7;

double dot(P a, P b){ return real(conj(a)*b); }
double cross(P a, P b){ return imag(conj(a)*b); }

int ccw(P a, P b, P c){
  b -= a;
  c -= a;
  if(cross(b,c) > EPS) return 1;
  if(cross(b,c) < -EPS) return -1;
  if(dot(b,c) < -EPS) return 2;
  if(norm(b) < norm(c)) return -2;
  return 0;
}

P proj(P p, L l){
    return l.first + dot(p - l.first, l.second - l.first) / norm(l.second - l.first) * (l.second - l.first);
}

P reflect(P p, L l){
  return p + (proj(p,l) - p) * 2.0;
}

bool isIntersect(L s1, L s2){
  return ( ccw(s1.first,s1.second,s2.first) * ccw(s1.first,s1.second,s2.second) <= 0 &&
           ccw(s2.first,s2.second,s1.first) * ccw(s2.first,s2.second,s1.second) <= 0 );
}

P crossPoint(L l, L m){
  double A = cross(l.second - l.first, m.second - m.first);
  double B = cross(l.second - l.first, l.second - m.first);
  if(fabs(A) < EPS && fabs(B) < EPS) return m.first;
  else if(fabs(A) >= EPS) return m.first + B / A * (m.second - m.first);
}

L refL(L a,L b){
  return L(reflect(a.first,b),reflect(a.second,b));
}

int n;
L m[5];
int dm[5];
P g,s;
double ans;

double check(int d){
  vector<L> gm[8];
  L tp[5],tm[5];
  P gg=g;
  
  for(int i=0;i<n;i++)tp[i]=m[i];
  bool ff=0;
  if(d==2&&dm[0]==1&&dm[1]==0)ff=1;
  for(int i=0;i<d;i++){

    for(int j=0;j<n;j++){

      if(dm[i]==j) tm[i]=tp[j];
      else if(!i||dm[i-1]!=j)gm[i].push_back(tp[j]);

    }

    for(int j=0;j<n;j++)tp[j]=refL(tp[j],tm[i]);
    gg=reflect(gg,tm[i]);
  }
 
  for(int i=0;i<n;i++)
    if(!d||dm[d-1]!=i)gm[d].push_back(tp[i]);

  L sg=L(s,gg);
  double res=abs(s-gg);

  vector<P> v;

  v.push_back(s);
  for(int i=0;i<d;i++){
    if(!isIntersect(sg,tm[i]))res=1e9;
    v.push_back(crossPoint(sg,tm[i]));
  }
  
  v.push_back(gg);
  double dd=0;
  for(int i=0;i<=d;i++){
    L ww=L(v[i],v[i+1]);
    dd+=abs(v[i]-v[i+1]);
    for(int j=0;j<(int)gm[i].size();j++)
      if(isIntersect(ww,gm[i][j]))res=1e9;
  }
  if(abs(dd-res)>EPS)res=1e9;
  return res;
}

void dfs(int pr,int d){
  ans=min(ans,check(d));
  if(d==5)return;
  for(int i=0;i<n;i++){
    if(pr==i)continue;
    dm[d]=i;
    dfs(i,d+1);
  }
}

int main(){
  while(cin>>n,n){
    double x1,y1,x2,y2;
    for(int i=0;i<n;i++){
      cin>>x1>>y1>>x2>>y2;
      m[i]=L(P(x1,y1),P(x2,y2));
    }
    cin>>x1>>y1>>x2>>y2;
    g=P(x1,y1),s=P(x2,y2);
    ans=1e9;
    dfs(-1,0);
    printf("%f\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 3224
final_rank: 3