Bimaru (Datenstrukturen)
Ein Bimaruspiel (Battleship oder Marinespiel) ist eine Art Schiffeversenken. Das Spielfeld ist eine quadratische Matrix. Die Schiffe darin haben alle die Breite Eins (1 Feld) und die Längen 1, 2, 3 bzw. 4 Felder. Wir bezeichnen die Schiffe daher auch Einer, Zweier, Dreier oder Vierer. Ein Schiff der Länge 3 hat also 3 Schiffsteile und nimmt 3 aneinanderliegende Quadrätchen in Anspruch. Schiffe berühren sich dabei nicht, auch nicht diagonal. Das heißt, die Schiffe sind komplett von Wasser umgeben. Beim Lösen eines Bimaru ist rechts (bzw. unten) pro Zeile (bzw. Spalte) angegeben, wie viele Schiffsteile total vorkommen. Einige Schiffsteile sind dabei manchmal schon vorgegeben. Dabei sieht man jeweils, ob es sich um ein Schiffsanfang oder -ende oder um eine Schiffsmitte handelt. In anderen Feldern ist vorgegeben, dass es sich um Wasser (also nicht um einen Schiffsteil) handelt. Weiter ist vorgegeben, wie viele Schiffe von welcher Länge (welchen Typs) total vorkommen. (Ob das hier abgebildete Bimaru lösbar ist, ist nicht Inhalt dieser Aufgabe).
< img src="../uploads/eximage-1d88f6.JPG" alt="" width="242" height="344" />
Schreiben Sie eine Datenstruktur, die ein (noch ungelöstes) Bimaru wie oben speichern kann. Schreiben Sie zudem ein Programm, das die einzelnen Informationen beschreiben, bzw lesen kann. Dabei ist eine Position (feld) immer durch einen der folgenden Werte bestimmt:
String feld = …
"unbestimmt" : Dieses Feld ist noch nicht gelöst.
"Wasser" : An dieser Position befindet sich sicher kein
Schiff.
"Schiffsmitte" : hier ist ein Schiffsteil, jedoch kein
Schiffsende
weder Bug noch Heck (Quadrat).
"Einzelschiff" : Schiff bestehend aus nur einer Zelle (Kreis).
"Ende_Oben" : Bug oder Heck oben
(wie im Bild 6. Zeile, 8. Spalte).
"Ende_Unten" : analog
"Ende_Links" : analog
"Ende_Rechts" : analog
"Schiffsteil" : An dieser Position befindet sich ein Teil
eines Schiffes (also kein Wasser), es ist
jedoch noch nicht bekannt, um welchen Typ
der obigen Definitionen es sich handeln
wird.
Definieren Sie die obigen nominalen Werte und schreiben Sie danach die folgenden Methoden (Dabei muss die Variable feld den entsprechenden nominalen Wert aufweisen).
setzeFeld(Bimaru b, int x, int y, String feld)
leseFeld (Bimaru b, int x, int y) : String
-> x, y = SpaltenNummer, ZeilenNummer
setzeSchiffeProZeile (Bimaru b, int y, int anzahl)
setzeSchiffeProSpalte(Bimaru b, int x, int anzahl)
leseSchiffeProZeile (Bimaru b, int y) : int
leseSchiffeProSpalte (Bimaru b, int x) : int
-> Das sind die am Rande aufgeführten Zahlen
setzeAnzahlSchiffe(Bimaru b, int typ, int anzahl)
leseAnzahlSchiffe (Bimaru b, int typ) : int
-> typ: Einer, Zweier, Dreier oder Vierer (= Länge der Schiffe)
anzahl = Wie viele Schiffe des Typs sind total vorhanden.
Die "lese-" bzw. "setze"-Methoden werden im Englischen getter- bzw. setter-Methoden genannt.
Option: Ersetzen Sie "String" durch einen Enumerationstypen.
//TODO: Evtl. als Kleinprojekt formulieren, denn nur so, macht es vielleicht gar keinen Spaß.
0 Kommentare
1 Lösung(en)
// TODO irgendwann:
// 1. verkürzung der zweiten und dritten abteilung
// (ohne die lesbarkeit zu verschlechtern)
// 2. plausbilitätsüberprüfungen der eingaben
/*---------------------------------------------------*\
| S T R U K T U R E I N E R P B N |
|=====================================================|
| PBN = Portable Bimaru Notation (hab ich mir |
| gerade ausgedacht) |
|-----------------------------------------------------|
| SYMBOLE der PBN-meerbeschreibung |
| (leerzeichen) = ungelöstes feld |
| ~ = wasser |
| X = schiffsteil ohne erkennbares ende |
| O = einer |
| N = oberes schiffsende |
| S = unteres schiffsende |
| W = linkes schiffsende |
| E = rechtes schiffsende |
| x (zahl) = x leerfelder, |
| leerfelder am rechten rand können |
| weggelassen werden |
| . = leere zeile |
| / = ende einer zeile |
|-----------------------------------------------------|
| Meerbeschreibung des aufgabenbeispiels: |
| ./8~/././6~/7N/3~/././. |
|=====================================================|
| Eine PBN besteht aus 4 abteilungen, getrennt durch |
| Semikola: |
| [meerbeschreibung]; |
| [schiffsanzahl letzte spalte]; |
| [schiffsanzahl letzte zeile]; |
| [anzahl der schiffstypen] |
| wobei die letzten drei zahlengruppen sind, |
| getrennt durch leerzeichen. |
|=====================================================|
| So der plan... |
\*---------------------------------------------------*/
let Bimaru = function(size) {
this.size = size;
this.sea = [];
// $sea initialisieren
for (let x = 0; x <= this.size; x++) {
this.sea[x] = new Array(this.size+1).fill(' ');
}
this.setField = function(x, y, item) {
this.sea[x][y] = item;
}
this.getField = function(x, y) {
return this.sea[x][y];
}
this.setShipsInRow = function(x, n) {
this.sea[x][this.size] = n;
}
this.setShipsInCol = function(y, n) {
this.sea[this.size][y] = n;
}
this.getShipsInRow = function(x) {
return this.sea[x][this.size];
}
this.getShipsInCol = function(y) {
return this.sea[this.size][y];
}
// statt setzeAnzahlSchiffe und leseAnzahlSchiffe
// ... weil zu trivial:
this.ships = []; // [einer, zweier, dreier, vierer]
this.toPBN = function() {
let pbn = [];
// erste abteilung:
// meerbeschreibung
let lines=[];
for (let i = 0; i < this.size; i++) { // $sea zeilenweise lesen
let line = '';
for (let j = 0; j < this.size; j++) line += this.sea[i][j];
lines.push(line);
}
for (i = 0; i < lines.length; i++) {
lines[i] = lines[i].trimEnd().split('');
if (lines[i].length == 0) lines[i] = '.';
else {
let str = '';
count = 0;
while (lines[i].length > 0) {
let tmp = lines[i].shift();
// leerfelder zählen
if (tmp == ' ') count++;
else {
if (count > 0) {
str += count + tmp;
count = 0;
} else str += tmp;
}
}
lines[i] = str;
}
}
pbn.push(lines.join('/'));
// zweite und dritte abteilung:
// schiffanzahl letzte spalte und letzte zeile
let arrC = [], arrR = [];
for (i = 0; i < this.size; i++) {
arrC.push(this.getShipsInCol(i));
arrR.push(this.getShipsInRow(i));
}
pbn.push(arrR.join(' '), arrC.join(' '));
// vierte abteilung:
// verwendete schiffe
pbn.push(this.ships.join(' '));
return pbn.join(';');
}
}
function parsePBN(pbn) {
pbn = pbn.split(';');
// erste abteilung:
// meerbeschreibung
let div = pbn.shift();
// das auszugebende bimaru
let b = new Bimaru(div.split('/').length);
div = div.split('');
// eventuelle mehrstellige ziffern zusammenfassen
for (let i = 0; i < div.length; i++)
if (div[i] == '.') div.splice(i, 1);
else if (!isNaN(div[i])) {
let j = i + 1;
while (!isNaN(div[j])) {
div[i] += '' + div[j];
div.splice(j, 1);
}
}
let x = 0; y = 0;
while (div.length > 0) {
let tmp = div.shift();
if (tmp == '/') { x++; y = 0; }
else if (!isNaN(tmp)) y += parseInt(tmp);
else b.setField(x, y, tmp);
}
// zweite und dritte abteilung:
// anzahl der schiffe in letzter spalte und zeile
let cols = pbn.shift().split(' '),
rows = pbn.shift().split(' ');
for (i = 0; i < b.size; i++) {
b.setShipsInCol(i, cols[i]);
b.setShipsInRow(i, rows[i]);
}
// vierte abteilung:
// verwendete schiffstypen
b.ships = pbn.shift().split(' ');
return b;
}
/*---------*\
| D E M O |
\*---------*/
// händische eingabe des aufgabenbeispiels
let b1 = new Bimaru(10);
b1.setField(1, 8, '~'); b1.setField(4, 6, '~');
b1.setField(5, 7, 'N'); b1.setField(6, 3, '~');
let rows = '1 3 1 1 1 3 6 1 2 1'.split(' '),
cols = '4 1 1 4 1 1 3 2 1 3'.split(' ');
for (let i = 0; i <= b1.size; i++) {
b1.setShipsInRow(i, rows[i]);
b1.setShipsInCol(i, cols[i]);
}
b1.ships = [4, 3, 2, 1];
console.table(b1.sea);
console.log(b1.ships);
console.log(b1.toPBN());
// erstellung eins bimaru per PBN
// beispiel nach https://de.wikipedia.org/wiki/Bimaru#/media/Datei:Bimaru_raetsel.gif
let desc = './7O/./4X/./././.;5 1 3 1 4 1 2 3;2 3 2 3 4 2 2 2;4 3 2 1';
let b2 = parsePBN(desc);
console.table(b2.sea);
console.log(b2.ships); // lissalanda@gmx.at
Lösung von: Lisa Salander (Heidi-Klum-Gymnasium Bottrop)
Aktionen
Neue Lösung hinzufügen
Bewertung
Durchschnittliche Bewertung:
Meta
Zeit: | 4.8 |
Schwierigkeit: | k.A. |
Webcode: | myrw-tke4 |
Autor: | Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch) |