private void ResetCake() { if (SizeSlider == null || angleSlider == null || DrawingCanvas == null) return; cake = new Cake((int)Math.Round(SizeSlider.Value, 0), (float)angleSlider.Value); cake.Render(ref DrawingCanvas); if(timer?.Enabled ?? false) timer.Stop(); generator?.Cancle(); generator = null; }
//Ermöglicht es den besten gefundenen Kuchen threadsafe zu aktualisieren private async Task UpdateCake(Cake cake, float newScore) { if (cake == null) throw new TheCakeIsALieException(); await Task.Run(() => { lock (this.cake) { if (newScore > bestScore) { bestScore = newScore; this.cake = cake; } } }); }
private void OptimizeInternal(object args) { //Argumente in sinnvolle Typen zurückverwandeln var argsTupel = (Tuple<int, int, CancellationToken>)args; int threadId = argsTupel.Item1; int iterations = argsTupel.Item2; var cancellationToken = argsTupel.Item3; var random = new Random(); var cake = internalCakes[threadId]; float lastScore = cake.CalculateScore(); for (int i = 0; i < iterations; i++) { //Es muss nicht alles n-fach gezählt werden if (threadId == 0) globalIterations++; int randomCandle = random.NextDouble() >= 0.25 ? cake.NearestCandle : random.Next(NumberOfCandles); int newX, newY; int oldX = cake.Candles[randomCandle].X, oldY = cake.Candles[randomCandle].Y; int currentTries = 0; while (true) { i++; float cooldown = (float)Math.Min(Math.Ceiling(globalIterations / 10000d), 20); //Evolutionen die nicht erfolgsversprechend sind zerstören if (i != 0 && i % 10000 == 0) //Zeit für Selektion { if (bestScore * 0.9 > lastScore) { internalCakes[threadId] = cake = Cake.Clone(); lastScore = bestScore; } } currentTries++; //Wenn eine Kerze nicht mehr weiter optimiert werden kann, dann wird eine andere genommen if (currentTries == 1000) { currentTries = 0; //Aus stucts in einer Liste wird by value zugegriffen -> Hacky workaround var tmp = cake.Candles[randomCandle]; tmp.X = oldX; tmp.Y = oldY; cake.Candles[randomCandle] = tmp; randomCandle = random.Next(NumberOfCandles); oldX = cake.Candles[randomCandle].X; oldY = cake.Candles[randomCandle].Y; } newX = oldX + (int)(Math.Max(((cake.Size * 2) / cooldown) * random.NextDouble(), 1) //Verschiebungsrange mit cooldown * (random.NextDouble() >= 0.5 ? 1 : -1)); //Zufälliges Vorzeichen newY = oldY + (int)(Math.Max(((cake.Bounds.Height / 2) / cooldown) * random.NextDouble(), 1) * (random.NextDouble() >= 0.5 ? 1 : -1)); //Wenn eine ungültige Mutation erzeugt wird, dann wird sie nicht mitgezählt if (!cake.Contains(newX, newY)) { i--; currentTries--; continue; } //Mal wieder der selbe Workaround var tmp2 = cake.Candles[randomCandle]; tmp2.X = newX; tmp2.Y = newY; cake.Candles[randomCandle] = tmp2; //Abbruchbedingung if (cancellationToken.IsCancellationRequested || i >= iterations) break; if (cake.CalculateScore() > lastScore) break; } lastScore = cake.CalculateScore(); if (cancellationToken.IsCancellationRequested) { //Es sollte sichergestellt werden, dass der Kuchen wirklich aktualisiert wird, wenn die Optimierung abgeschlossen ist //Sonst kann es sein, dass ein veralteter Kuchen gerendert wird UpdateCake(cake.Clone(), lastScore).GetAwaiter().GetResult(); break; } //Es ist egal wann der beste Kuchen aktualisiert wird UpdateCake(cake.Clone(), lastScore); } }
public CakeGenerator(Cake cake, int degreeOfParallelization) { this.cake = cake; DegreeOfParallelization = degreeOfParallelization; NumberOfCandles = cake.Candles.Count; threads = new Thread[DegreeOfParallelization]; internalCakes = new Cake[DegreeOfParallelization]; for (int i = 0; i < DegreeOfParallelization; i++) internalCakes[i] = cake.Clone(); //Workaround um zu verhindern das der Kuchen automatisch überschrieben wird globalIterations = 1; }
public CakeGenerator(int numberOfCandles, int degreeOfParallelization, int size, float angle, int colors) { //Spannende Zuweisungen NumberOfCandles = numberOfCandles; DegreeOfParallelization = degreeOfParallelization; Colors = colors; cake = new Cake(size, angle); threads = new Thread[DegreeOfParallelization]; internalCakes = new Cake[DegreeOfParallelization]; for (int i = 0; i < DegreeOfParallelization; i++) internalCakes[i] = cake.Clone(); }
public Cake Clone() //Mache mehr Kuchen { var cake = new Cake(Size, Angle); cake.Candles.Capacity = Candles.Count; foreach (var candle in Candles) cake.Candles.Add(candle); return cake; }
private void OpenButton_Click(object sender, RoutedEventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = "Innovatives Dateiformat|*.json"; dialog.CheckFileExists = true; dialog.ShowDialog(); try { if (!File.Exists(dialog.FileName)) return; var cake = JsonConvert.DeserializeObject<Cake>(File.ReadAllText(dialog.FileName)); CandleCountSlider.Value = cake.Candles.Count; SizeSlider.Value = cake.Size; angleSlider.Value = cake.Angle; this.cake = cake; cake.Render(ref DrawingCanvas); generator = new CakeGenerator(cake, (int)Math.Round(ParallelizationSlider.Value, 0)); } catch (JsonReaderException) { throw new TheCakeIsALieException(); } }
private void OptimizationEndedCallback() { running = false; StartButton.Content = "Start"; ProgressBar.IsIndeterminate = false; cake = generator.Cake; cake.Render(ref DrawingCanvas); }