1unitedpower: Haskell Lösung

Beitrag lesen

Die eingegangenen Lösungen von @Rolf B, @1unitedpower, @Camping_RIDER, @Gunnar Bittersmann und @encoder, empfinde ich zum Teil deutlich eleganter als meine, ich überlasse es ihnen, sie hier zu posten.

Zeigst du uns deine Lösung denn trotzdem?

Ich habe Haskell bemüht:

module Prisoners where

type Index = Int
type Size = Int
type Prisoner = Int

-- n Gefangene  haben sich in einem Kreis aufgestellt und wurden beginnend mit
-- 1 durchnummeriert. Angefangen mit dem (i+k)-ten Gefangen wird  nun jeder
-- k-te Gefangene zurück in seine Zelle geschickt, bis noch k-1 Gefangene übrig
-- sind, welche dann begnadigt werden.
-- Die Funktion `actOfGrace` liefert die Nummern der k-1 Gefangenen, die
-- entlassen werden.
actOfGrace :: Index -> Index -> Size -> [Prisoner]
actOfGrace k i n = dropKth k (i-1) [1..n]

-- Angefangen mit dem (i+k)-ten Element, entferne jedes k-te Element aus einem
-- Ring bis nur noch k-1 Elemente übrig sind. Die Zählung beginnt mit 0.
dropKth :: Index -> Index -> [a] -> [a]
dropKth k i xs
  = if (length xs == k - 1)               -- Abbruchbedingung erreicht?
      then xs                             -- Finales Ergebnis
      else dropKth k i' xs'               -- Entferne ein Element rekursiv
    where
      out = (i + k - 1) `mod` (length xs) -- zu entferneder Index
      xs' = remove out xs                 -- Ring um ein Element verkürzt
      i'  = out `mod` (length xs')        -- Beginn nächster Zählung

-- Entferne das n-te Element aus einer Liste. Die Zählung beginnt mit 0.
remove :: Index -> [a] -> [a]
remove n xs
  = (take n xs) ++ (drop (n+1) xs)

-- Test mit 10 Gefangenen, Zählbeginn bei 1 und jeder 3-te wird zurück auf die
-- Zelle geschickt bis nur noch 2 übrig sind.
test :: Bool
test
  = expected == actual
    where
      expected = [4, 10]
      actual = actOfGrace 3 1 10

Aber wenigstens die while-Schleife habe ich auch verwendet

In Haskell gibt es keine while-Schleifen oder irgendwelche Schleifen, da muss man auf Rekursion zurückgreifen. Das schöne an der Aufgabenstellung war, dass der Start-Index frei wählbar war, dadurch ergibt sich fast von alleine eine Tail-Rekrusion, die von Haskell automatisch so optimiert wird, dass der Callstack nicht anwächst.