add visualization and report
This commit is contained in:
parent
661b55ace6
commit
3a4a5f6021
282
Lab4/Algorithm.cs
Normal file
282
Lab4/Algorithm.cs
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
public class Algorithm
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Faile places_data.xlsx pateikta informacija apie lankytinas vietas (1 lentelė). Tikslas: kaip galima pigesnio maršruto sudarymas kai,
|
||||||
|
|
||||||
|
* priimama, kad kelionės tarp vietų kaina lygi kvadratinei šakniai iš kelionės atstumo;
|
||||||
|
* kelionės pradžios ir pabaigos vieta sutampa (su grįžimu atgal);
|
||||||
|
* ta pati vieta negali būti aplankyta daugiau nei vieną;
|
||||||
|
* Reikia aplankyti bet kurias 150 vietų iš pateikto sąrašo.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int pathLength = 150;
|
||||||
|
public int batchSize = 40;
|
||||||
|
public float mutationPickUniqueChance = 0.005f;
|
||||||
|
public float mutationSwapChance = 0.01f;
|
||||||
|
public float mutationPickLocalChance = 0.005f;
|
||||||
|
public float localAreaRadius = 70000.000f;
|
||||||
|
public int seed;
|
||||||
|
public int iteration = 0;
|
||||||
|
public SortedList<double, List<int>> paths;
|
||||||
|
public List<List<int>> localPlaces;
|
||||||
|
|
||||||
|
List<Place> places;
|
||||||
|
Random rand;
|
||||||
|
|
||||||
|
public Algorithm(List<Place> places, int seed)
|
||||||
|
{
|
||||||
|
this.places = places;
|
||||||
|
this.seed = seed;
|
||||||
|
rand = new Random(seed);
|
||||||
|
paths = GenerateInitialPaths(rand, places, pathLength, batchSize);
|
||||||
|
localPlaces = ComputeLocalNodes(places, localAreaRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Algorithm(List<Place> places) : this(places, (int)DateTime.Now.Ticks) { }
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
rand = new Random(seed);
|
||||||
|
paths = GenerateInitialPaths(rand, places, pathLength, batchSize);
|
||||||
|
localPlaces = ComputeLocalNodes(places, localAreaRadius);
|
||||||
|
iteration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Place
|
||||||
|
{
|
||||||
|
public string name;
|
||||||
|
public float x;
|
||||||
|
public float y;
|
||||||
|
public Place(string name, float x, float y)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetDistance(float x0, float y0, float x1, float y1)
|
||||||
|
{
|
||||||
|
float dx = x0 - x1;
|
||||||
|
float dy = y0 - y1;
|
||||||
|
return Math.Sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetDistance(Place A, Place B)
|
||||||
|
{
|
||||||
|
return GetDistance(A.x, A.y, B.x, B.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetTravalCost(Place A, Place B)
|
||||||
|
{
|
||||||
|
return Math.Sqrt(GetDistance(A, B));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Place> ReadPlacesFromTSV(string filename)
|
||||||
|
{
|
||||||
|
List<Place> cities = new List<Place>();
|
||||||
|
foreach (var line in File.ReadLines(filename))
|
||||||
|
{
|
||||||
|
string[] parts = line.Split("\t");
|
||||||
|
|
||||||
|
string name = parts[0];
|
||||||
|
float x = float.Parse(parts[2]);
|
||||||
|
float y = float.Parse(parts[3]);
|
||||||
|
cities.Add(new Place(name, x, y));
|
||||||
|
}
|
||||||
|
return cities;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning 'PickUnqiueNode' could get stuck in an infinite loop, if there are not enough places
|
||||||
|
public static int PickUnqiueNode(Random rand, List<int> path, int placesCount)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int num = rand.Next(0, placesCount);
|
||||||
|
if (!path.Contains(num))
|
||||||
|
{
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<List<int>> ComputeLocalNodes(List<Place> places, float localRadius)
|
||||||
|
{
|
||||||
|
var locals = new List<List<int>>(places.Count);
|
||||||
|
for (int i = 0; i < places.Count; i++)
|
||||||
|
{
|
||||||
|
var nodeLocals = new List<int>();
|
||||||
|
for (int j = 0; j < places.Count; j++)
|
||||||
|
{
|
||||||
|
if (i == j) continue;
|
||||||
|
|
||||||
|
if (GetDistance(places[i], places[j]) < localRadius)
|
||||||
|
{
|
||||||
|
nodeLocals.Add(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locals.Add(nodeLocals);
|
||||||
|
}
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int PickUniqueLocalNode(Random rand, List<int> path, List<int> localPlaces)
|
||||||
|
{
|
||||||
|
if (localPlaces.Count == 0) return -1;
|
||||||
|
|
||||||
|
int retryCount = 5;
|
||||||
|
for (int i = 0; i < retryCount; i++)
|
||||||
|
{
|
||||||
|
int idx = rand.Next(0, localPlaces.Count);
|
||||||
|
int place = localPlaces[idx];
|
||||||
|
if (!path.Contains(place))
|
||||||
|
{
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<int> GenerateRandomPath(Random rand, int size, int placesCount)
|
||||||
|
{
|
||||||
|
List<int> path = new List<int>(size);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
path.Add(PickUnqiueNode(rand, path, placesCount));
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetPathCost(List<int> path, List<Place> places)
|
||||||
|
{
|
||||||
|
double cost = 0;
|
||||||
|
for (int i = 0; i < path.Count - 1; i++)
|
||||||
|
{
|
||||||
|
int from = path[i];
|
||||||
|
int to = path[i + 1];
|
||||||
|
cost += GetTravalCost(places[from], places[to]);
|
||||||
|
}
|
||||||
|
cost += GetTravalCost(places[path.First()], places[path.Last()]);
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<int> SplicePaths(Random rand, List<int> A, List<int> B)
|
||||||
|
{
|
||||||
|
Debug.Assert(A.Count == B.Count);
|
||||||
|
|
||||||
|
List<int> spliced = new List<int>(A.Count);
|
||||||
|
for (int i = 0; i < A.Count - 1; i++)
|
||||||
|
{
|
||||||
|
spliced[i] = rand.Next(0, 2) == 0 ? A[i] : B[i];
|
||||||
|
}
|
||||||
|
return spliced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SortedList<double, List<int>> GenerateInitialPaths(Random rand, List<Place> places, int pathLength, int pathCount)
|
||||||
|
{
|
||||||
|
var paths = new SortedList<double, List<int>>();
|
||||||
|
for (int i = 0; i < pathCount; i++)
|
||||||
|
{
|
||||||
|
var path = GenerateRandomPath(rand, pathLength, places.Count);
|
||||||
|
var cost = GetPathCost(path, places);
|
||||||
|
paths.Add(cost, path);
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SetLocalRadius(float radius)
|
||||||
|
{
|
||||||
|
localAreaRadius = radius;
|
||||||
|
localPlaces = ComputeLocalNodes(places, localAreaRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MutatePath(List<int> path)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < path.Count; i++)
|
||||||
|
{
|
||||||
|
if (rand.NextSingle() < mutationPickUniqueChance)
|
||||||
|
{
|
||||||
|
path[i] = PickUnqiueNode(rand, path, places.Count);
|
||||||
|
}
|
||||||
|
if (rand.NextSingle() < mutationSwapChance)
|
||||||
|
{
|
||||||
|
int idx1 = rand.Next(0, path.Count);
|
||||||
|
int idx2 = rand.Next(0, path.Count);
|
||||||
|
|
||||||
|
(path[idx2], path[idx1]) = (path[idx1], path[idx2]);
|
||||||
|
}
|
||||||
|
if (rand.NextSingle() < mutationPickLocalChance)
|
||||||
|
{
|
||||||
|
int localNode = PickUniqueLocalNode(rand, path, localPlaces[i]);
|
||||||
|
if (localNode != -1)
|
||||||
|
{
|
||||||
|
path[i] = localNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IterateSolution()
|
||||||
|
{
|
||||||
|
double bestScore = paths.First().Key;
|
||||||
|
double worstScore = paths.Last().Key;
|
||||||
|
|
||||||
|
var removedPaths = new List<double>();
|
||||||
|
var parentPool = new List<List<int>>();
|
||||||
|
foreach (var entry in paths)
|
||||||
|
{
|
||||||
|
double probability = (entry.Key - bestScore) / (worstScore - bestScore);
|
||||||
|
if (rand.NextSingle() >= probability)
|
||||||
|
{
|
||||||
|
parentPool.Add(entry.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removedPaths.Add(entry.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in removedPaths)
|
||||||
|
{
|
||||||
|
paths.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (batchSize > paths.Count)
|
||||||
|
{
|
||||||
|
var parentIdx = rand.Next(0, parentPool.Count);
|
||||||
|
var parent = parentPool[parentIdx];
|
||||||
|
var child = new List<int>(parent);
|
||||||
|
MutatePath(child);
|
||||||
|
var cost = GetPathCost(child, places);
|
||||||
|
if (!paths.ContainsKey(cost))
|
||||||
|
{
|
||||||
|
paths.Add(cost, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IterateSolutionFor(float seconds)
|
||||||
|
{
|
||||||
|
var stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
while (stopwatch.ElapsedMilliseconds < seconds * 1000)
|
||||||
|
{
|
||||||
|
IterateSolution();
|
||||||
|
}
|
||||||
|
stopwatch.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tuple<double, List<int>> GetBestPath()
|
||||||
|
{
|
||||||
|
var entry = paths.First();
|
||||||
|
return Tuple.Create(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Lab4/Ataskaita.docx
Normal file
BIN
Lab4/Ataskaita.docx
Normal file
Binary file not shown.
94
Lab4/EditorWindow.cs
Normal file
94
Lab4/EditorWindow.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Lab4;
|
||||||
|
using Raylib_cs;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
class EditorWindow
|
||||||
|
{
|
||||||
|
private bool showDemoWindow = false;
|
||||||
|
public ImFontPtr font1;
|
||||||
|
|
||||||
|
MainWindow win;
|
||||||
|
|
||||||
|
public EditorWindow(MainWindow win)
|
||||||
|
{
|
||||||
|
this.win = win;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float dt)
|
||||||
|
{
|
||||||
|
ImGui.PushFont(font1);
|
||||||
|
|
||||||
|
if (showDemoWindow)
|
||||||
|
{
|
||||||
|
// Normally user code doesn't need/want to call this because positions are saved in .ini file anyway.
|
||||||
|
// Here we just want to make the demo initial state a bit more friendly!
|
||||||
|
ImGui.SetNextWindowPos(new Vector2(650, 20), ImGuiCond.FirstUseEver);
|
||||||
|
ImGui.ShowDemoWindow(ref showDemoWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Begin("Editor", ImGuiWindowFlags.None))
|
||||||
|
{
|
||||||
|
var algo = win.algo;
|
||||||
|
|
||||||
|
var mouse = win.GetMousePosition();
|
||||||
|
if (win.isIterationRunning)
|
||||||
|
{
|
||||||
|
if (ImGui.Button(win.iterationPaused ? "Continue" : "Pause"))
|
||||||
|
{
|
||||||
|
win.iterationPaused = !win.iterationPaused;
|
||||||
|
}
|
||||||
|
if (ImGui.Button("Stop"))
|
||||||
|
{
|
||||||
|
win.Stop();
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Start"))
|
||||||
|
{
|
||||||
|
win.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.Text($"Mouse: {mouse.X:f3} {mouse.Y:f3}");
|
||||||
|
ImGui.Text($"Iteration: {algo.iteration}");
|
||||||
|
ImGui.Text($"Runtime: {win.interationTime:f3}s");
|
||||||
|
|
||||||
|
ImGuiInputTextFlags inputFlags = 0;
|
||||||
|
if (win.isIterationRunning)
|
||||||
|
{
|
||||||
|
uint bg = ImGui.GetColorU32(ImGuiCol.FrameBg);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.FrameBg, 0x44000000 | (bg & 0x00FFFFFF));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled));
|
||||||
|
inputFlags = ImGuiInputTextFlags.ReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.InputInt("Seed", ref algo.seed, 1, 1, ImGuiInputTextFlags.CharsDecimal | inputFlags);
|
||||||
|
ImGui.InputInt("Batch size", ref algo.batchSize, 1, 1, ImGuiInputTextFlags.CharsDecimal | inputFlags);
|
||||||
|
|
||||||
|
if (win.isIterationRunning)
|
||||||
|
{
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
var localRadius = algo.localAreaRadius;
|
||||||
|
if (ImGui.InputFloat("Local area radius", ref localRadius))
|
||||||
|
{
|
||||||
|
Console.WriteLine(localRadius);
|
||||||
|
win.algo.SetLocalRadius(localRadius);
|
||||||
|
}
|
||||||
|
ImGui.SliderFloat("Mutation swap chance", ref algo.mutationSwapChance, 0, 0.3f);
|
||||||
|
ImGui.SliderFloat("Mutation repick chance", ref algo.mutationPickUniqueChance, 0, 0.3f);
|
||||||
|
ImGui.SliderFloat("Mutation repick local chance", ref algo.mutationPickLocalChance, 0, 0.3f);
|
||||||
|
|
||||||
|
ImGui.Text($"Best path score: {win.bestScore}");
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopFont();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
323
Lab4/ImguiController.cs
Normal file
323
Lab4/ImguiController.cs
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
using ImGuiNET;
|
||||||
|
using Raylib_cs;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
public class ImguiController : IDisposable
|
||||||
|
{
|
||||||
|
IntPtr context;
|
||||||
|
Texture2D fontTexture;
|
||||||
|
Vector2 scaleFactor = Vector2.One;
|
||||||
|
|
||||||
|
public ImguiController()
|
||||||
|
{
|
||||||
|
context = ImGui.CreateContext();
|
||||||
|
ImGui.SetCurrentContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ImGui.DestroyContext(context);
|
||||||
|
Raylib.UnloadTexture(fontTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a texture and loads the font data from ImGui.
|
||||||
|
/// </summary>
|
||||||
|
public void Load(int width, int height)
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
io.Fonts.AddFontDefault();
|
||||||
|
|
||||||
|
Resize(width, height);
|
||||||
|
LoadFontTexture();
|
||||||
|
SetupInput();
|
||||||
|
ImGui.NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe void LoadFontTexture()
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders.
|
||||||
|
// If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
io.Fonts.GetTexDataAsRGBA32(out byte* pixels, out int width, out int height);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
Image image = new Image
|
||||||
|
{
|
||||||
|
data = pixels,
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
mipmaps = 1,
|
||||||
|
format = PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
|
||||||
|
};
|
||||||
|
fontTexture = Raylib.LoadTextureFromImage(image);
|
||||||
|
|
||||||
|
// Store texture id in imgui font
|
||||||
|
io.Fonts.SetTexID(new IntPtr(fontTexture.id));
|
||||||
|
|
||||||
|
// Clears font data on the CPU side
|
||||||
|
io.Fonts.ClearTexData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupInput()
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Setup config flags
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
|
||||||
|
|
||||||
|
// Setup back-end capabilities flags
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos;
|
||||||
|
|
||||||
|
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||||
|
io.KeyMap[(int)ImGuiKey.Tab] = (int)KeyboardKey.KEY_TAB;
|
||||||
|
io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)KeyboardKey.KEY_LEFT;
|
||||||
|
io.KeyMap[(int)ImGuiKey.RightArrow] = (int)KeyboardKey.KEY_RIGHT;
|
||||||
|
io.KeyMap[(int)ImGuiKey.UpArrow] = (int)KeyboardKey.KEY_UP;
|
||||||
|
io.KeyMap[(int)ImGuiKey.DownArrow] = (int)KeyboardKey.KEY_DOWN;
|
||||||
|
io.KeyMap[(int)ImGuiKey.PageUp] = (int)KeyboardKey.KEY_PAGE_UP;
|
||||||
|
io.KeyMap[(int)ImGuiKey.PageDown] = (int)KeyboardKey.KEY_PAGE_DOWN;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Home] = (int)KeyboardKey.KEY_HOME;
|
||||||
|
io.KeyMap[(int)ImGuiKey.End] = (int)KeyboardKey.KEY_END;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Insert] = (int)KeyboardKey.KEY_INSERT;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Delete] = (int)KeyboardKey.KEY_DELETE;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Backspace] = (int)KeyboardKey.KEY_BACKSPACE;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Space] = (int)KeyboardKey.KEY_SPACE;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Enter] = (int)KeyboardKey.KEY_ENTER;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Escape] = (int)KeyboardKey.KEY_ESCAPE;
|
||||||
|
io.KeyMap[(int)ImGuiKey.A] = (int)KeyboardKey.KEY_A;
|
||||||
|
io.KeyMap[(int)ImGuiKey.C] = (int)KeyboardKey.KEY_C;
|
||||||
|
io.KeyMap[(int)ImGuiKey.V] = (int)KeyboardKey.KEY_V;
|
||||||
|
io.KeyMap[(int)ImGuiKey.X] = (int)KeyboardKey.KEY_X;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Y] = (int)KeyboardKey.KEY_Y;
|
||||||
|
io.KeyMap[(int)ImGuiKey.Z] = (int)KeyboardKey.KEY_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update imgui internals(input, frameData)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt"></param>
|
||||||
|
public void Update(float dt)
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
|
||||||
|
io.DisplayFramebufferScale = Vector2.One;
|
||||||
|
io.DeltaTime = dt;
|
||||||
|
|
||||||
|
UpdateKeyboard();
|
||||||
|
UpdateMouse();
|
||||||
|
|
||||||
|
if (Raylib.IsWindowResized())
|
||||||
|
{
|
||||||
|
Resize(Raylib.GetScreenWidth(), Raylib.GetScreenHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resize imgui display
|
||||||
|
/// </summary>
|
||||||
|
public void Resize(int width, int height)
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
io.DisplaySize = new Vector2(width, height) / scaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateKeyboard()
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Modifiers are not reliable across systems
|
||||||
|
io.KeyCtrl = io.KeysDown[(int)KeyboardKey.KEY_LEFT_CONTROL] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_CONTROL];
|
||||||
|
io.KeyShift = io.KeysDown[(int)KeyboardKey.KEY_LEFT_SHIFT] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_SHIFT];
|
||||||
|
io.KeyAlt = io.KeysDown[(int)KeyboardKey.KEY_LEFT_ALT] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_ALT];
|
||||||
|
io.KeySuper = io.KeysDown[(int)KeyboardKey.KEY_LEFT_SUPER] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_SUPER];
|
||||||
|
|
||||||
|
// Key states
|
||||||
|
for (int i = (int)KeyboardKey.KEY_SPACE; i < (int)KeyboardKey.KEY_KB_MENU + 1; i++)
|
||||||
|
{
|
||||||
|
io.KeysDown[i] = Raylib.IsKeyDown((KeyboardKey)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key input
|
||||||
|
int keyPressed = Raylib.GetCharPressed();
|
||||||
|
if (keyPressed != 0)
|
||||||
|
{
|
||||||
|
io.AddInputCharacter((uint)keyPressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateMouse()
|
||||||
|
{
|
||||||
|
ImGuiIOPtr io = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Store button states
|
||||||
|
for (int i = 0; i < io.MouseDown.Count; i++)
|
||||||
|
{
|
||||||
|
io.MouseDown[i] = Raylib.IsMouseButtonDown((MouseButton)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse scroll
|
||||||
|
io.MouseWheel += Raylib.GetMouseWheelMove();
|
||||||
|
|
||||||
|
// Mouse position
|
||||||
|
Vector2 mousePosition = io.MousePos;
|
||||||
|
bool focused = Raylib.IsWindowFocused();
|
||||||
|
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
{
|
||||||
|
Raylib.SetMousePosition((int)mousePosition.X, (int)mousePosition.Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
io.MousePos = Raylib.GetMousePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse cursor state
|
||||||
|
if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) == 0 || Raylib.IsCursorHidden())
|
||||||
|
{
|
||||||
|
ImGuiMouseCursor cursor = ImGui.GetMouseCursor();
|
||||||
|
if (cursor == ImGuiMouseCursor.None || io.MouseDrawCursor)
|
||||||
|
{
|
||||||
|
Raylib.HideCursor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Raylib.ShowCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the geometry as set up by ImGui and sends it to the graphics device
|
||||||
|
/// </summary>
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
ImGui.Render();
|
||||||
|
RenderCommandLists(ImGui.GetDrawData());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a Color struct from hexadecimal value
|
||||||
|
Color GetColor(uint hexValue)
|
||||||
|
{
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
color.r = (byte)(hexValue & 0xFF);
|
||||||
|
color.g = (byte)((hexValue >> 8) & 0xFF);
|
||||||
|
color.b = (byte)((hexValue >> 16) & 0xFF);
|
||||||
|
color.a = (byte)((hexValue >> 24) & 0xFF);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTriangleVertex(ImDrawVertPtr idxVert)
|
||||||
|
{
|
||||||
|
Color c = GetColor(idxVert.col);
|
||||||
|
Rlgl.rlColor4ub(c.r, c.g, c.b, c.a);
|
||||||
|
Rlgl.rlTexCoord2f(idxVert.uv.X, idxVert.uv.Y);
|
||||||
|
Rlgl.rlVertex2f(idxVert.pos.X, idxVert.pos.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the imgui triangle data
|
||||||
|
void DrawTriangles(uint count, int idxOffset, int vtxOffset, ImVector<ushort> idxBuffer, ImPtrVector<ImDrawVertPtr> idxVert, IntPtr textureId)
|
||||||
|
{
|
||||||
|
ushort index = 0;
|
||||||
|
ImDrawVertPtr vertex;
|
||||||
|
|
||||||
|
if (Rlgl.rlCheckRenderBatchLimit((int)count * 3))
|
||||||
|
{
|
||||||
|
Rlgl.rlDrawRenderBatchActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rlgl.rlBegin(DrawMode.TRIANGLES);
|
||||||
|
Rlgl.rlSetTexture((uint)textureId);
|
||||||
|
|
||||||
|
for (int i = 0; i <= (count - 3); i += 3)
|
||||||
|
{
|
||||||
|
index = idxBuffer[idxOffset + i];
|
||||||
|
vertex = idxVert[vtxOffset + index];
|
||||||
|
DrawTriangleVertex(vertex);
|
||||||
|
|
||||||
|
index = idxBuffer[idxOffset + i + 1];
|
||||||
|
vertex = idxVert[vtxOffset + index];
|
||||||
|
DrawTriangleVertex(vertex);
|
||||||
|
|
||||||
|
index = idxBuffer[idxOffset + i + 2];
|
||||||
|
vertex = idxVert[vtxOffset + index];
|
||||||
|
DrawTriangleVertex(vertex);
|
||||||
|
}
|
||||||
|
Rlgl.rlEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderCommandLists(ImDrawDataPtr data)
|
||||||
|
{
|
||||||
|
// Scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fbWidth = (int)(data.DisplaySize.X * data.FramebufferScale.X);
|
||||||
|
int fbHeight = (int)(data.DisplaySize.Y * data.FramebufferScale.Y);
|
||||||
|
|
||||||
|
// Avoid rendering if display is minimized or if the command list is empty
|
||||||
|
if (fbWidth <= 0 || fbHeight <= 0 || data.CmdListsCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rlgl.rlDrawRenderBatchActive();
|
||||||
|
Rlgl.rlDisableBackfaceCulling();
|
||||||
|
Rlgl.rlEnableScissorTest();
|
||||||
|
|
||||||
|
data.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale);
|
||||||
|
|
||||||
|
for (int n = 0; n < data.CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
int idxOffset = 0;
|
||||||
|
ImDrawListPtr cmdList = data.CmdListsRange[n];
|
||||||
|
|
||||||
|
// Vertex buffer and index buffer generated by DearImGui
|
||||||
|
ImPtrVector<ImDrawVertPtr> vtxBuffer = cmdList.VtxBuffer;
|
||||||
|
ImVector<ushort> idxBuffer = cmdList.IdxBuffer;
|
||||||
|
|
||||||
|
for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++)
|
||||||
|
{
|
||||||
|
ImDrawCmdPtr pcmd = cmdList.CmdBuffer[cmdi];
|
||||||
|
|
||||||
|
// Scissor rect
|
||||||
|
Vector2 pos = data.DisplayPos;
|
||||||
|
int rectX = (int)((pcmd.ClipRect.X - pos.X) * data.FramebufferScale.X);
|
||||||
|
int rectY = (int)((pcmd.ClipRect.Y - pos.Y) * data.FramebufferScale.Y);
|
||||||
|
int rectW = (int)((pcmd.ClipRect.Z - rectX) * data.FramebufferScale.Y);
|
||||||
|
int rectH = (int)((pcmd.ClipRect.W - rectY) * data.FramebufferScale.Y);
|
||||||
|
Rlgl.rlScissor(rectX, Raylib.GetScreenHeight() - (rectY + rectH), rectW, rectH);
|
||||||
|
|
||||||
|
if (pcmd.UserCallback != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// pcmd.UserCallback(cmdList, pcmd);
|
||||||
|
idxOffset += (int)pcmd.ElemCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawTriangles(pcmd.ElemCount, idxOffset, (int)pcmd.VtxOffset, idxBuffer, vtxBuffer, pcmd.TextureId);
|
||||||
|
idxOffset += (int)pcmd.ElemCount;
|
||||||
|
Rlgl.rlDrawRenderBatchActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rlgl.rlSetTexture(0);
|
||||||
|
Rlgl.rlDisableScissorTest();
|
||||||
|
Rlgl.rlEnableBackfaceCulling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@ -21,6 +22,8 @@
|
|||||||
<None Update="places.tsv">
|
<None Update="places.tsv">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<PackageReference Include="Raylib-cs" Version="4.5.0" />
|
||||||
|
<PackageReference Include="ImGui.NET" Version="1.78.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
198
Lab4/MainWindow.cs
Normal file
198
Lab4/MainWindow.cs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Raylib_cs;
|
||||||
|
using static Lab4.Algorithm;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
public class MainWindow
|
||||||
|
{
|
||||||
|
public Algorithm algo;
|
||||||
|
List<Place> places;
|
||||||
|
public int screenWidth;
|
||||||
|
public int screenHeight;
|
||||||
|
|
||||||
|
public float interationTime = 0;
|
||||||
|
Task? iterationTask;
|
||||||
|
|
||||||
|
public List<int>? bestPath;
|
||||||
|
public double bestScore = 0;
|
||||||
|
public bool isIterationRunning = false;
|
||||||
|
|
||||||
|
public bool iterationPaused = false;
|
||||||
|
|
||||||
|
RaylibDrawContext ctx;
|
||||||
|
|
||||||
|
ScoreHistWindow scoreHist;
|
||||||
|
|
||||||
|
public MainWindow(int screenWidth, int screenHeight, List<Place> places)
|
||||||
|
{
|
||||||
|
this.places = places;
|
||||||
|
algo = new Algorithm(places);
|
||||||
|
scoreHist = new ScoreHistWindow(this);
|
||||||
|
|
||||||
|
this.screenWidth = screenWidth;
|
||||||
|
this.screenHeight = screenHeight;
|
||||||
|
|
||||||
|
{
|
||||||
|
ctx = new RaylibDrawContext();
|
||||||
|
|
||||||
|
const int screenMargin = 50;
|
||||||
|
|
||||||
|
var (minX, maxX, minY, maxY) = GetCoordinateBounds(places);
|
||||||
|
var rangeX = maxX - minX;
|
||||||
|
var rangeY = maxY - minY;
|
||||||
|
float scale = Math.Min((screenWidth - screenMargin * 2) / rangeX, (screenHeight - screenMargin * 2) / rangeY);
|
||||||
|
ctx.Scale(scale, scale);
|
||||||
|
ctx.Translate(-screenMargin, -screenMargin);
|
||||||
|
ctx.Translate(minX * scale, minY * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
algo.Reset();
|
||||||
|
scoreHist.Reset();
|
||||||
|
isIterationRunning = true;
|
||||||
|
iterationPaused = false;
|
||||||
|
interationTime = 0;
|
||||||
|
iterationTask = new Task(() => {
|
||||||
|
while (isIterationRunning)
|
||||||
|
{
|
||||||
|
if (!iterationPaused)
|
||||||
|
{
|
||||||
|
algo.IterateSolution();
|
||||||
|
var best = algo.GetBestPath();
|
||||||
|
bestScore = best.Item1;
|
||||||
|
bestPath = best.Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
iterationTask.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
isIterationRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tuple<float, float, float, float> GetCoordinateBounds(List<Place> places)
|
||||||
|
{
|
||||||
|
float minX = places[0].x;
|
||||||
|
float maxX = places[0].x;
|
||||||
|
float minY = places[0].y;
|
||||||
|
float maxY = places[0].y;
|
||||||
|
|
||||||
|
for (int i = 1; i < places.Count; i++)
|
||||||
|
{
|
||||||
|
minX = Math.Min(minX, places[i].x);
|
||||||
|
maxX = Math.Max(maxX, places[i].x);
|
||||||
|
minY = Math.Min(minY, places[i].y);
|
||||||
|
maxY = Math.Max(maxY, places[i].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Tuple.Create(minX, maxX, minY, maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawPath(RaylibDrawContext ctx, List<int> path, List<Place> places)
|
||||||
|
{
|
||||||
|
Color color = Color.GREEN;
|
||||||
|
for (int i = 0; i < path.Count - 1; i++)
|
||||||
|
{
|
||||||
|
var place0 = places[path[i + 0]];
|
||||||
|
var place1 = places[path[i + 1]];
|
||||||
|
ctx.DrawLine(place0.x, place0.y, place1.x, place1.y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 GetMousePosition()
|
||||||
|
{
|
||||||
|
return ctx.TransformToLocalSpace(Raylib.GetMousePosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Place? GetNearestPlaceToMouse()
|
||||||
|
{
|
||||||
|
if (places.Count == 0) return null;
|
||||||
|
|
||||||
|
var mouse = GetMousePosition();
|
||||||
|
var mearest = places.First();
|
||||||
|
double nearestDistance = GetDistance(mearest.x, mearest.y, mouse.X, mouse.Y);
|
||||||
|
foreach (var place in places)
|
||||||
|
{
|
||||||
|
var distance = GetDistance(place.x, place.y, mouse.X, mouse.Y);
|
||||||
|
if (distance < nearestDistance)
|
||||||
|
{
|
||||||
|
nearestDistance = distance;
|
||||||
|
mearest = place;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void Run()
|
||||||
|
{
|
||||||
|
Raylib.SetTraceLogCallback(&Logging.LogConsole);
|
||||||
|
Raylib.SetConfigFlags(ConfigFlags.FLAG_VSYNC_HINT | ConfigFlags.FLAG_WINDOW_RESIZABLE);
|
||||||
|
Raylib.InitWindow(this.screenWidth, this.screenHeight, "IP Užduotis");
|
||||||
|
Raylib.SetTargetFPS(60);
|
||||||
|
|
||||||
|
Raylib.InitAudioDevice();
|
||||||
|
|
||||||
|
ImguiController controller = new ImguiController();
|
||||||
|
EditorWindow editor = new EditorWindow(this);
|
||||||
|
|
||||||
|
controller.Load(screenWidth, screenHeight);
|
||||||
|
while (!Raylib.WindowShouldClose())
|
||||||
|
{
|
||||||
|
// Update
|
||||||
|
float dt = Raylib.GetFrameTime();
|
||||||
|
controller.Update(dt);
|
||||||
|
editor.Update(dt);
|
||||||
|
scoreHist.Update(dt);
|
||||||
|
if (isIterationRunning && !iterationPaused)
|
||||||
|
{
|
||||||
|
interationTime += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
Raylib.BeginDrawing();
|
||||||
|
Raylib.ClearBackground(Color.RAYWHITE);
|
||||||
|
|
||||||
|
foreach (var place in places)
|
||||||
|
{
|
||||||
|
ctx.DrawCircle(place.x, place.y, 2000, Color.RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestPath != null)
|
||||||
|
{
|
||||||
|
DrawPath(ctx, bestPath, places);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var nearest = GetNearestPlaceToMouse();
|
||||||
|
if (nearest != null)
|
||||||
|
{
|
||||||
|
var mouse = GetMousePosition();
|
||||||
|
ctx.DrawLine(nearest.x, nearest.y, mouse.X, mouse.Y, Color.BLUE);
|
||||||
|
ctx.DrawCircleLines(nearest.x, nearest.y, algo.localAreaRadius, Color.BLUE);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
controller.Draw();
|
||||||
|
|
||||||
|
Raylib.EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
controller.Dispose();
|
||||||
|
Raylib.CloseAudioDevice();
|
||||||
|
Raylib.CloseWindow();
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
194
Lab4/Program.cs
194
Lab4/Program.cs
@ -1,197 +1,27 @@
|
|||||||
using System.Diagnostics;
|
using Microsoft.VisualBasic;
|
||||||
using System.IO;
|
using Raylib_cs;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Lab4
|
namespace Lab4
|
||||||
{
|
{
|
||||||
class Place
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public float x;
|
|
||||||
public float y;
|
|
||||||
public Place(string name, float x, float y)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double GetDistance(Place A, Place B)
|
static unsafe void Main(string[] args)
|
||||||
{
|
{
|
||||||
float dx = A.x - B.x;
|
var places = Algorithm.ReadPlacesFromTSV("places.tsv");
|
||||||
float dy = A.y - B.y;
|
|
||||||
return Math.Sqrt(dx * dx + dy * dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double GetTravalCost(Place A, Place B)
|
var win = new MainWindow(1280, 720, places);
|
||||||
{
|
win.Run();
|
||||||
return Math.Sqrt(GetDistance(A, B));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Place> ReadPlacesFromTSV(string filename)
|
//var algo = new Algorithm(places);
|
||||||
{
|
//algo.IterateSolutionFor(1);
|
||||||
List<Place> cities = new List<Place>();
|
//Console.WriteLine("Best after {0} iterations is {1}", algo.iteration, algo.GetBestPath().Item1);
|
||||||
foreach (var line in File.ReadLines(filename))
|
//Console.WriteLine("Seed: {0}", algo.seed);
|
||||||
{
|
|
||||||
string[] parts = line.Split("\t");
|
|
||||||
|
|
||||||
string name = parts[0];
|
|
||||||
float x = float.Parse(parts[2]);
|
|
||||||
float y = float.Parse(parts[3]);
|
|
||||||
cities.Add(new Place(name, x, y));
|
|
||||||
}
|
|
||||||
return cities;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning 'PickUnqiueNode' could get stuck in an infinite loop, if there are not enough places
|
|
||||||
public static int PickUnqiueNode(Random rand, List<int> path, int placesCount)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int num = rand.Next(0, placesCount);
|
|
||||||
if (!path.Contains(num))
|
|
||||||
{
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<int> GenerateRandomPath(Random rand, int size, int placesCount)
|
|
||||||
{
|
|
||||||
List<int> path = new List<int>(size);
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
path.Add(PickUnqiueNode(rand, path, placesCount));
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double GetPathCost(List<int> path, List<Place> places)
|
|
||||||
{
|
|
||||||
double cost = 0;
|
|
||||||
for (int i = 0; i < path.Count-1; i++)
|
|
||||||
{
|
|
||||||
int from = path[i];
|
|
||||||
int to = path[i+1];
|
|
||||||
cost += GetTravalCost(places[from], places[to]);
|
|
||||||
}
|
|
||||||
cost += GetTravalCost(places[path.First()], places[path.Last()]);
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<int> SplicePaths(Random rand, List<int> A, List<int> B)
|
|
||||||
{
|
|
||||||
Debug.Assert(A.Count == B.Count);
|
|
||||||
|
|
||||||
List<int> spliced = new List<int>(A.Count);
|
|
||||||
for (int i = 0; i < A.Count-1; i++)
|
|
||||||
{
|
|
||||||
spliced[i] = rand.Next(0, 2) == 0 ? A[i] : B[i];
|
|
||||||
}
|
|
||||||
return spliced;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void MutatePath(Random rand, List<int> path, float mutationPickUniqueChance, float mutationSwapChance, int placesCount)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < path.Count; i++)
|
|
||||||
{
|
|
||||||
if (rand.NextSingle() < mutationPickUniqueChance) {
|
|
||||||
path[i] = PickUnqiueNode(rand, path, placesCount);
|
|
||||||
}
|
|
||||||
if (rand.NextSingle() < mutationSwapChance) {
|
|
||||||
int idx1 = rand.Next(0, path.Count);
|
|
||||||
int idx2 = rand.Next(0, path.Count);
|
|
||||||
|
|
||||||
(path[idx2], path[idx1]) = (path[idx1], path[idx2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Main(string[] args)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Faile places_data.xlsx pateikta informacija apie lankytinas vietas (1 lentelė). Tikslas: kaip galima pigesnio maršruto sudarymas kai,
|
|
||||||
|
|
||||||
* priimama, kad kelionės tarp vietų kaina lygi kvadratinei šakniai iš kelionės atstumo;
|
|
||||||
* kelionės pradžios ir pabaigos vieta sutampa (su grįžimu atgal);
|
|
||||||
* ta pati vieta negali būti aplankyta daugiau nei vieną;
|
|
||||||
* Reikia aplankyti bet kurias 150 vietų iš pateikto sąrašo.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int pathLength = 150;
|
|
||||||
int batchSize = 50;
|
|
||||||
int timeLimitMs = 60 * 1000;
|
|
||||||
float mutationPickUniqueChance = 0.05f;
|
|
||||||
float mutationSwapChance = 0.05f;
|
|
||||||
|
|
||||||
int seed = (int)DateTime.Now.Ticks;
|
|
||||||
Random rand = new Random(seed);
|
|
||||||
|
|
||||||
var places = ReadPlacesFromTSV("places.tsv");
|
|
||||||
|
|
||||||
var bestPaths = new SortedList<double, List<int>>();
|
|
||||||
for (int i = 0; i < batchSize; i++)
|
|
||||||
{
|
|
||||||
var path = GenerateRandomPath(rand, pathLength, places.Count);
|
|
||||||
var cost = GetPathCost(path, places);
|
|
||||||
bestPaths.Add(cost, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
var stopwatch = new Stopwatch();
|
|
||||||
int iteration = 0;
|
|
||||||
stopwatch.Start();
|
|
||||||
while (stopwatch.ElapsedMilliseconds < timeLimitMs)
|
|
||||||
{
|
|
||||||
double bestScore = bestPaths.First().Key;
|
|
||||||
double worstScore = bestPaths.Last().Key;
|
|
||||||
|
|
||||||
if (iteration % 200 == 0)
|
|
||||||
{
|
|
||||||
//Console.WriteLine("At {0}, best '{1}', worst '{2}'", iteration, bestScore, worstScore);
|
|
||||||
}
|
|
||||||
|
|
||||||
var removedPaths = new List<double>();
|
|
||||||
var parentPool = new List<List<int>>();
|
|
||||||
foreach (var entry in bestPaths)
|
|
||||||
{
|
|
||||||
double probability = (entry.Key - bestScore) / (worstScore - bestScore);
|
|
||||||
if (rand.NextSingle() >= probability) {
|
|
||||||
parentPool.Add(entry.Value);
|
|
||||||
} else {
|
|
||||||
removedPaths.Add(entry.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var key in removedPaths)
|
|
||||||
{
|
|
||||||
bestPaths.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (batchSize > bestPaths.Count)
|
|
||||||
{
|
|
||||||
var parentIdx = rand.Next(0, parentPool.Count);
|
|
||||||
var parent = parentPool[parentIdx];
|
|
||||||
var child = new List<int>(parent);
|
|
||||||
MutatePath(rand, child, mutationPickUniqueChance, mutationSwapChance, places.Count);
|
|
||||||
var cost = GetPathCost(child, places);
|
|
||||||
if (!bestPaths.ContainsKey(cost)) {
|
|
||||||
bestPaths.Add(cost, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iteration++;
|
|
||||||
}
|
|
||||||
stopwatch.Stop();
|
|
||||||
|
|
||||||
Console.WriteLine("Best after {0} iterations is {1}", iteration, bestPaths.First().Key);
|
|
||||||
Console.WriteLine("Time taken: {0}ms", stopwatch.ElapsedMilliseconds);
|
|
||||||
Console.WriteLine("Seed: {0}", seed);
|
|
||||||
|
|
||||||
// Best after 484012 iterations is 30826.444176719036
|
// Best after 484012 iterations is 30826.444176719036
|
||||||
// Time taken: 60000ms
|
// Time taken: 60000ms
|
||||||
// Seed: -1477536140
|
// Seed: -1477536140
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
98
Lab4/RaylibDrawContext.cs
Normal file
98
Lab4/RaylibDrawContext.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using Raylib_cs;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
public class RaylibDrawContext
|
||||||
|
{
|
||||||
|
class DrawFrame
|
||||||
|
{
|
||||||
|
public float ox = 0;
|
||||||
|
public float oy = 0;
|
||||||
|
public float sx = 1;
|
||||||
|
public float sy = 1;
|
||||||
|
public DrawFrame(float ox, float oy, float sx, float sy)
|
||||||
|
{
|
||||||
|
this.ox = ox;
|
||||||
|
this.oy = oy;
|
||||||
|
this.sx = sx;
|
||||||
|
this.sy = sy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ox = 0;
|
||||||
|
public float oy = 0;
|
||||||
|
public float sx = 1;
|
||||||
|
public float sy = 1;
|
||||||
|
|
||||||
|
Stack<DrawFrame> stack;
|
||||||
|
|
||||||
|
public RaylibDrawContext()
|
||||||
|
{
|
||||||
|
stack = new Stack<DrawFrame>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Translate(float offsetX, float offsetY)
|
||||||
|
{
|
||||||
|
ox += offsetX / sx;
|
||||||
|
oy += offsetY / sy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Scale(float scaleX, float scaleY)
|
||||||
|
{
|
||||||
|
sx *= scaleX;
|
||||||
|
sy *= scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Push()
|
||||||
|
{
|
||||||
|
stack.Push(new DrawFrame(ox, oy, sx, sy));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pop()
|
||||||
|
{
|
||||||
|
var frame = stack.Pop();
|
||||||
|
ox = frame.ox;
|
||||||
|
oy = frame.oy;
|
||||||
|
sx = frame.sx;
|
||||||
|
sy = frame.sy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 TransformToLocalSpace(Vector2 pos)
|
||||||
|
{
|
||||||
|
return new Vector2(
|
||||||
|
(pos.X / sx) + ox,
|
||||||
|
(pos.Y / sy) + oy
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawCircle(float centerX, float centerY, float radius, Color color)
|
||||||
|
{
|
||||||
|
int x = (int)((centerX - ox) * sx);
|
||||||
|
int y = (int)((centerY - oy) * sy);
|
||||||
|
float rh = radius * sx;
|
||||||
|
float rv = radius * sy;
|
||||||
|
Raylib.DrawEllipse(x, y, rh, rv, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawCircleLines(float centerX, float centerY, float radius, Color color)
|
||||||
|
{
|
||||||
|
int x = (int)((centerX - ox) * sx);
|
||||||
|
int y = (int)((centerY - oy) * sy);
|
||||||
|
float rh = radius * sx;
|
||||||
|
float rv = radius * sy;
|
||||||
|
Raylib.DrawEllipseLines(x, y, rh, rv, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLine(float startPosX, float startPosY, float endPosX, float endPosY, Color color)
|
||||||
|
{
|
||||||
|
int x0 = (int)((startPosX - ox) * sx);
|
||||||
|
int y0 = (int)((startPosY - oy) * sy);
|
||||||
|
int x1 = (int)((endPosX - ox) * sx);
|
||||||
|
int y1 = (int)((endPosY - oy) * sy);
|
||||||
|
Raylib.DrawLine(x0, y0, x1, y1, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
Lab4/ScoreHistWindow.cs
Normal file
59
Lab4/ScoreHistWindow.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace Lab4
|
||||||
|
{
|
||||||
|
internal class ScoreHistWindow
|
||||||
|
{
|
||||||
|
public ImFontPtr font1;
|
||||||
|
MainWindow win;
|
||||||
|
|
||||||
|
float[] dataPoints;
|
||||||
|
|
||||||
|
float timer = 0;
|
||||||
|
float lastSampleTime = -1;
|
||||||
|
float sampleInterval = 0.1f;
|
||||||
|
|
||||||
|
public ScoreHistWindow(MainWindow win)
|
||||||
|
{
|
||||||
|
this.win = win;
|
||||||
|
dataPoints = new float[100];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
dataPoints = new float[100];
|
||||||
|
timer = 0;
|
||||||
|
lastSampleTime = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void Update(float dt)
|
||||||
|
{
|
||||||
|
if (win.isIterationRunning && !win.iterationPaused)
|
||||||
|
{
|
||||||
|
timer += dt;
|
||||||
|
if (timer - lastSampleTime > sampleInterval)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dataPoints.Length-1; i++)
|
||||||
|
{
|
||||||
|
dataPoints[i] = dataPoints[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPoints[dataPoints.Length - 1] = (float)win.bestScore;
|
||||||
|
|
||||||
|
lastSampleTime = timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PushFont(font1);
|
||||||
|
|
||||||
|
if (ImGui.Begin("Score histogram", ImGuiWindowFlags.None))
|
||||||
|
{
|
||||||
|
ImGui.PlotLines("", ref dataPoints[0], dataPoints.Length, 0, null, 10_000f, 50_000f, new System.Numerics.Vector2(0, 180.0f));
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopFont();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user