{"id":30456266,"url":"https://github.com/mafeth/bwinf-2021-exercise4","last_synced_at":"2025-08-23T16:13:55.614Z","repository":{"id":162051275,"uuid":"432594973","full_name":"mafeth/bwinf-2021-exercise4","owner":"mafeth","description":"This project is my elaboration of Task 4 in the Federal Computer Science Competition 2021. The idea was to determine from a finite set of different dice which one of them is best suited for a complete game of “Don't get angry”. For this, I had to implement and simulate the entire game principle with all the rules, such as throwing out.","archived":false,"fork":false,"pushed_at":"2022-10-10T20:58:55.000Z","size":28,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-16T12:40:51.588Z","etag":null,"topics":["2021","bwinf40","dont-get-angry","game","simulation"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mafeth.png","metadata":{"files":{"readme":"README-de.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-28T01:44:30.000Z","updated_at":"2023-02-19T13:13:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"b572d653-9718-4719-91f0-5b10dfddeebb","html_url":"https://github.com/mafeth/bwinf-2021-exercise4","commit_stats":null,"previous_names":["mafeth/bwinf-2021-exercise4","devofvictory/bwinf-2021-exercise4"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mafeth/bwinf-2021-exercise4","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafeth%2Fbwinf-2021-exercise4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafeth%2Fbwinf-2021-exercise4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafeth%2Fbwinf-2021-exercise4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafeth%2Fbwinf-2021-exercise4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mafeth","download_url":"https://codeload.github.com/mafeth/bwinf-2021-exercise4/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mafeth%2Fbwinf-2021-exercise4/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271755480,"owners_count":24815415,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2021","bwinf40","dont-get-angry","game","simulation"],"created_at":"2025-08-23T16:13:55.136Z","updated_at":"2025-08-23T16:13:55.592Z","avatar_url":"https://github.com/mafeth.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"**[Switch to english version](README.md)**\n# 🎲 Aufgabe 4: Würfelglück\n\n*DevOFVictory, 28.11.21 - Bundeswettbewerb Informatik 2021*\n\n---\n\n# Inhalt\n\n1. Informationen\n2. Lösungsideen + (Probleme)\n3. Programmatische Umsetzung\n4. Benutzung\n5. Beispiele\n6. Quellcode\n7. Programmstruktur\n\n# 1. Informationen\n\nBei diesem Projekt handelt es sich um meiner Ausarbeitung der Aufgabe 4 im Bundeswettbewerb der Informatik 2021. Es ging darum, aus einer endlichen Menge an verschiedensten Würfeln, zu bestimmen, welcher von ihnen am besten geeignet ist für ein komplettes Spiel \"Mensch ärgere dich nicht\". Dafür musste ich das komplette Spielprinzip mit allen Regeln, wie dem Herauswerfen programmatisch umsetzten und simulieren.\n\n# 2. Lösungsideen (+Probleme)\n\n### Jeder Spieler hat seinen eigenen Spielplan\n\n\n💡 Bei meiner ersten Idee, spielt jeder Spieler auf seinem eigenen Spielplan, da jeder Spieler sozusagen seine eigene Strecke läuft und damit auch sein eigenes Ziel und einen separierten Start hat. Das Problem, das sich bei dieser Idee herausstellte, ist die Interaktion der Spieler untereinander, also das Herauswerfen und überspringen der fremden Spielfiguren. Ein Ansatz zur Lösung dieses Problems wäre es gewesen, die einzelnen Spielfelder miteinander zu synchronisieren. Dies wäre aber eine häufige Fehlerursache geworden, sodass ich mich gegen diese Idee entschieden habe.\n\n\n\n### Es gibt einen Spielplan für alle Spieler, bei dem jedes Feld eine eigene ID besitzt\n\n\n💡 Da sich bei der ersten Idee, das Problem mit der schwierigen Synchronisation zwischen auftrat, entschied ich mich hier, ein Spielbrett für alle Figuren des Spieles zu definieren. Dabei wird jedes einzelnes Feld mit einer einzigartigen ID Nummer bestückt, sodass die Felder direkt ansprechbar sind.  Hier stellte sich aber dann das Problem, dass jeder Spieler seine eigene Strecke hat und nicht allgemein gesagt werden kann, dass die Strecke mit der ID 0 beginnt und mit der 39 aufhört, da jeder Spieler in sein eigenes Haus einbiegen muss.\n\n\n\n### Überarbeitung: Ein Spielplan, IDs für alle Felder, Spezifikation der einzelnen Felder\n\n\n💡 Die Lösung für das Problem der zweiten Idee und damit auch der endgültige Lösungsansatz ist es nun, weiterhin ein Spielfeld für alle Spieler zu deklarieren, aber alle Felder inklusive der Zielfelder mit einer eindeutigen ID als Eigenschaft des Objektes zu versehen. Außerdem besitzt die `Field`-Klasse noch die Eigenschaft, welchem Spieler das jeweilige Feld gehört. Somit kann die `GameFigure` Klasse eine Prozedur `getTargetField()` implementieren, die für einen Parameter `diced` das `Field` zurückgibt, auf dem die Figur nach dem Zug landet, während sie die fremden Zielfelder überspringt.\n\n\n\n# 3. Programmatische Umsetzung\n\nNachdem ich der doch etwas umfangreicheren Aufgabe mich von Python 3 abgewendet habe, entschied ich mich für Java 16 als Programmiersprache, um dieses Projekt anzugehen. Die Gründe dafür sind meine mehrjährige Erfahrung mit Java, aber hauptsächlich die Möglichkeit auf strikte Objektorientierung. Diese ist für die Aufgabe meiner Meinung nach essenziell, um den Überblick über die einzelnen Spielelemente, wie das Spielbrett, auf dem sich Spielfelder befinden und natütlich Objekte wie der Spieler, der würfen und ziehen kann, sowie das Spiel an sich, um allgemeine Methoden zentral definieren zu können.\n\nIch implementierte also in der Java Entwicklungsumgebung *(IDE)* \"IntelliJ Ultimate\" die Klassen\n\n`Game.java`, `GameField.java`, `GameFigure.java`, `GamePlan.java` und `GamePlayer.java`.\n\nNäherer Sinn, Funktionen der einzelnen Klassen und ein Class-Diagramm finden Sie unter dem Punkt \"**6. Programmstruktur**\"\n\n# 4. Benutzung\n\nDas Programm lässt sich durch einen Befehl aktivieren, in welchem auch Einstellungsparameter wie Anzahl der Iterationen der Spielkombinationen, und der Pfad festgelegt werden kann.\n\n```bash\njava -jar Exercise4.java \u003cboolean showDebug\u003e \u003cint iterations\u003e \u003cstring pathToFile\u003e\n```\n\n- showDebug - Gibt an, ab alle Nachrichten wie der komplette Spielverlauf in der Konsole angezeigt werden sollen. Dies ist sinnvoll, um das Spiel im Nachhinein nachvollziehen zu können. Die möglichen Werte sind true und false\n- iterations - Gibt an, wie oft jede Spielkombination gespielt werden soll. Je höher diese Zahl ist, desto genauer ist das Ergebnis, aber es dauert auch länger. Das Wertespektrum für diesen Parameter sind alle natürlichen, ganzen Zahlen größer als 0.\n- pathToFile - Gibt an, unter welchem Pfad die Datei mit den zu testenden Würfeln gespeichert ist. Eine relative Pfadangabe ist möglich. Dieser Wert ist ein beliebiger String.\n\n### Beispiel einer Würfeldatei:\n\n```\n6\n6 1 2 3 4 5 6\n6 1 1 1 6 6 6\n4 1 2 3 4\n10 0 1 2 3 4 5 6 7 8 9\n12 1 2 3 4 5 6 7 8 9 10 11 12\n20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n```\n\n- in der ersten Zeile die Anzahl n der Würfel,\n- in den weiteren n Zeilen jeweils:\n    - als erste Zahl die Anzahl m_i der Seiten des Würfels i und\n    - in den weiteren m_i Zahlen jeweils die Augenzahlen der\n    Würfelseiten\n\n# 5. Beispiel\n\nBenutzer Befehl: `java -jar Exercise4.jar false 50 dice0.txt`\n\n### dices0.txt - Dauerte ungefähr 16,5 Sekunden\n\n```\nHere are the wins of each dice ordered by quantity:\n1.) Dice 1 (41 Wins)\n2.) Dice 4 (35 Wins)\n3.) Dice 5 (31 Wins)\n4.) Dice 6 (25 Wins)\n5.) Dice 2 (9 Wins)\n6.) Dice 3 (0 Wins)\n```\n\n# 6. Quellcode\n\n## Umsetzung von Regelwerk im Quellcode\n\nIch werde unter diesem Abschnitt für jede Regel aus dem offiziellen Regelwerk den dafür zuständigen Code Schnipsel hier einfügen.\n\n\u003e *Wer seine vier Spielsteine als erster „nach Hause“ gebracht hat, gewinnt das Spiel*\n\u003e \n\n```java\npublic boolean hasWon() {\n        boolean won = true;\n\n        for (GameField house : game.getGamePlan().getHouses(this)) {\n            if (house.getContent() == null) {\n                won = false;\n                break;\n            }\n        }\n\n        if (won) {\n            Exercise4.logMessage(this.getName() + \" won this game.\");\n        }\n\n        return won;\n    }\n```\n\n\u003e *Der Spieler, der an der Reihe ist, würfelt und setzt seinen Spielstein\nUm die gewürfelte Augenzahl in Pfeilrichtung auf der Laufbahn vor.\nEigene und fremde Steine können übersprungen werden, die besetzten Felder werden aber mitgezählt.*\n\u003e \n\n\u003e *Wer mit dem letzten Punkt seiner Augenzahl auf ein Feld trifft, das\nvon einer fremden Spielfigur besetzt ist, schlägt diese Figur und setzt\nseinen eigenen Stein auf ihren Platz.*\n\u003e \n\n\n```java\npublic void turn() {\n        int diced = dice();\n\n        if (diced != 6) {\n            move(diced);\n\n            if (!hasWon()) {\n                this.game.nextPlayer();\n            }else {\n                this.game.setWinner(this);\n            }\n\n        }else {\n            if (getStart().isOccupied()) {\n                GameFigure occupyingFigure = getStart().getContent();\n                \n                if (occupyingFigure.getOwner().equals(this)) {\n                    Exercise4.logMessage(\"Start is occupied by own figure. Moving this. \");\n                    this.game.moveFigure(occupyingFigure, occupyingFigure.getTargetField(diced));\n                }else {\n                    Exercise4.logMessage(\"Start is occupied by other figure. Kicking this.\");\n                    getStart().getContent().getOwner().getHouse().add(occupyingFigure);\n\n                    if (!this.getHouse().isEmpty()) {\n                        GameFigure houseFigure = getHouse().get(0);\n\n                        this.getStart().setContent(houseFigure);\n                        getHouse().remove(houseFigure);\n                    }else {\n                        this.move(diced);\n                    }\n                }\n\n            }else {\n                if (!this.getHouse().isEmpty()) {\n                    Exercise4.logMessage(this.getName() + \" left his house.\");\n                    GameFigure houseFigure = getHouse().get(0);\n\n                    this.getStart().setContent(houseFigure);\n                    getHouse().remove(houseFigure);\n                }else {\n                    Exercise4.logMessage(this.getName() + \" moved, because house is empty.\");\n                    move(diced);\n                }\n            }\n\n            if (!hasWon()) {\n                turn();\n            }else {\n                this.game.setWinner(this);\n            }\n\n        }\n\n    }\n```\n\n\u003e *Wer mehrere Spielsteine auf der Laufbahn stehen hat, muss mit dem vordersten Stein ziehen, der gezogen werden kann.*\n\u003e \n\n```java\npublic GameFigure getFirstGameFigure(List\u003cGameFigure\u003e includedFigures) {\n\n        if (includedFigures.isEmpty()) {\n            return null;\n        }\n\n        GameFigure firstFigure = includedFigures.get(0);\n\n        if (!getStart().isOccupied()) {\n\n            for (GameFigure figures : includedFigures) {\n                if (getRaceIds().indexOf(figures.getField().getId()) \u003e getRaceIds().indexOf(firstFigure.getField().getId())) {\n                    firstFigure = figures;\n                }\n            }\n\n            int currentId = firstFigure.getField().getId();\n            int idIndex = getRaceIds().indexOf(currentId);\n\n            GameField nextField = getRaceIds().size() \u003e idIndex+1 ? this.game.getFieldById(getRaceIds().get(idIndex+1)) : null;\n\n            if (nextField == null) {\n                includedFigures.remove(firstFigure);\n                return getFirstGameFigure(includedFigures);\n            }else {\n                if (nextField.isOccupied() \u0026\u0026 nextField.getContent().getOwner() == this) {\n                    includedFigures.remove(firstFigure);\n                    return getFirstGameFigure(includedFigures);\n                }else {\n                    return firstFigure;\n                }\n            }\n\n        }else {\n            return getStart().getContent();\n        }\n    }\n```\n\n\u003e *So lange noch weitere Steine auf den B-Feldern auf ihren Spieleinsatz warten, darf keine eigene Figur auf dem A-Feld stehen bleiben.\nSie muss das Feld frei machen, sobald sie die Möglichkeit dazu\nhat.*\n\u003e \n\n```java\nif (!getStart().isOccupied()) {\n\t[...]\n}else {\n\treturn getStart().getContent();\n}\n```\n\n\u003e *Die Steine, die auf den B-Feldern stehen, können nur mit einer „6“\nins Spiel gebracht und damit auf das Anfangsfeld A gesetzt werden.*\n\u003e \n\n\u003e *Wer eine „6“ würfelt, hat nach seinem Zug einen weiteren Wurf frei.\nErzielt er dabei wieder eine „6“, darf er erneut nach dem Ziehen\nwürfeln.*\n\u003e \n\n\u003e *Bei einer „6“ muss man einen neuen Stein ins Spiel bringen, solange noch Spielfiguren auf den eigenen B-Feldern stehen. Der neue\nStein wird dann auf das Feld A der eigenen Farbe gestellt.*\n\u003e \n\n```java\nint diced = dice();\nif (diced != 6) {\n\t[...]\n}else {\n\t[...]\n\tif (!this.getHouse().isEmpty()) {\n\t  Exercise4.logMessage(this.getName() + \" left his house.\");\n\t\tGameFigure houseFigure = getHouse().get(0);\n\t\tthis.getStart().setContent(houseFigure);\n\t\tgetHouse().remove(houseFigure);\n\n\t}else {\n\t\tExercise4.logMessage(this.getName() + \" moved, because house is empty.\");\n\t\tmove(diced);\n\n  }\n\tturn();\n}\n```\n\n\u003e *Steht dagegen eine\nfremde Figur auf dem Feld A, wird sie geschlagen.*\n\u003e \n\n\u003e *Wer eine „6“ würfelt und keinen Stein mehr auf den B-Feldern hat,\ndarf mit einer seiner Figuren auf der Laufbahn sechs Felder weiterziehen und dann noch einmal würfeln.*\n\u003e \n\n```java\nif (getStart().isOccupied() \u0026\u0026 !occupyingFigure.getOwner().equals(this)) {\n\tExercise4.logMessage(\"Start is occupied by other figure. Kicking this.\");\n\tgetStart().getContent().getOwner().getHouse().add(occupyingFigure);\n\tif (!this.getHouse().isEmpty()) {\n\t    GameFigure houseFigure = getHouse().get(0);\n\t    this.getStart().setContent(houseFigure);\n\t    getHouse().remove(houseFigure);\n\t}else {\n\t    this.move(diced);\n}\n```\n\n\u003e *Fremde Zielfelder darf man nicht betreten.*\n\u003e \n\n```java\nif ((field != null \u0026\u0026 field.getLimited() == null) || (field != null \u0026\u0026 field.getLimited().equals(this.getOwner()))) {\n\t[...]\n}\n```\n\n## Simulationssteuerung\n\nHier sind wichtige Code Teile, die dafür sorgen, dass die Dateien korrekt ausgelesen werden und die einzelnen Simulationen gestartet werden.\n\n### Auswahl der Spielkombinationen\n\n```java\nfor (int i=0; i\u003cdices.size(); i++) {\n\tscores.put(i, 0);\n\tfor (int j = i + 1; j \u003c dices.size(); j++) {\n\t\n\t    List\u003cString\u003e combination = new ArrayList\u003c\u003e();\n\t    combination.add(dices.get(i));\n\t    combination.add(dices.get(j));\n\t\n\t    combinations.add(combination);\n\t}\n}\n```\n\n### Erstellung einer Spielsimulation\n\n```java\nGame game = new Game(48, 0);\n\nGamePlayer player1 = new GamePlayer(game, \"Player 1 (Green)\", 0, 47, dice1.subList(1, dice1.size()));\nGamePlayer player2 = new GamePlayer(game, \"Player 2 (Red)\", 24, 23, dice2.subList(1, dice2.size()));\n\nhouses.put(44, player1);\nhouses.put(45, player1);\nhouses.put(46, player1);\nhouses.put(47, player1);\n\nhouses.put(20, player2);\nhouses.put(21, player2);\nhouses.put(22, player2);\nhouses.put(23, player2);\n\ngame.getGamePlan().setHouses(houses);\ngame.joinPlayer(player1);\ngame.joinPlayer(player2);\n```\n\n### Maximale Ausführungsdauer von 1,5 Sekunden\n\n```java\nlong startedTime = System.currentTimeMillis();\nwhile (game.isRunning()) {\n\n  if (System.currentTimeMillis() - startedTime \u003e= 1500) {\n      logMessage(\"Simulation took too long. Skipped this game.\");\n      break;\n  }\n[...]\n}\n```\n\n# 7. Programmstruktur\n\n## Class Diagramm\n\n![https://i.ibb.co/vPCZgsY/Package-exercise4.png](https://i.ibb.co/vPCZgsY/Package-exercise4.png)\n\nJede Klasse implementiert das `Game` Objekt, um auf alle Daten des Spiels von überall zugreifen zu können.\n\n## Erklärung zu den einzelnen Klassen\n\n### `Exercise4.java`\n\n\n💡 Hier startet die ganze Simulation in der `main()` Methode. Außerdem enthält sie nicht eine Funktion, um Nachrichten in einem bestimmten Format auszugeben.\n\n\n\n### `Game.java`\n\n\n💡 Über diese Klasse bzw. dieses Objekt werden allgemeine Funktionen des Spielablaufs definiert, wie zum Beispiel das Bewegen von Figuren, der Gewinnerstatus oder der Spieler, der momentan an der Reihe ist.\n\n\n\n### `GamePlayer.java`\n\n\n💡 Hier sind Spieler spezifische Funktionen und Eigenschaften gespeichert, wie z.B. der einzelne Zug und die jeweiligen Figuren, die zu dem Spieler gehören.\n\n\n\n### `GameFigure.java`\n\n\n💡 Die eben genannten Figuren sind alles Objekte dieses Typen. Sie implementiert z.B. die Eigenschaften des Besitzers, sowie das Feld, auf dem die Figur steht.\n\n\n\n### `GameField.java`\n\n\n💡 Das ist das einzelne Feld, auf dem eine Figur stehen kann, oder auch nicht stehen kann. Über diese Information gibt die Eigenschaft `content` Information. Eine Liste mit vielen dieser Objekte befindet sich auf dem Spielfeld.\n\n\n\n### `GamePlan.java`\n\n\n💡 Diese Klasse stellt das eigentliche Spielfeld dar. Es enthält eine Liste aller Plätze für Felder und die einzelnen Häuser mit den IDs der Spieler.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmafeth%2Fbwinf-2021-exercise4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmafeth%2Fbwinf-2021-exercise4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmafeth%2Fbwinf-2021-exercise4/lists"}