{"id":3822,"date":"2018-12-12T21:01:40","date_gmt":"2018-12-12T20:01:40","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3822"},"modified":"2019-01-02T00:00:39","modified_gmt":"2019-01-01T23:00:39","slug":"c-guns-weihnachtsratsel","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3822","title":{"rendered":"C++ Guns: R\u00e4tsel 2018"},"content":{"rendered":"<p>Betrachte ein unstruturiertes Gitternetz bestehend aus Punkte und Dreiecken. Jeder Punkt kann durchnummeriert werden. F\u00fcr jeden Punkt <em>IP<\/em> bezeichnet die Variable <em>NCONN<\/em> die Anzahl der angeschlossenen Punkte pro Punkt. Und die Variable <em>NCONE<\/em> bezeichnet die angeschlossene Dreiecke pro Punkt.<br \/>\nEs ist leicht zu sehen, dass Punkte am Rand eine unterschiedliche Anzahl von angeschlossenen Punkte und Dreiecke haben. W\u00e4rend Punkte im Mesh gleich viele angeschlossene Punkte und Dreiecke haben.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/9\/93\/Unstructured_grid.svg\/266px-Unstructured_grid.svg.png\" alt=\"Unstructured Grid\" \/><\/p>\n<p>Folgender C++ k\u00f6nnte grob so ein Gitternetz beschreiben:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;vector&gt;\r\n\r\nstruct Mesh {\r\n  std::vector&lt;int&gt; NCONN, NCONE;\r\n\r\n  void update_NCONN_NCONE() {\r\n     \/\/ Genaue Impl. nicht relevant f\u00fcr das R\u00e4tsel\r\n  }\r\n\r\n  bool istRandpunkt(int IP) const {\r\n    return NCONN&#x5B;IP] != NCONE&#x5B;IP];\r\n  }\r\n}\r\n<\/pre>\n<p>Vor der ersten Benutzung der Funktion <em>isRandpunkt<\/em> m\u00fcssen die Variablen <em>NCONN<\/em> und <em>NCONE<\/em> gef\u00fcllt werden. Dies \u00fcbernimmt die Funktion <em>update_NCONN_NCONE<\/em>. Die genaue Implementierung dieser Funktion ist f\u00fcr das R\u00e4tsel nicht relevant, und wird daher nicht angegeben.<\/p>\n<p>Nun muss der Programmierer darauf achten, dass diese Funktion auch immer aufgerufen wird. Programmierer sind aber auch nur Menschen und machen Fehler. Sollte der Aufruf von <em>update_NCONN_NCONE<\/em> einmal vergessen werden, st\u00fcrzt das Programm im besten Fall ab. Im schlechtesten Fall werden falsche Ergebnisse produziert.<\/p>\n<p>Wie kann dem Programmierer geholfen werden?<br \/>\nEs muss auf eine Art sichergestellt werden, dass die Variablen <em>NCONN<\/em> und <em>NCONE<\/em> immer mit den aktuellen Daten gef\u00fcllt sind. Allerdings darf die Funktion   <em>update_NCONN_NCONE<\/em> nicht unn\u00f6tig oft aufgerufen werden, da sie unter Umst\u00e4nden eine lange Laufzeit zur Folge hat. <\/p>\n<p>Beachtet auch, dass dieser Code zur Laufzeit in ein Programm geladen werden k\u00f6nnte (Library\/Plugin).<\/p>\n<p>Es gibt f\u00fcr jedes Problem viele L\u00f6sungen und auch wenige gute.<\/p>\n<p><strong>Beispiel<\/strong><br \/>\nIn der Funktion <em>istRandpunkt<\/em> bei jedem Aufruf zu testen, ob die Funktion <em>update_NCONN_NCONE<\/em> aufgerufen werden muss w\u00fcrde zwar sicherstellen, dass die Variablen immer aktuell sind. Allerdings ist das so keine gute Idee, da dies die Laufzeit negativ beeinflusst.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct Mesh {\r\n  mutable std::vector&lt;int&gt; NCONN, NCONE;\r\n  mutable bool needUpdate = true;\r\n\r\n  void update_NCONN_NCONE() {\r\n     if(not needUpdate) return;\r\n     needUpdate = false;\r\n     \/\/ Genaue Impl. nicht relevant f\u00fcr das R\u00e4tsel\r\n  }\r\n\r\n  bool istRandpunkt(int IP) const {\r\n    update_NCONN_NCONE();\r\n    return NCONN&#x5B;IP] != NCONE&#x5B;IP];\r\n  }\r\n}\r\n<\/pre>\n<p>In der Implementierung zeigen sich noch weitere H\u00e4sslichkeiten. Die Funktion <em>istRandpunkt<\/em> sollte als <em>const<\/em> attributiert sein, da sie keine Daten \u00e4ndert. Allerdings widerspricht das der Idee, die Variablen on-the-fly zu aktualisieren. Daher m\u00fcssen sie als <em>mutable<\/em> deklariert werden.<br \/>\nDamit werden aber Dinge im Hintergrund getriggert, welcher der Programmierer nicht erwartet. Die Funktion <em>istRandpunkt<\/em> sagt vom Funktionsnamen nicht aus, dass noch ein Update passiert.<\/p>\n<p><strong>L\u00f6sung 1: Tags<\/strong><br \/>\nDie Idee ist, dass die Funktion <i>istRandPunkt<\/i> nur dann aufgerufen\/compiliert werden kann, wenn als Argument irgendetwas mitgegeben werden kann, was vorher nur von der Funktion update_NCONN_NCONE erstellt wurde. Beispielsweise mittels einer Tag Variable. Diese kann nur von <em>update_NCONN_NCONE<\/em> erstellt werden.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstruct Mesh {\r\n    private:\r\n    struct Tag { };\r\n\r\npublic:\r\n  std::vector&lt;int&gt; NCONN, NCONE;\r\n\r\n  Tag update_NCONN_NCONE() {\r\n     \/\/ Genaue Impl. nicht relevant f\u00fcr das R\u00e4tsel\r\n     return Tag();\r\n  }\r\n\r\n  bool istRandpunkt(int IP, Tag) const {\r\n    return NCONN&#x5B;IP] != NCONE&#x5B;IP];\r\n  }\r\n};\r\n\r\nauto func() {\r\n    Mesh mesh;    \r\n    auto tag = mesh.update_NCONN_NCONE();\r\n    return mesh.istRandpunkt(1, tag);\r\n}\r\n<\/pre>\n<p>Der Nachteil ist schnell erkannt. Sobald mehr als ein Mesh existiert, kann die tag Variable mehrfach genutzt werden. Es existiert keine Bindung zu einer speziellen Instanz eines Mesh Types. <\/p>\n<p><strong>L\u00f6sung 1: Enums<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Betrachte ein unstruturiertes Gitternetz bestehend aus Punkte und Dreiecken. Jeder Punkt kann durchnummeriert werden. F\u00fcr jeden Punkt IP bezeichnet die Variable NCONN die Anzahl der angeschlossenen Punkte pro Punkt. Und die Variable NCONE bezeichnet die angeschlossene Dreiecke pro Punkt. Es ist leicht zu sehen, dass Punkte am Rand eine unterschiedliche Anzahl von angeschlossenen Punkte und [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-3822","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3822","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3822"}],"version-history":[{"count":19,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3822\/revisions"}],"predecessor-version":[{"id":3905,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3822\/revisions\/3905"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3822"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}