Hallo,
ich wollte mich etwas mit automatisiertem Scheduling und der gleichen beschäftigen. Da mir momentan nichts sinnvolleres eingefallen ist, ist mein Projekt folgendes:
Ein "intelligenter" Raidplaner für OGame.
Bei OGame kann man andere Spieler(Planeten) Raiden (angreifen um Resourcen zu klauen), Planeten können sowohl mit Schiffen als auch fixer Verteidigung verteidigt werden. Mit sog. Spionageberichten erfährt man was genau auf diesem Planeten vorhanden ist.
Der Ablauf soll folgendermaßen sein: Man spioniert beliebig viele Planeten aus, fügt die Spionageberichte in das Programm ein und gibt dazu noch seine verfügbare Flotte an. Das Programm soll dann versuchen den optimalen Raidplan zu erstellen.
Folgende Begrenzungen existieren: *Maximal X Angriffe können in einem Plan enthalten sein. Die Zahl ist bekannt und wird vor dem Start angegeben. *Es steht eine begrenzte Flotte (verschiedene Schiffsarten, verschiedene Anzahl / Schiffsart) zur verfügung, ebenfalls bekannt. *Schiffe die in einem Plan bereits eingesetzt werden, können im selben Plan nicht erneut eingesetzt werden. *Planeten bei denen ein Angriff nicht über einem bestimmten Gewinn liegt bzw. in einem Verlust resultiert sollen ignoriert werden. *Die Simulation eines Angriffes auf einen Planeten dauert zwischen 10ms und 500ms, im Schnitt ca. 200ms. *Es stehen maximal 25 Minuten pro Planerstellung zur verfügung.
Mein Ansatz wären hier jetzt zwei genetische Algorithmen:
Einmal einen der versucht die optimale Fleetzusammenstellung pro Planet herauszufinden (aus den zu dem Zeitpunkt noch verfügbaren Schiffen) und dann noch einmal einen der den gesamten Plan optimiert.
Gibt es für so etwas einfachere / schnellere / bessere Alternativen? Es geht mir nicht um den optimalen Raidplan sondern nur etwas annähernd optimales.
Hallo,
in letzter Zeit habe ich recht viel mit WPF und dem MVVM-Pattern zu tun, was mich daran stört ist die Menge an Boilerplatecode wie z. B. die INotifyPropertyChanged Geschichte.
Um das zu minimieren habe ich ein bisschen mit Mono.Cecil rumgespielt und mir eine kleine Konsolenanwendung geschrieben. Diese Anwendung schreibt die WPF Assembly so um, dass jeder public Setter INotifyPropertyChanged benutzt und für jede public void Methode ein ICommand Field und Property angelegt wird, das Field wird dann im Konstruktor initialisiert. (Die ICommand Implementierung ist eine Art RelayCommand / DelegateCommand).
Also kurzes Code Beispiel:
// Was man vorher selbst schreiben musste
public class AViewModel: AbstractViewModel
{
private string _name;
private readonly ICommand _doSomethingCommand;
public AViewModel()
{
_doSomethingCommand = new Command(DoSomething, CanDoSomething);
}
public ICommand DoSomethingCommand
{
get { return _doSomethingCommand; }
}
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
FirePropertyChanged("Name");
}
}
public void DoSomething()
{
}
public bool CanDoSomething()
{
return true;
}
}
// Was man jetzt schreiben muss
public class AViewModel: AbstractViewModel
{
public string Name { get; set; }
public void DoSomething()
{
}
public bool CanDoSomething()
{
return true;
}
}
Das funktioniert auch alles so weit. Das einzige Problem ist: ich kann keine Breakpoints mehr setzen. Die PDB und Dll/Exe sind scheinbar nicht mehr synchron bzw. in der umgeschriebenden PDB fehlt etwas. Die Pdb der Beispielanwendung hat vorher 18kb und nachher nur noch 12.
Muss man mehr machen als:
var assembly = AssemblyFactory.GetAssembly(Path);
assembly.MainModule.LoadSymbols();
// Änderungen
assembly.MainModule.SaveSymbols();
AssemblyFactory.SaveAssembly(assembly, Path);
Bisher habe ich herausgefunden, dass es so bei einigen funktioniert bei anderen aber nicht.
Hätte hier noch jemand einen Tipp was ich probieren könnte oder evtl. eine Alternative zu Mono.Cecil (wenn möglich nicht PostSharp)?
Wäre so etwas z. B. mit LinFu möglich (da es ja auf Cecil basiert) und funktioniert dort das Debuggen?
Du musst auf beide Spalten zusammen einen unique constraint legen, nicht auf jede spalte einzeln.
Wenn ich dich richtig verstanden habe wäre das Stichwort Model Driven UI
Afaik ist im .Net / SqlServer Bereich folgendes vermehrt anzutreffen:
Entity - Tabellen (Englisch, PascalCase, Plural)
Customers
Orders
M:N Tabellen
Einen "vernünftigen" neuen Begriff für diese Relation erstellen oder aber aus den teilnehmenden Tabellen zusammengesetzt:
CustomersAddresses
UsersRoles
oder
CustomersToAddresses
UsersToRoles
oder
CustomerAddresses
UserRoles
oder
Customers_Addresses
Users_Roles
Spalten (PascalCase, Singular)
FirstName
LastName
**Primary Key Spalte **
Id
oder
CustomerId (Tabellenname + Id)
Foreign Key Spalte
CustomerId
FKCustomerId
Customer
Das ist in jedem Fall ja sehr Ähnlich zu dem was ich gemacht habe, bei mir verwendet z. B. der MessageBus den "CommandHandler" intern, genau wie das restliche Programm wenn es um asynchrone Ausführung geht.
Bei mir war der Haupgrund für den CommandHandler das einfachere Unittesting der asynchronen Geschichte, bei den Unittests schiebt man einfach einen CommandHandler ein der alles synchron durchläuft -> Kein Problem mit Threading während der Unittests.
Aber was ist z.b. mit nicht gespeicherten Daten?
Abfragen an den Benutzer ob noch gespeichert werden soll, o.ä.
sollten schon ggf mit Abbrechen beantwortet werden können,
und dann hat wohlmöglich jemand zu früh den Service gekillt.
Naja man muss ja nicht direkt eine ShutDownMessage losschicken sondern einfach ein Request und wenn man ein Response bekommt heißt es, das irgend etwas noch Zeit benötigt, kommt kein Response innerhalb einer bestimmten Zeit kann man halt schließen.
Insgesammt ist bei Messages und ServiceBus sachen die asynchrone Arbeit
meist viel schwieriger und Fehleranfällig, als die sequentielle.
Du musst dann ja alles mögliche ThreadSave implementieren, was sonst meist
nicht nötig wäre.
Ja das stimmt definitiv und ist auch einer der Gründe warum ich die Frage gestellt habe, ich kann momentan noch nicht abschätzen wie groß der Mehraufwand wirklich ist.
Incl. Contextswitch um aus Nebenthreads direkt auf den UI-Thread zu kommen.
Habe ich bei meiner kleiner Testanwendung halbwegs drin (wenn auch Quick & Dirty aber es funktioniert).
Bei mir ist die Signatur der Subscibefunktion momentan:
SubscribeTo<T>(Action<T> handler, bool receiveInMainThread, Func<T, bool> restriction) where T : IMessage
IMessage ist ein leeres Markerinterface und es gibt natürlich entsprechende Überladungen, nur mit dem Handler oder Handler + Restriction oder nur Handler und MainThread.
Ein Aufruf der alles benutzt würde halt so aussehen:
_bus.SubscribeTo<LoginResonse>(LoginResponseHandler, true, x => x.Failed);
... da ich mir auch mal ein paar Gedanken über so eine Architektur gemacht habe, habe diese Idee dann aber relativ schnell verworfen.
Genau das ist der Grund für meine Frage, das Interesse, bisher habe ich es noch nicht gemacht (ledigleich ein kleines ProofOfConcept Progrämmchen), finde es aber sehr interessant, dass man dann überhaupt keinerlei Referenzen mehr auf irgendwelche Service/Repository Interfaces benötigt, lediglich auf die Messages und den MessageBus.
Du bist halt danach extrem flexibel was zur Folge hat das du wahrscheinlich wesentlich mehr Code wiederverwenden kannst. Also schon eher eine Überlegung Wert das nicht auf die eine Clientanwendung zu beschränken sondern es von anfang an als Framework zu entwickeln auf das man mehrere Anwendungen aufsetzen kann.
Natürlich wäre das sehr gut, allerdings gibt es dabei ein Problem, wie und wo die MessageQueue speichern und wie an andere Rechner versenden, was bei Fehler machen etc.
In einer Clientanwendung gibt es all diese Probleme nicht, eine Message kann nicht einfach verloren gehen da es alles nur in einer Queue<IMessage> o. Ä. vorhanden ist und einfach losgeschickt wird.
Das mit dem grundsätzlich Asynchron sollte man aber nochmal überdenken,
denn es gibt schon messages ( ShutDown z.b. ) die sollten synchron refolgen.
Natürlich bedarf grundsätzlich asynchron zu Arbeiten einer großen Änderung der Art wie man programmiert, allerdings lässt sich damit das Meiste erledigen.
Mir fällt z.B. nichts ein, was so fatal daran wäre, wenn die ShutDown-Message von Service A ein paar ms vor Service B empfangen wird.
ja, diese Annahme ist falsch.
Oh das wusste ich nicht, war vorher wohl auch noch nie zu einem Problem geworden, danke 😃
Ich glaube ich weiß jetzt, wo das Problem liegt. Deklariere innerhalb der Schleife eine Variable
currAction, weise bei jedem Durchlaufitem.ValueancurrActionzu und verwenden.Click += (x, y) => currAction();.
Danke, damit funktioniert es.