Pen & Paper - Rollenspiel > Werkstatt
Covella - Fantasy-Kalender - DSL für beliebige Systeme von Zeitmessung
1of3:
--- Zitat ---Eine Herausforderung hierbei wird es sein, unterschiedliche (fiktive) Kalender zu unterstützen.
--- Ende Zitat ---
Das scheint mir jetzt gerade das einfachste an dem Unterfangen. Wenn du willst, helf ich da gern. Mit welcher Sprache willst du das genau machen? Ich vermute Java? (Mein Favorit ist Scala.)
Talwyn:
Für Android habe ich Scala noch nicht verwendet. Was ich mit Herausforderung bei den Kalendern meinte ist: Es sollte für Nicht-Programmierer möglich sein, auf relativ einfache Weise den Kalender ihrer Spielwelt so zu beschreiben, dass die App damit arbeiten kann.
1of3:
Verstehe. Dann schauen wir doch mal.
Ein Kalendersystem ist ein Objekt, das eine Liste von Tages-Zyklen enthält. Bei uns ist das der Jahreszyklus und der Wochenzyklus. (Wir können auch weitere Zyklen wie etwa den Mondzyklus oder die Jahreszeiten hinzunehmen.)
--- Code: ---case class CalendarSystem (cycle : Days*)
--- Ende Code ---
Wir brauchen also Klassen für Mengen von Tagen. Diese Klassen sollten komponierbar sein und wieder Tage ergeben. Wir möchten zudem sicher wissen, wie viele Tage eine Instanz von Days enthält.
--- Code: ---abstract class Days {
def number : Int}
case class SimpleDays(number: Int) extends Days{
def + (that: SimpleDays) = CompoundDays(List(this, that))
def + (those: CompoundDays) = CompoundDays(this + those.comps)
}
case class CompoundDays (comps : Seq[Days]) extends Days {
def number = comps map (_ number) sum
def + (that: SimpleDays) = CompoundDays(this.comps :+ that)
def + (those: CompoundDays) = CompoundDays(this.comps ++ those.comps)
}
--- Ende Code ---
Um das ganze brauchbar zu machen, müssen wir Tage mit einem Bezeichner ausstatten können, also z.B. Woche, Monat, Jahr. Zudem haben einige Days-Objekte Eigennamen, wie Mittwoch oder Januar. Um das ganze anschaulich zu machen, fügen wir passend benannte Setter hinzu.
Unsere abstrakte Klasse sieht nun so aus.
--- Code: ---abstract class Days {
def number : Int
var designation: Option[String] = None
var name: Option[String] = None
def as(des : String) designation = Some(des)
def named(nam : String) name = Some(nam)
}
--- Ende Code ---
Für größere Konvenienz wählen wir zwei Factory-Funktionen für Tages-Objekte.
--- Code: ---object Days{
def apply(number : Int) = SimpleDays(number)
def apply(names: String*) = names map (SimpleDays(1) named _) foldLeft(Days.empty,_+_)
}
--- Ende Code ---
Wir können einen Kalender nun so definieren.
--- Code: ---val woche = Days("Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag") as "Woche"
val januar = Days 31 as "Monat" named "Januar"
val februar = Days 28 as "Monat" named "Februar"
val schaltFebruar = Days 29 as "Monat" named "Februar"
val maerz = Days 31 as "Monat" named "März"
val april = Days 30 as "Monat" named "April"
val mai = Days 31 as "Monat" named "Mai"
val juni = Days 30 as "Monat" named "Juni"
val juli = Days 31 as "Monat" named "Juli"
val august = Days 31 as "Monat" named "August"
val september = Days 30 as "Monat" named "September"
val oktober = Days 31 as "Monat" named "Oktober"
val november = Days 30 as "Monat" named "November"
val dezember = Days 31 as "Monat" named "Dezember"
val jahr = (januar + februar + maerz + april + mai + juni + juli + august + september + oktober + november + dezember) as "Jahr"
val schaltjahr = (januar + schaltFebruar+ maerz + april + mai + juni + juli + august + september + oktober + november + dezember) as "Jahr"
julianisch = CalendarSystem (woche, jahr + jahr + jahr + schaltjahr)
--- Ende Code ---
Damit das System gültig ist, liefert der Konstruktor eine Fehlermeldung, wenn…
[*] Bezeichner in unterschiedlichen Zykeln auftreten. Wenn der erste Zyklus etwas namens "Woche" enthält, darf der zweite Zyklus das nicht.
[*] Wenn CompoundDays den selben Bezeichner tragen, wie eines ihrer Elemente. Ein "Monat" darf also z.B. keine Monate enthalten.
Mit einem Kalendersystem können wir aber noch nicht arbeiten. Wir brauchen mindestens ein Start-Datum, dass die Zykel synkronisiert. Wir müssen also für mindestens ein Jahr und einen Tag im Jahr wissen, welcher Wochentag das ist.
Wir brauchen also ein weiteres Objekt, nennen wir es Era. Nutzerfreundlich benutzen wir eine Factory-Funktion auf unserem CalendarSystem. Nennen wir sie startWith. Also in unserem Fall z.B.
--- Code: ---val julianischerKalender = julianisch startWith ("Samstag", 1)
--- Ende Code ---
Ich nehme für die Funktion zunächst passende Überladungen an.
Nota bene: Der erste Januar im Jahre 1 war ein Samstag, jedenfalls wenn wir das ausrechnen. Die Planetenwoche war noch nicht sehr in Mode und die Zählung ab Christi Geburt noch nicht erfunden.
Es sollte vielleicht noch passende Funktionen geben, um ein Days-Objekt zu wiederholen. Ich hätte keine Lust den gregorianischen Kalender auf diese Weise zu schreiben. Natürlich kommen realiter Kalenderwechsel und Reformen vor. Davon würde ich absehen. That way lies madness.
Womöglich ist es aber gewünscht auch mit dem Jahr 1970 starten zu können, als mit einem Tag aus der ersten Jahresrunde. Da bräuchte es dann eine erweiterte startWith-Funktion. Das ließe sich vielleicht auch mit benannten Jahren, etwa im Stil vom Year of Blue Fire der Forgotten Realms oder den Konsulzählungen der Römer kombinieren.
Letztlich braucht es eine Klasse für bestimmte Daten mit passenden Gettern und Methoden wie next und previous.
Antariuk:
Ich verstehe von 1of3s Beitrag leider kaum etwas da ich 0,0 Programmierkenntnisse habe, aber wenn es um Kalendaerfunktionalitäten geht finde ich das Eberron Calendar Tool von Wizards immer eine coole Vorlage um zu sehen, was man theoretisch machen könnte. Das Feature der Existenzebenen mit den waning/waxing/coterminous Zuständen könnten in anderen Settings auch Monde sein, wenn man das eine offen eintragbare Funktion macht.
firstdeathmaker:
Das Problem mit den Kalendern sehe ich auch eher darin, dass sie zwar in unserer realen Welt noch eingermaßen gut funktionieren (sieht man mal von den ganzen Ausnahmen ab), aber eben nur bedingt flexibel für sämtliche Fantasy-Settings funktionieren. Und ich will ein Fantasysetting vielleicht nicht nur nach äquitemporaler Zeit gelten lassen.
Ein wirklich umfassendes Kalendersystem für Fantasy, das man konfigurieren kann, sollte folgende Funktionen besitzen (nicht zwingend, aber um so mehr nach unten hin, um so flexibler wäre es):
Normaler heutiger benutzter Kalender
Kalender, die verschiedene Zeitalter und darin unterschiedliche Zeitrechnungen berücksichtigen. z.B. im ersten Zeitalter 8-Tage Wochen, 50-70 Tage Monate), im zweiten Zeitalter 5-Tage Wochen etc.
Lunare römische Kalender
Maya-Kalender
Weltenübergreifender Kalender (wie im oben geposteten Tool https://www.wizards.com/dnd/ec/index.htm) mit unterschiedlich schnell vergehender Zeit
Nichtlinearer Zeitfluss Kalender (für Zeitreisenszenarios mit alternativen Realitäten)
Nichtkonstanter Zeitfluss (Relativistischer Kalender für so etwas wie im Film "Interstellar")
Und da wird es halt extrem frickelig. Das Thema "Kalender" lasse ich bei meinem Tool bewusst aus. Dafür bräuchte man auch etwas mehr Dynamik als man mit HTML ohne weiteres realisieren kann.
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln