dedlfix: Haskell Lösung

Beitrag lesen

Tach!

Wenn du mich meinst … 🤪 Die ist auf CodePen

Ich habe sie mal hierher geholt und nehmn sie mal etwas auseinander.

const n = 1000, k = 3, start = 0;

n und k - typisch Mathematiker. Diese Bezeichner gehen zwar so aus der Aufgabenstellung hervor, aber zum Verständnis ihrer Funktion sind sie nicht besonders geeignet.

let prisoners = [], i;

// fill array with numbers from 1 through n
for (i = 1; i <= n; i++)
{
	prisoners.push(i);
}

Kommentare sollen beschreiben, was man nicht oder nur umständlich aus dem Code erkennen kann.

Eine Zählschleife und ein Push in ein Array füllt natürlich ein Array, was auch sonst?

i = start;

Die Wiederverwendung von Variablen für unterschiedliche Aufgaben sollte man vermeiden. Das führt nur zu Missverständnissen. Besser wäre gewesen, dem i im for ein let zu spendieren, dort lebt es dann in seinem eigenen Scope. Das andere i sollte man bei der prisoners-Deklaration weglassen und stattdessen der obigen Zeile ein let voranstellen, um es für den nachfolgenden Teil anzulegen.

while (prisoners.length >= k)
{
	i = (i - 1 + k) % prisoners.length; // index of next element to be removed
	prisoners.splice(i, 1); // remove element of index i from array
}

Auch hier erklären die beiden Kommentare nichts, was nicht bereits in der Dokumentation zu splice() zu finden ist. Ein Element aus dem Array zu entfernen ist ureigenste Aufgabe von splice(). Dass das i ein Platzhalter für das zu entfernende Element sein soll, sieht man auch problemlos. Es wäre etwas anders, wenn man eine Funktion missbraucht oder in ungewöhnlicher Weise anwendet. Ein Beispiel wäre foo = bar.slice(). slice() ist eigentlich dazu da, einen Teil aus einem Array zu kopieren. Ohne Parameter kopiert es das gesamte Array (shallow copy), was dann aber kein schneiden (to slice) mehr ist. Somit stimmt der damit erledigte Anwendungsfall, eine Kopie eines Array zu erzeugen (shallow copy), nicht mehr mit dem Namen der Funktion überein. Hier könnte man einen Kommentar anbringen, wenn man davon ausgehen kann, dass das Zielpublikum diesen nicht ganz unbekannten Javascript-Trick nicht kennt.

Jedenfalls wäre hier interessanter gewesen, die Überlegungen niederzuschreiben, die zu der verwendeten Formel führten.


Eine Lösung (fast) ohne Kommentare kann ich auch bieten, hab sie aber eben erst erstellt und nicht eingereicht.

const inmateCount = 10;
const countTo = 3;
const amnesty = countTo - 1;

let inmates = [...Array(inmateCount + 1).keys()].slice(1);
let backToCell = countTo - 1; // starts with countTo but zero-based
while (inmates.length > amnesty) {
    let rest = inmates.length % countTo;
    inmates = inmates.filter((_, index) => index % countTo != backToCell);
    backToCell = (backToCell - rest + countTo) % countTo;
}
console.log(inmates);

Hilfreiche Kommentare an den wichtigsten Stellen kann ich keine geben, weil ich die Lösung nicht wirklich erklären kann. Ich hab mit Hilfe von Graphit auf Pflanzenfasern gefummelt, bis ich einen funktionierenden Algorithmus hatte. Ein Bild davon zu zeigen bringt nichts, weil man aus den Zahlenreihen meine Gedankengänge nicht erkennen kann. Relativ einfach ist noch der Filter zu verstehen. Der Ausdruck muss false liefern, wenn die Zählung beim x-ten Insassen vorbeikommt. Die anderen zwei Zeilen dienen zum Nachjustieren um am Ende des Kreises den Offset für die nächste Runde zu justieren. Aber fragt mich nicht nach den Details, das ist mir zu kompliziert zu erklären.

dedlfix.