Problem bei Mühle programmieren?
Hallo. Ich habe mir als Projekt vorgestellt das Spiel Mühle mit Html, Css und Js zu programmieren. Jedoch scheitere ich voll, dass Spielfeld für Mühle zu zeichnen. Was empfehlt ihr mir, soll ich doch ein Bild für das Mühle Spielfeld suchen? Aber wie greife ich dann auf die Punkte zu die sind ja dann wie ein Bild und ich müsste mit Koordinaten abschätzen wo sie sind oder was? Ich hab echt ein bisschen Probleme kann mir jemand weiterhelfen?
4 Antworten
Einen schönen guten Abend, liebe*r Wanderprediger5,
ich würde mir das Spielbrett von Mühle anschauen:
Man sieht, dass jede Seite mit den inneren Punkten 7 Punkte hat. Also würde ich eine Tabelle in der Größe 7x7 erstellen. Die Zellen kannst Du entsprechend als aktive Spielfelder markieren.
Für das Spielfeld selbst würde ich einfach ein passendes Bild unter eine unsichtbare Tabelle legen und dann die Spielsteine in den Zellen setzen.
Mit freundlichen Grüßen
![- (Webseite, programmieren, HTML)](https://images.gutefrage.net/media/fragen-antworten/bilder/560720219/0_big.png?v=1725218380000)
Ich bin kein Webdesigner! War nur das Erste, was mir einfiel. :-)
Ich hätte die entsprechenden Zellen ggf. genutzt, um das Spielfeld zu zeichnen.
Muss aber auch sagen, dass ich Mühle als Spiel nie selbst gespielt habe.
Achso na dann. Ich habe mal eine Antwort geschrieben, bin mit meiner Idee aber auch nicht 100% zufrieden. Ich denke dein Kernansatz war im Prinzip richtig, aber ich bin auch kein besonders erfahrener Webdesigner, sondern Ex Designer, ich habe diesen Berufsweg wieder verlassen. Will nur deutlich machen, so "einfache" Spiele sind gar nicht so "einfach" zu programmieren wie man denkt. Kannst gerne mal meine Antwort lesen, um zu sehen, wie viel Programmierprobleme einem da durch den Kopf gehen ^^ Das Ding ist nämlich Spielfeld zeichnen schön und gut, aber man muss die Punkte ja auch ansprechen können, um draufzuklicken.
Schau mal unter meinem anderen Kommentar. Ich habe auf die Schnelle via KI einfach etwas zusammenbauen lassen, wie ich es mir vorgestellt hätte.
Unter dem Kommentar unter meiner Antwort vom Fragesteller. :-)
Hier, gerne nochmal kopiert:
index.html:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mühle Spiel</title>
<style>
table {
border-collapse: collapse;
margin: 20px auto;
}
td {
width: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
vertical-align: middle;
font-size: 24px;
}
.active {
background-color: lightgray;
}
.valid {
background-color: white;
}
</style>
</head>
<body>
<table id="muehleBoard">
<!-- Die Tabelle wird hier durch JavaScript gefüllt -->
</table>
<script src="src/muehle.js"></script>
</body>
</html>
muehle.js
document.addEventListener('DOMContentLoaded', () => {
const board = document.getElementById('muehleBoard');
const validPositions = [
[0, 0], [0, 3], [0, 6],
[1, 1], [1, 3], [1, 5],
[2, 2], [2, 3], [2, 4],
[3, 0], [3, 1], [3, 2], [3, 4], [3, 5], [3, 6],
[4, 2], [4, 3], [4, 4],
[5, 1], [5, 3], [5, 5],
[6, 0], [6, 3], [6, 6]
];
let playerTurn = true; // true für Spieler, false für KI
// Tabelle erstellen
for (let i = 0; i < 7; i++) {
const row = document.createElement('tr');
for (let j = 0; j < 7; j++) {
const cell = document.createElement('td');
if (validPositions.some(pos => pos[0] === i && pos[1] === j)) {
cell.classList.add('valid');
cell.addEventListener('click', () => handleCellClick(cell));
}
row.appendChild(cell);
}
board.appendChild(row);
}
function handleCellClick(cell) {
if (playerTurn && !cell.classList.contains('active')) {
cell.classList.add('active');
cell.textContent = 'X'; // Spielerzug
playerTurn = false;
setTimeout(aiMove, 500); // KI-Zug nach 500ms
}
}
function aiMove() {
const cells = Array.from(document.querySelectorAll('td.valid'));
const emptyCells = cells.filter(cell => !cell.classList.contains('active'));
if (emptyCells.length > 0) {
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
randomCell.classList.add('active');
randomCell.textContent = 'O'; // KI-Zug
playerTurn = true;
}
}
});
Würde am Ende des Tages wahrscheinlich einfach in den anderen Feldern Striche ziehen und Kreise zeichnen, sowie die Striche unsichtbar machen. Dann dürfte es eigentlich soweit ganz gut aussehen. :-)
Interessant:
const validPositions = [
[0, 0], [0, 3], [0, 6],
[1, 1], [1, 3], [1, 5],
[2, 2], [2, 3], [2, 4],
[3, 0], [3, 1], [3, 2], [3, 4], [3, 5], [3, 6],
[4, 2], [4, 3], [4, 4],
[5, 1], [5, 3], [5, 5],
[6, 0], [6, 3], [6, 6]
Diesen Teil habe ich in der Schule nicht mehr gelernt dann mit Arrays. Es könnte sein, dass das hier die Lösung darauf ist, was ich einfach nicht weiß. Dann könnte es also mit einer Tabelle durchaus perfekt funktionieren. Die Kreise könnte man dann nachträglich drauf zeichnen.
Ich programmiere nur prinzipiell nichts mit Copy&Paste, was ich selbst nicht verstehe, deswegen würde ich niemals eine AI nutzen, um etwas zu programmieren. Du kannst ja auch privat jetzt ausprobieren, ob das von der AI klappt, indem du es in eine txt am PC schreibst, die Txt endung zu .html abänderst und die Datei im Browser öffnest.
Du wirst vermutlich feststellen, dass noch um einiges mehr programmiert werden muss, damit das Spiel dann auch tatsächlich funktioniert. Und da wird dir die AI dann plötzlich nicht mehr helfen können. Du müsstest den AI Code dann menschlich erweitern und dafür wirklich gut verstehen. Da kann dann nur ein erfahrener Javascripter ran. Ich verwende nur Jquery und begrenztes Programmierwissen, das mir ausreicht. LG
Du kannst ja auch privat jetzt ausprobieren, ob das von der AI klappt, indem du es in eine txt am PC schreibst, die Txt endung zu .html abänderst und die Datei im Browser öffnest.
Klappt ohne Probleme, sonst würde ich den Code hier nicht teilen. :-)
Aber ja, ich stimme auf jeden Fall zu, dass man nicht nur auf KI bestehen sollte. Ich denke nur, dass es als Proof of Concept sehr praktisch ist. Am Ende stauchelt dann aber auch die KI beim grafischen. Also am besten direkt alles selbst machen. :-)
Digga das ist doch keine Mühle, was die KI da produziert hat! Du willst mir erzählen du hast es ausprobiert? Da kommt nämlich eine vergrößerte Version von Tic Tac Toe dabei raus und keine Mühle HAHAHHA
Die Felder sind weiß. Setz mal den Hintergrund schwarz, dann erkennst Du es.
Nein. Das wird nur immer schlimmer jetzt, jetzt sieht es aus wie eine schreckliche Spinne. Was die AI da produziert hat ist eine Totalkatastrophe.
Genau so sieht das Spielbrett bei Mühle aus... Vergleiche mal, wo Du die Steine setzen kannst auf dem Raster und beim echten Layout.
Ach ja ok, ich verstehe schon, die Spieldynamik geht einigermaßen. Aber trotzdem, sieht das für dich aus wie Mühle? Das sieht ja vom Design schrecklich aus und null wie das Spiel XDDDD Wie willst du das jetzt umprogrammieren, damit es richtig aussieht? Das braucht tonnenweise CSS Arbeit und am Schluss musst du erst Recht wieder darauf zurückgreifen, was ich geschrieben habe. Naja das Javascript könnte man vielleicht übernehmen. Aber wo bleibt dann noch der Spaß am eigenen Programmieren? Gut, die KI kann einiges, aber mich überzeugt das nicht.
Die Zellen benötigen nur noch Kreise und Striche, um vernünftig dargestellt zu werden.
Dann schwarze und weiße Kreise anstelle der X und O. Dann die Farbe der Grids entfernen und du bist good to go.
Das ist ein Proof of Concept, ein Prototyp mit dem absoluten Minimum. Am Ende des Tages musst Du einfach drei Rechtecke und ein Kreuz zeichnen, sowie kleine Kreise in die Tabellen setzen und die Steine setzen und das wars.
Die Zellen benötigen nur noch Kreise und Striche, um vernünftig dargestellt zu werden.
Dann mach das mal mit einer rigiden Tabelle, die aus den HTML Anfängen stammt, als noch Windows Vista eine Modernheit war. Ich schau dir zu.
Dann schwarze und weiße Kreise anstelle der X und O.
Zeig es mir vor bitte.
Das ist ein Proof of Concept, ein Prototyp mit dem absoluten Minimum.
Das stimmt schon, es ist für den geringen Arbeitsaufwand beachtlich, aber nur weil du eine KI benutzt hast. Es sieht null aus wie das Spiel, es funktioniert nur wie das Spiel. Und möglicherweise hat auch die Spieldynamik Fehler.
Am Ende des Tages musst Du einfach drei Rechtecke und ein Kreuz zeichnen, sowie kleine Kreise in die Tabellen setzen und die Steine setzen und das wars.
Ich verstehe nicht ganz, wenn du vorher noch zugegeben hast, gar kein Webdesigner zu sein, wieso du mir jetzt erklärst, wie einfach das jetzt angeblich ist. Dann machs doch. Weil der Fragesteller wird es nicht wissen. Ich find du bist ein sehr sympathischer Mod, aber das wäre jetzt ein gutes Beispiel für den Dunning-Kruger-Effekt.
wieso du mir jetzt erklärst, wie einfach das jetzt angeblich ist.
Weil ich trotzdem Entwickler bin. Logik ist nicht das Problem, sondern HTML und CSS.
Zeig es mir vor bitte.
Gerne, hier:
index.html
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mühlespiel</title>
<link rel="stylesheet" href="src/style.css">
</head>
<body>
<div class="board-container">
<!-- Hintergrund mit SVG für die Mühleliniendiagramm -->
<svg id="background" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">
<!-- Äußeres Quadrat -->
<rect x="22" y="20" width="275" height="280" stroke="black" stroke-width="2" fill="none"/>
<!-- Mittleres Quadrat -->
<rect x="69" y="70" width="182" height="182" stroke="black" stroke-width="2" fill="none"/>
<!-- Inneres Quadrat -->
<rect x="114" y="114" width="92" height="92" stroke="black" stroke-width="2" fill="none"/>
<!-- Mittellinien -->
<line x1="160" y1="20" x2="160" y2="120" stroke="black" stroke-width="2"/>
<line x1="160" y1="200" x2="160" y2="300" stroke="black" stroke-width="2"/>
<line x1="20" y1="160" x2="120" y2="160" stroke="black" stroke-width="2"/>
<line x1="200" y1="160" x2="300" y2="160" stroke="black" stroke-width="2"/>
</svg>
<!-- Tabelle für das Spielbrett -->
<table id="muehleBoard">
<!-- Tabellenzeilen und -zellen -->
<tr>
<td><div class="circle" data-pos="0-0"></div></td><td></td><td></td><td><div class="circle" data-pos="0-3"></div></td><td></td><td></td><td><div class="circle" data-pos="0-6"></div></td>
</tr>
<tr>
<td></td><td><div class="circle" data-pos="1-1"></div></td><td></td><td><div class="circle" data-pos="1-3"></div></td><td></td><td><div class="circle" data-pos="1-5"></div></td><td></td>
</tr>
<tr>
<td></td><td></td><td><div class="circle" data-pos="2-2"></div></td><td><div class="circle" data-pos="2-3"></div></td><td><div class="circle" data-pos="2-4"></div></td><td></td><td></td>
</tr>
<tr>
<td><div class="circle" data-pos="3-0"></div></td><td><div class="circle" data-pos="3-1"></div></td><td><div class="circle" data-pos="3-2"></div></td><td></td><td><div class="circle" data-pos="3-4"></div></td><td><div class="circle" data-pos="3-5"></div></td><td><div class="circle" data-pos="3-6"></div></td>
</tr>
<tr>
<td></td><td></td><td><div class="circle" data-pos="4-2"></div></td><td><div class="circle" data-pos="4-3"></div></td><td><div class="circle" data-pos="4-4"></div></td><td></td><td></td>
</tr>
<tr>
<td></td><td><div class="circle" data-pos="5-1"></div></td><td></td><td><div class="circle" data-pos="5-3"></div></td><td></td><td><div class="circle" data-pos="5-5"></div></td><td></td>
</tr>
<tr>
<td><div class="circle" data-pos="6-0"></div></td><td></td><td></td><td><div class="circle" data-pos="6-3"></div></td><td></td><td></td><td><div class="circle" data-pos="6-6"></div></td>
</tr>
</table>
</div>
<script src="src/script.js"></script>
</body>
</html>
style.css
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
margin: 0;
}
.board-container {
position: relative;
width: 320px;
height: 320px;
}
#background {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
}
#muehleBoard {
position: absolute;
top: 0;
left: 0;
z-index: 2;
width: 100%;
height: 100%;
border-collapse: collapse;
table-layout: fixed;
}
#muehleBoard td {
width: 14.285%; /* 100% / 7 Spalten */
height: 14.285%; /* 100% / 7 Zeilen */
text-align: center;
vertical-align: middle;
background-color: transparent;
position: relative;
}
.circle {
width: 12px; /* Kleinere Kreise */
height: 12px;
border: 2px solid black;
border-radius: 50%;
background-color: white;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
z-index: 3; /* über dem Hintergrund */
}
.stone {
width: 30px;
height: 30px;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 4; /* über den Kreisen */
}
.white-stone {
background-color: white;
}
.black-stone {
background-color: black;
}
script.js
document.addEventListener('DOMContentLoaded', () => {
const validPositions = [
[0, 0], [0, 3], [0, 6],
[1, 1], [1, 3], [1, 5],
[2, 2], [2, 3], [2, 4],
[3, 0], [3, 1], [3, 2], [3, 4], [3, 5], [3, 6],
[4, 2], [4, 3], [4, 4],
[5, 1], [5, 3], [5, 5],
[6, 0], [6, 3], [6, 6]
];
let currentPlayer = 'white'; // Der erste Spieler ist weiß
document.querySelectorAll('.circle').forEach(circle => {
circle.addEventListener('click', function() {
const pos = this.dataset.pos.split('-').map(Number);
// Überprüfen, ob die Position gültig ist und kein Stein gesetzt wurde
if (isValidPosition(pos) && !this.hasChildNodes()) {
// Kreis bleibt weiß gefüllt
// Stein setzen
const stone = document.createElement('div');
stone.classList.add('stone');
stone.classList.add(currentPlayer === 'white' ? 'white-stone' : 'black-stone');
this.appendChild(stone);
// Wechsel des Spielers
currentPlayer = currentPlayer === 'white' ? 'black' : 'white';
}
});
});
function isValidPosition(pos) {
return validPositions.some(validPos => validPos[0] === pos[0] && validPos[1] === pos[1]);
}
});
https://i.imgur.com/WBUikBV.png
Besser? ;-)
Ich werde jetzt nicht weiter den Abend damit verbringen, das zu "Perfektionieren". Es bleibt ein Proof of Concept. Die Spielelogik muss nur noch hinzugefügt werden. Ist kein Hexenwerk.
Ich verstehe nicht ganz, wenn du vorher noch zugegeben hast, gar kein Webdesigner zu sein, wieso du mir jetzt erklärst, wie einfach das jetzt angeblich ist. Dann machs doch. Weil der Fragesteller wird es nicht wissen. Ich find du bist ein sehr sympathischer Mod, aber das wäre jetzt ein gutes Beispiel für den Dunning-Kruger-Effekt.
Um das nochmal auszuweiten;
Ich bin kein Webdesigner, ich komme zu 99% aus dem Backend.
aber das wäre jetzt ein gutes Beispiel für den Dunning-Kruger-Effekt.
Das wäre es, würde ich nun mit wenig Erfahrung von mir behaupten, ich sei sonderlich gut. Nein, es geht mir darum, dass man ein Konzept in der Theorie ausarbeiten kann, ob man nun Webentwickler ist oder nicht.
Dass es funktioniert habe ich Dir hoffentlich jetzt bewiesen. Dass es nicht perfekt ist, ist mir völlig klar. Das Teil ist noch krumm und schief. Ist aber irrelevant für eine einfache Demonstration, wie ich daran herangehen würde.
Im eigenen Fall natürlich ohne KI.
Hier auf Gutefrage werde ich mich aber nicht für solche konzeptionellen Fragen Stunden lang hinsetzen, um jemandem ein Problem zu lösen, dass er selbst lösen möchte und mich am Schluss wahrscheinlich sowieso vergisst. Deshalb halte ich Antworten kurz und lasse mir bei sowas von KI aushelfen.
Alles Klar ist es okay wenn ich dir dann bei Fragen privat schreibe?
Prinzipiell ja, gerne. Bin aber kein Webdesigner. War nur das Erste, was mir einfiel, was dazu gepasst hat. :-)
Hier, das habe ich fix über ChatGPT erstellen lassen und so hätte ich es auch gemacht. Da ist eine kleine "KI" mit dabei, aber man sieht eigentlich ganz gut, wie es funktionieren könnte:
index.html:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mühle Spiel</title>
<style>
table {
border-collapse: collapse;
margin: 20px auto;
}
td {
width: 50px;
height: 50px;
border: 1px solid black;
text-align: center;
vertical-align: middle;
font-size: 24px;
}
.active {
background-color: lightgray;
}
.valid {
background-color: white;
}
</style>
</head>
<body>
<table id="muehleBoard">
<!-- Die Tabelle wird hier durch JavaScript gefüllt -->
</table>
<script src="src/muehle.js"></script>
</body>
</html>
muehle.js
document.addEventListener('DOMContentLoaded', () => {
const board = document.getElementById('muehleBoard');
const validPositions = [
[0, 0], [0, 3], [0, 6],
[1, 1], [1, 3], [1, 5],
[2, 2], [2, 3], [2, 4],
[3, 0], [3, 1], [3, 2], [3, 4], [3, 5], [3, 6],
[4, 2], [4, 3], [4, 4],
[5, 1], [5, 3], [5, 5],
[6, 0], [6, 3], [6, 6]
];
let playerTurn = true; // true für Spieler, false für KI
// Tabelle erstellen
for (let i = 0; i < 7; i++) {
const row = document.createElement('tr');
for (let j = 0; j < 7; j++) {
const cell = document.createElement('td');
if (validPositions.some(pos => pos[0] === i && pos[1] === j)) {
cell.classList.add('valid');
cell.addEventListener('click', () => handleCellClick(cell));
}
row.appendChild(cell);
}
board.appendChild(row);
}
function handleCellClick(cell) {
if (playerTurn && !cell.classList.contains('active')) {
cell.classList.add('active');
cell.textContent = 'X'; // Spielerzug
playerTurn = false;
setTimeout(aiMove, 500); // KI-Zug nach 500ms
}
}
function aiMove() {
const cells = Array.from(document.querySelectorAll('td.valid'));
const emptyCells = cells.filter(cell => !cell.classList.contains('active'));
if (emptyCells.length > 0) {
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
randomCell.classList.add('active');
randomCell.textContent = 'O'; // KI-Zug
playerTurn = true;
}
}
});
Ich merke nochmal an, dass man von KI nicht abschreiben sollte, trotzdem ist es für Konzepte praktisch.
Siehe gerne unter der anderen Kommentarkette ein Beispiel, das optisch deutlich ansprechender ist. In dem Falle ohne einen "Computergegner". Das heißt, den müsste man nur hinzufügen, wenn man das möchte.
Ein in HTML eingebettetes SVG wäre hierfür meine bevorzugte Wahl. Es ist leicht via JavaScript und CSS manipulierbar, verhält sich responsive, beinhaltet schon die für das Spielbrett benötigte Basisformen (Rechteck, Kreis, Linien) und kann über unterschiedliche Schnittstellen (entweder via Code oder einem Grafikprogramm wie Adobe Illustrator oder Inkscape) beschrieben/gezeichnet werden.
Auf Wikimedia Commons findest du sogar schon ein SVG, welches du übernehmen oder zumindest als Vorlage nutzen könntest (Nine Men's Morris board.svg).
Um nun den Spielstatus zu verdeutlichen, reicht es im einfachsten Fall sicherlich, nur die Kreise mit einer anderen Farbe zu befüllen (oder man setzt doch noch einen größeren Kreis - als Spielstein - über einen vorhandenen).
Vergib an die Elemente einfach IDs. Darüber kannst du sie später identifizieren.
Ein einfaches Beispiel:
<!doctype html>
<head>
<title>Example</title>
<style>
circle { fill: white; stroke: black }
.activated { fill: red }
</style>
</head>
<body>
<svg height="200" id="board" width="200" viewBox="0 0 200 200">
<g>
<circle cx="30" cy="30" id="circle-1" r="20" />
<circle cx="60" cy="60" id="circle-2" r="20" />
</g>
</svg>
<script>
const circles = document.querySelectorAll("#board circle");
for (const circle of circles) {
circle.addEventListener("click", evt => {
const clickedElement = evt.currentTarget;
console.log(`clicked: ${clickedElement.id} at ${clickedElement.cx.baseVal.value}/${clickedElement.cy.baseVal.value}`);
clickedElement.classList.add("activated");
});
}
</script>
</body>
Hier wird ein angeklickter Kreis mit roter Farbe gefüllt und dessen ID und Mittelpunkt in der Konsole ausgegeben.
Wenn man einen Kreis dynamisch mit JavaScript (aufbauend auf dem vorherigen Beispiel, positioniert über dem gerade angeklickten Kreis) kreieren möchte, könnte das so aussehen:
const svgNamespace = "http://www.w3.org/2000/svg";
const container = document.querySelector("#board > g");
const circle = document.createElementNS(svgNamespace, "circle");
circle.setAttributeNS(null, "cx", clickedElement.cx.baseVal.value);
circle.setAttributeNS(null, "cy", clickedElement.cy.baseVal.value);
circle.setAttributeNS(null, "r", 50);
container.appendChild(circle);
Statt die Elemente bei jedem Spielzug erneut im Dokument zu suchen, würde ich dir empfehlen, sie in einer Map (oder einem anderen Objekt) zu speichern.
Von dem Einsatz einer HTML-Tabelle, würde ich im Übrigen abraten. Sie ist nicht nur generell überflüssig, sondern auch aus semantischer Sicht nicht dazu gedacht, um Layouts (in diesem Fall eines Spielbretts) umzusetzen.
Wenn du kein SVG nutzen möchtest, wäre noch ein Canvas-Element eine gute Option (das Zeichnen darauf könntest du dir mittels einer Bibliothek wie p5.js nochmals vereinfachen) oder du ordnest div-Elemente via CSS Grid an.
Ich würde das mit SVG machen. Du kannst das ganze Brett und die Spielsteine statisch in HTML definieren. Mit dem Attribut pointer-events kannst Du die Steine und Felder interaktiv steuern.
Das ist am Anfang eine steile Lernkurve, aber man sieht schon bald die ersten Erfolge, und das macht dann richtig Spaß!
Ich habe mal einen ersten Versuch für das Spielbrett generiert (berechnet+exportiert). Mit CSS kann das noch reichlich verschönern.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Mühle</h2>
<svg id="graph" width="900" height="900" viewBox="0 0 300 300">
<!-- Mittelstege von außen nach innen -->
<line x1="150" y1="10" x2="150" y2="110" stroke="#421" stroke-width="3"></line>
<line x1="10" y1="150" x2="110" y2="150" stroke="#421" stroke-width="3"></line>
<line x1="150" y1="290" x2="150" y2="190" stroke="#421" stroke-width="3"></line>
<line x1="290" y1="150" x2="190" y2="150" stroke="#421" stroke-width="3"></line>
<!-- äußeres Quadrat mit 8 Feldern -->
<line x1="10" y1="10" x2="290" y2="10" stroke="#421" stroke-width="3"></line>
<line x1="290" y1="10" x2="290" y2="290" stroke="#421" stroke-width="3"></line>
<line x1="290" y1="290" x2="10" y2="290" stroke="#421" stroke-width="3"></line>
<line x1="10" y1="290" x2="10" y2="10" stroke="#421" stroke-width="3"></line>
<circle cx="10" cy="10" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="10" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="10" cy="290" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="10" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="290" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="290" cy="10" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="290" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="290" cy="290" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<!-- mittleres Quadrat mit 8 Feldern -->
<line x1="60" y1="60" x2="240" y2="60" stroke="#421" stroke-width="3"></line>
<line x1="240" y1="60" x2="240" y2="240" stroke="#421" stroke-width="3"></line>
<line x1="240" y1="240" x2="60" y2="240" stroke="#421" stroke-width="3"></line>
<line x1="60" y1="240" x2="60" y2="60" stroke="#421" stroke-width="3"></line>
<circle cx="60" cy="60" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="60" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="60" cy="240" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="60" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="240" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="240" cy="60" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="240" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="240" cy="240" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<!-- inneres Quadrat mit 8 Feldern -->
<line x1="110" y1="110" x2="190" y2="110" stroke="#421" stroke-width="3"></line>
<line x1="190" y1="110" x2="190" y2="190" stroke="#421" stroke-width="3"></line>
<line x1="190" y1="190" x2="110" y2="190" stroke="#421" stroke-width="3"></line>
<line x1="110" y1="190" x2="110" y2="110" stroke="#421" stroke-width="3"></line>
<circle cx="110" cy="110" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="110" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="110" cy="190" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="110" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="150" cy="190" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="190" cy="110" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="190" cy="150" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
<circle cx="190" cy="190" r="8" fill="#fed" stroke="#421" stroke-width="3"></circle>
</svg>
</body>
</html>
Mit dem Attribut pointer-events kannst Du die Steine und Felder interaktiv steuern.
Da die Steuerung (Prüfung möglicher Züge u.ä.) eh mit JavaScript getätigt werden muss, würde ich auf unerlaubte Spielzüge einfach nicht reagieren oder den Prozess vorzeitig abbrechen, statt via pointer-events (zusätzlich) den Elementstatus hin- und herzusetzen. Das birgt nämlich eher Fehlerpotenzial.
Servus,
also nachdem ich Dultus Ansatz gelesen habe, hat sich das erstmal richtig angehört mit den 7x7 Feldern, aber da die Eckpunkte der dann entstandenen Tabellenzellen die eigentlichen Spielfelder sind, wird für mich fragwürdig, wie man denn dann darauf klicken soll. Der Ansatz gefällt mir deshalb nicht. Außerdem: Wenn man ein Hintergrundbild verwendet, kann es Probleme beim Verändern des Browserfensters geben, also bei Responsive Design.
Ich würde einen anderen Ansatz verfolgen, einen ganz anderen. Ich würde div-Boxen für die Kreise erstellen, sodass die Hitbox sicher immer dem Kreis entsprechen wird und diese div-Box mittels Border-Radius zu Kreisen umgestalten, das geht sehr einfach. Danach würde ich diese div-Boxen alle mit einer ID und Klasse versehen (die ID brauchst für das Javascript später und die Klasse für das CSS, damit es wie ein Kreis aussieht). Danach positionierst du jeden Kreis in einem gewissen Abstand zueinander, am besten mit absoluten Werten.
Wieso so? Dadurch ist mal die Spielmechanik sicher gegeben. Jetzt hast du noch eine letzte Herausforderung: Wie um alles in der Welt verbindest du die Kreise mit Linien? Tatsächlich müsste ich hier nochmal drüber nachdenken. Du könntest jetzt auf die Methodik mit dem Hintergrundbild zurückgreifen oder aber du findest eine bessere Methode dafür. Mein Punkt ist: Die Linien sind nur Zierde. Das Spiel funktioniert ohne die Linien, denn es sind nur Hilfslinien für das menschliche Denken und Sehen.
Ich würde 3 Quadrate machen, also 3 Div Boxen ineinandergeschachtelt plus 4 Linien und hoffen sie an die Punkte hinzukriegen, notfalls mit Media Queries für verschiedene Browsergrößen, notfalls mit sehr vielen Media Queries, dass die immer gut hinter den Linien liegen. Das ganze mit z-index heruntersetzen eine Ebene. Ich würde in Kauf nehmen, dass die Linien vielleicht nicht immer perfekt liegen. Allerdings geht das schon, wenn das Ganze in einem Container-Div in der Seite selbst steckt, mit overflow: hidden; dann wird es gar nicht so viele Media Queries brauchen und gut funktionieren.
All das kann man wieder über den Haufen werfen, wenn es eine Möglichkeit gibt, die Eckpunkte der Zellen eines 7x7 Rasters anzusprechen, dann hat Dultus Recht und seine Methode ist sauberer und funktioniert besser. So "einfache" Spiele wie Mühle sind oft gar nicht so einfach. Ich habe mal Mine Sweeper und Cookie Clicker nachprogrammiert. Das hat mir viel Spaß gemacht. Programmieren bedeutet immer auch etwas Kreativität an den Tag zu legen! Viel Glück!
Danke für die guten Antworten mach dann Morgen weiter und schreibe dann :)
Du hast zwar Recht, aber ich möchte ebenfalls als Webdesigner zwei Anmerkungen machen. Die Tabelle ist zwar gut, aber bedenke doch, dass die interaktiven Klickpunkte jeweils an der ECKE einer Zelle liegen. Außerdem kann bei einem hinterliegenden Bild bei Responsive Design schnell mal die Hitbox nicht mehr mit dem Hintergrundbild übereinstimmen. Vielleicht können wir dieses Problem zusammen lösen, da es keinen Sinn macht diese Anfangsarbeit von dir zu ignorieren, die auf jeden Fall richtig ist mit den 7x7 Feldern, doch mir erschließt sich nicht, wie das so funktionieren soll.