void ShowOptimalSolution() { if (currentInstanceMetadata == null) { return; } List <int> solution = new List <int>(); string solutionFilePath = currentInstanceMetadata.ProblemFile.Replace(".vrp", ".opt"); if (File.Exists(solutionFilePath)) { StreamReader solutionFileStream = new StreamReader(solutionFilePath); solution = VRPModel.LoadSolutionFromStream(solutionFileStream); } else if (File.Exists(PROBLEM_SOURCE)) { using (ZipArchive zip = ZipFile.Open(PROBLEM_SOURCE, ZipArchiveMode.Read)) { string fileName = Path.GetFileName(solutionFilePath); foreach (ZipArchiveEntry entry in zip.Entries) { if (entry.Name == fileName) { StreamReader solutionZipStream = new StreamReader(entry.Open()); solution = VRPModel.LoadSolutionFromStream(solutionZipStream); } } } } var oldSolutionEdges = new List <GameObject>(instance.solutionEdges); foreach (var oldEdge in oldSolutionEdges) { instance.RemoveEdgeFromSolution(oldEdge); Remove(oldEdge); } for (int i = 1; i < solution.Count; i++) { var fromNode = solution[i - 1]; var toNode = solution[i]; var edge = CreateNewEdge(instance.points[fromNode], fromNode, toNode); instance.AddEdgeToSolution(edge); } optimalLoaded = true; RefreshStateAndUpdateDisplays(); HighlightViolations(); }
void ChooseNextLevel() { // Reset everything ClearGameObjects(); Mouse.Clear(); currentInstanceMetadata = null; instance = null; truckFillBars = new List <ProgressBar>(); mouseDownPointIdx = -1; mouseDownEdge = null; activePointIdx = -1; activePointObject = null; dragEdges = new List <GameObject>(); blinkingObjects = new List <GameObject>(); originalColors = new Dictionary <GameObject, Color>(); pointToCircleObject = new Dictionary <Vector, GameObject>(); //Mouse.Listen(MouseButton.Left, ButtonState.Pressed, MenuMousePressed, "Valitse kenttä"); //TouchPanel.Listen(ButtonState.Released, OnTouchEvent, "Valitse kenttä"); problemMenu.ViewSetSelect(problemInstanceMetadata, OnSetSelected); }
public void StartGame(string problemFilePath) { optimalLoaded = false; Mouse.Listen(MouseButton.Left, ButtonState.Pressed, MouseBtnGoesDown, "Tökkää piirtääksesi reittejä"); Mouse.Listen(MouseButton.Left, ButtonState.Released, MouseBtnGoesUp, ""); Mouse.ListenMovement(0.1, MouseMoves, "Rakenna reittejä venyttämällä"); // UI trucksUsed = new IntMeter(0); trucksDisplay = CreateMeterDisplay( trucksUsed, new Vector(-Screen.Width / 4, Screen.Top - TOP_MARGIN), LoadImage("truck")); distanceTraveled = new DoubleMeter(0.0); distanceDisplay = CreateMeterDisplay( distanceTraveled, new Vector(0, Screen.Top - TOP_MARGIN), LoadImage("road")); ofBKS = new IntMeter(99); ofBKSDisplay = CreateMeterDisplay( ofBKS, new Vector(Screen.Width / 4, Screen.Top - TOP_MARGIN), LoadImage("dash")); ofBKSDisplay.IntFormatString = "{0} %"; UpdateDisplayIconPosition(ofBKSDisplay); ofBKSDisplay.IsVisible = false; // use "--" label until feasible ofBKSDisplayNA = new Label("-- %"); ofBKSDisplayNA.Position = ofBKSDisplay.Position; Add(ofBKSDisplayNA, 3); // Navigation buttons PushButton backButton = new PushButton(ofBKSDisplay.Width * 1.1, ofBKSDisplay.Height * 1.0, LoadImage("back_btn")); backButton.Clicked += () => ChooseNextLevel(); backButton.Position = new Vector(-Screen.Width / 2 + ofBKSDisplay.Height * 1.5, ofBKSDisplay.Position.Y); Add(backButton); PushButton helpButton = new PushButton(ofBKSDisplay.Width * 1.1, ofBKSDisplay.Height * 1.0, LoadImage("help_btn")); helpButton.Clicked += () => ShowHelp(); helpButton.Position = new Vector(Screen.Width / 2 - ofBKSDisplay.Height * 1.5, ofBKSDisplay.Position.Y); Add(helpButton); string problemName = Path.GetFileNameWithoutExtension(problemFilePath); if (File.Exists(problemFilePath)) { StreamReader problemFileStream = new StreamReader(problemFilePath); // The problem instance = VRPModel.LoadProblemFromStream(problemFileStream, problemName, Screen.Width - Screen.Width / SCREEN_MARGIN_WIDHT_RATIO, Screen.Height - Screen.Height / SCREEN_MARGIN_WIDHT_RATIO ); } else if (File.Exists(PROBLEM_SOURCE)) { using (ZipArchive zip = ZipFile.Open(PROBLEM_SOURCE, ZipArchiveMode.Read)) { string fileName = Path.GetFileName(problemFilePath); foreach (ZipArchiveEntry entry in zip.Entries) { if (entry.Name == fileName) { StreamReader problemZipStream = new StreamReader(entry.Open()); // The problem instance = VRPModel.LoadProblemFromStream(problemZipStream, problemName, Screen.Width - Screen.Width / SCREEN_MARGIN_WIDHT_RATIO, Screen.Height - Screen.Height / SCREEN_MARGIN_WIDHT_RATIO ); } } } } // Determine the max size of a dot dotMaxSize = Math.Min(Screen.Width / DOT_MAX_SIZE_RATIO, Screen.Height / DOT_MAX_SIZE_RATIO); for (int i = 1; i < instance.points.Count; i++) { for (int j = i + 1; j < instance.points.Count; j++) { double d = Vector.Distance(instance.points[i], instance.points[j]) * DOT_MIN_SIZE_MAX_ALLOWED_OVERLAP; if (d > DOT_MIN_SIZE_PX && d < dotMaxSize) { dotMaxSize = d; } } } for (int i = 0; i < instance.points.Count; i++) { double hcd = Math.Sqrt(Math.Max(0.5, instance.demands[i] / instance.capacity)) * dotMaxSize + BORDER_WIDTH * 2; var hitCircle = new GameObject(hcd, hcd, Shape.Circle); hitCircle.IsVisible = false; hitCircle.Position = instance.points[i]; hitCircle.Tag = i; Add(hitCircle); double d = Math.Sqrt(instance.demands[i] / instance.capacity) * dotMaxSize; var customer = new GameObject(d, d, Shape.Circle); if (i == 0) { customer.Color = DepotColor; } else { customer.Color = NotRoutedColor; } customer.Tag = "customer"; customer.Position = instance.points[i]; Add(customer, -2); while (pointToCircleObject.ContainsKey(instance.points[i])) { instance.points[i] += new Vector(DOT_MIN_SIZE_PX, DOT_MIN_SIZE_PX); } pointToCircleObject.Add(instance.points[i], customer); var border = new GameObject(d + BORDER_WIDTH * 2, d + BORDER_WIDTH * 2, Shape.Circle); border.Color = BorderColor; border.Position = instance.points[i]; Add(border, -3); } }
static public VRPModel LoadProblemFromStream(StreamReader file, string problemName, double displayWidth, double displayHeight) { VRPModel model = new VRPModel(); int N = 0; string weightStyle = "EUC_2D"; string weightFormat = "FULL_MATRIX"; string line; int xDIdx = 0; int yDIdx = 0; // indexes for EXPLICIT matrix wts TSPLibReaderState state = TSPLibReaderState.Header; while ((line = file.ReadLine()) != null) { // Check for keywords // TODO: Name, EDGE_WEIGHT_TYPE, CAPACITY if (line.Contains("NODE_COORD_SECTION") || line.Contains("DISPLAY_DATA_SECTION")) { state = TSPLibReaderState.CoordSection; continue; } else if (line.Contains("DEMAND_SECTION")) { state = TSPLibReaderState.DemandSection; continue; } else if (line.Contains("DEPOT_SECTION")) { state = TSPLibReaderState.DepotSection; continue; } else if (line.Contains("EDGE_WEIGHT_SECTION")) { model.D = new double[N, N]; state = TSPLibReaderState.WeightSection; continue; } string[] parts; switch (state) { case TSPLibReaderState.Header: if (line.Contains("CAPACITY")) { parts = line.Split(':'); model.capacity = Double.Parse(parts[1], CultureInfo.InvariantCulture); } if (line.Contains("NAME")) { parts = line.Split(':'); model.problemName = parts[1].Trim(); model.BKS_k = Int32.Parse(problemName.Split('-').Last().Replace('k', ' ')); } if (line.Contains("BEST_KNOWN")) { parts = line.Split(':'); model.BKS_val = Double.Parse(parts[1], CultureInfo.InvariantCulture); } if (line.Contains("EDGE_WEIGHT_TYPE")) { parts = line.Split(':'); weightStyle = parts[1].Trim(); } if (line.Contains("EDGE_WEIGHT_FORMAT")) { parts = line.Split(':'); weightFormat = parts[1].Trim(); if (weightFormat == "LOWER_ROW") { yDIdx = 1; } else if (weightFormat == "UPPER_ROW") { xDIdx = 1; } } if (line.Contains("DIMENSION")) { parts = line.Split(':'); N = Int32.Parse(parts[1]); } break; case TSPLibReaderState.CoordSection: parts = line.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (weightStyle == "GEO") { // id pos-x pos-y model.points.Add(new Vector( Double.Parse(parts[2], CultureInfo.InvariantCulture), Double.Parse(parts[1], CultureInfo.InvariantCulture))); } else { // id pos-x pos-y model.points.Add(new Vector( Double.Parse(parts[1], CultureInfo.InvariantCulture), Double.Parse(parts[2], CultureInfo.InvariantCulture))); } break; case TSPLibReaderState.DemandSection: parts = line.Split(' '); int id = Int32.Parse(parts[0]); // one based indexing. first is the depot. if (id == 1) { model.demands.Add(model.capacity); } else { model.demands.Add(Double.Parse(parts[1], CultureInfo.InvariantCulture)); } break; case TSPLibReaderState.WeightSection: var distances = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); foreach (var dstr in distances) { if (dstr == "") { continue; } double d = Double.Parse(dstr, CultureInfo.InvariantCulture); model.D[xDIdx, yDIdx] = d; model.D[yDIdx, xDIdx] = d; if (weightFormat == "LOWER_ROW") { xDIdx += 1; if (xDIdx == yDIdx) { yDIdx++; xDIdx = 0; } } else if (weightFormat == "UPPER_ROW") { xDIdx++; if (xDIdx == N) { yDIdx++; xDIdx = yDIdx + 1; } } else if (weightFormat == "FULL_MATRIX") { xDIdx++; if (xDIdx == N) { yDIdx++; xDIdx = 0; } } else if (weightFormat == "LOWER_DIAG_ROW") { xDIdx++; if (xDIdx == yDIdx + 1) { xDIdx = 0; yDIdx++; } } else if (weightFormat == "UPPER_DIAG_ROW") { xDIdx++; if (xDIdx == N) { yDIdx++; xDIdx = yDIdx; } } } break; default: break; } } // Calculate D (instance matrix) if needed if (model.D == null) { model.D = new double[model.points.Count, model.points.Count]; for (int i = 0; i < model.points.Count; i++) { for (int j = i; j < model.points.Count; j++) { if (i == j) { model.D[i, j] = 0.0; } else { double d = -1.0; if (weightStyle == "EUC_2D") { d = Math.Round(Math.Sqrt( // rounded to nearest integer! Math.Pow(model.points[i].X - model.points[j].X, 2) + // dx^2 Math.Pow(model.points[i].Y - model.points[j].Y, 2))); // dy^2 } else if (weightStyle == "GEO") { /* from http://stackoverflow.com/questions/4913349/ * Calculate the great circle distance between two points * on the earth (specified in decimal degrees) * The distance should be within ~0.3% of the correct value.*/ // convert decimal degrees to radians double lon1 = (Math.PI / 180) * model.points[i].X; double lat1 = (Math.PI / 180) * model.points[i].Y; double lon2 = (Math.PI / 180) * model.points[j].X; double lat2 = (Math.PI / 180) * model.points[j].Y; // haversine formula double dlon = lon2 - lon1; double dlat = lat2 - lat1; double a = Math.Pow(Math.Sin(dlat / 2), 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow(Math.Sin(dlon / 2), 2); double c = 2 * Math.Asin(Math.Sqrt(a)); double km = 6367 * c; d = km; } model.D[i, j] = d; model.D[j, i] = d; } } } } // Scale to fill the screen double minX = model.points.Min((p) => p.X); double maxX = model.points.Max((p) => p.X); double minY = model.points.Min((p) => p.Y); double maxY = model.points.Max((p) => p.Y); double scale = Math.Min(displayWidth / (maxX - minX), displayHeight / (maxY - minY)); double displayLeftOffset = (maxX - minX) * scale / 2; double displayTopOffset = (maxY - minY) * scale / 2; for (int i = 0; i < model.points.Count; i++) { Vector oldpt = model.points[i]; Vector newpt = new Vector( (oldpt.X - minX) * scale - displayLeftOffset, (oldpt.Y - minY) * scale - displayTopOffset ); model.points[i] = newpt; } // Init current solution data structures model.neighbourEdges = new List <List <GameObject> >(); foreach (var p in model.points) { model.neighbourEdges.Add(new List <GameObject>()); } model.solutionEdges = new List <GameObject>(model.points.Count); model.routeIdxForNodes = Enumerable.Repeat(-1, model.points.Count).ToArray(); return(model); }