/* Subject: Contest submission for problem #2, file 2.java */ /* cs61a-mb@imail.EECS.Berkeley.EDU */ /* Thu Sep 18 16:17:54 PDT 2003 */ /*___CONTEST_SUBMISSION___ cs61a-mb 2 */ import java.awt.Color; import java.awt.Graphics; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.io.EOFException; import java.io.InputStreamReader; import java.io.IOException; import java.io.Reader; import java.io.StreamTokenizer; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JTabbedPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; class P2 { public static void main(String[] args) { NumberStreamReader reader = new NumberStreamReader(new InputStreamReader(System.in)); ArrayList scenarios = new ArrayList(); int rectangles; try { while ((rectangles = (int) reader.readNumber()) != -1) { Scenario scenario = new Scenario( reader.readNumber(), reader.readNumber(), reader.readNumber(), reader.readNumber()); for (int rectangle = 0; rectangle < rectangles; rectangle++) { scenario.addRectangle( reader.readNumber(), reader.readNumber(), reader.readNumber(), reader.readNumber(), reader.readNumber(), reader.readNumber()); } scenarios.add(scenario); } if (args.length == 1 && args[0].equals("-gui")) { ScenarioDrawer drawer = new ScenarioDrawer(); for (Iterator iterator = scenarios.iterator(); iterator.hasNext(); ) { Scenario scenario = (Scenario) iterator.next(); drawer.addScenario(scenario); } drawer.show(); } else { for (int index = 0; index < scenarios.size(); index++) { Scenario scenario = (Scenario) scenarios.get(index); DecimalFormat format = new DecimalFormat("#.##"); String length = format.format(scenario.getShortestPath().getLength()); System.out.println("Scenario #" + (index + 1)); System.out.println(" route distance: " + length); } } } catch (IOException exception) { exception.printStackTrace(); } } } class ScenarioDrawer extends JFrame { private JTabbedPane scenarios = new JTabbedPane(); public ScenarioDrawer() { super("Scenario Drawer"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 400); getContentPane().add(scenarios); } public void addScenario(final Scenario scenario) { scenarios.addTab( "Scenario #" + (scenarios.getTabCount() + 1), new ScenarioPanel(scenario)); } } class ScenarioPanel extends JPanel implements ChangeListener { private JLabel lengthLabel = new JLabel(), zoomLabel = new JLabel("x25"); private JSlider slider = new JSlider(1, 50, 25); private Scenario scenario; public ScenarioPanel(Scenario scenario) { this.scenario = scenario; DecimalFormat format = new DecimalFormat("#.##"); String length = format.format(scenario.getShortestPath().getLength()); lengthLabel.setText("Shortest route: " + length); add(lengthLabel); slider.addChangeListener(this); add(slider); add(zoomLabel); } public void paint(Graphics graphics) { super.paint(graphics); graphics.setColor(Color.BLACK); drawLines(graphics, scenario.getLines()); graphics.setColor(Color.RED); for (Iterator iterator = scenario.getPaths().iterator(); iterator.hasNext(); ) { drawLines(graphics, (Path) iterator.next()); } graphics.setColor(Color.GREEN); drawLines(graphics, scenario.getShortestPath()); } public void stateChanged(ChangeEvent event) { zoomLabel.setText("x" + slider.getValue()); repaint(); } private void drawLines(Graphics graphics, Collection lines) { for (Iterator iterator = lines.iterator(); iterator.hasNext();) { Line2D line = (Line2D) iterator.next(); graphics.drawLine( (int) (line.getX1() * slider.getValue()), getHeight() - (int) (line.getY1() * slider.getValue()), (int) (line.getX2() * slider.getValue()), getHeight() - (int) (line.getY2() * slider.getValue())); } } } class Path extends LinkedList { double length = 0.0D; public void addStep(Line2D line) { double x = line.getX2() - line.getX1(); double y = line.getY2() - line.getY1(); length += Math.sqrt(x * x + y * y); add(line); } public double getLength() { return length; } } class Scenario { private ArrayList lines = new ArrayList(); private Point2D start, end; public Scenario(double x1, double y1, double x2, double y2) { start = new Point2D.Double(x1, y1); end = new Point2D.Double(x2, y2); } public void addRectangle( double x1, double y1, double x2, double y2, double x3, double y3) { Line2D.Double line1 = new Line2D.Double(x1, y1, x2, y2); Line2D.Double line2 = new Line2D.Double(x2, y2, x3, y3); if (arePerpendicular(line1, line2)) { double x4 = x1 + x3 - x2, y4 = y1 + y3 - y2; lines.add(line1); lines.add(line2); lines.add(new Line2D.Double(x3, y3, x4, y4)); lines.add(new Line2D.Double(x4, y4, x1, y1)); } else { addRectangle(x1, y1, x3, y3, x2, y2); } } public ArrayList getLines() { return lines; } public ArrayList getPaths() { return getPaths(start, end, new LinkedList(), new Path()); } public Path getShortestPath() { ArrayList paths = getPaths(); Path shortestPath = null; for (Iterator iterator = paths.iterator(); iterator.hasNext();) { Path path = (Path) iterator.next(); if (shortestPath == null || path.getLength() < shortestPath.getLength()) { shortestPath = path; } } return shortestPath; } private boolean arePerpendicular(Line2D line1, Line2D line2) { double line1Slope = calculateSlope(line1); double line2Slope = calculateSlope(line2); return line1Slope == -1.0D / line2Slope || (Double.isInfinite(line1Slope) && Double.isInfinite(-1.0D / line2Slope)); } private double calculateSlope(Line2D line) { return (line.getY2() - line.getY1()) / (line.getX2() - line.getX1()); } private ArrayList getPaths( Point2D start, Point2D end, LinkedList intersectedLines, Path path) { Line2D line = new Line2D.Double(start, end); ArrayList paths = new ArrayList(); boolean intersects = false; for (Iterator iterator = getLines().iterator(); iterator.hasNext();) { Line2D rectangleLine = (Line2D) iterator.next(); if (!intersectedLines.contains(rectangleLine) && line.intersectsLine(rectangleLine)) { Path path1 = (Path) path.clone(); Path path2 = (Path) path.clone(); Point2D point1 = rectangleLine.getP1(); Point2D point2 = rectangleLine.getP2(); Line2D line1 = new Line2D.Double(start, point1); Line2D line2 = new Line2D.Double(start, point2); intersectedLines.add(rectangleLine); if (!intersectsLines(line1)) { path1.addStep(new Line2D.Double(start, point1)); paths.addAll( getPaths(point1, end, intersectedLines, path1)); } if (!intersectsLines(line2)) { path2.addStep(new Line2D.Double(start, point2)); paths.addAll( getPaths(point2, end, intersectedLines, path2)); } intersects = true; } } if (!intersects && !intersectsLines(line)) { path.addStep(line); paths.add(path); } return paths; } private boolean intersectsLines(Line2D line) { for (Iterator iterator = lines.iterator(); iterator.hasNext();) { Line2D intersectedLine = (Line2D) iterator.next(); if (!(line.getP1().equals(intersectedLine.getP1()) || line.getP1().equals(intersectedLine.getP2()) || line.getP2().equals(intersectedLine.getP1()) || line.getP2().equals(intersectedLine.getP2())) && line.intersectsLine(intersectedLine)) { return true; } } return false; } } class NumberStreamReader { private StreamTokenizer tokenizer; public NumberStreamReader(Reader reader) { tokenizer = new StreamTokenizer(reader); } public double readNumber() throws IOException { tokenizer.nextToken(); switch (tokenizer.ttype) { case StreamTokenizer.TT_EOF : throw new EOFException(); case StreamTokenizer.TT_NUMBER : return tokenizer.nval; default : throw new NumberFormatException(); } } }