Scala , 764 Bytes
object B{
def main(a: Array[String]):Unit={
val v=false
val (m,l,k,r,n)=(()=>print("\033[H\033[2J\n"),a(0)toInt,a(1)toInt,scala.util.Random,print _)
val e=Seq.fill(k, l)(v)
m()
(0 to (l*k)/2-(l*k+1)%2).foldLeft(e){(q,_)=>
val a=q.zipWithIndex.map(r => r._1.zipWithIndex.filter(c=>
if(((r._2 % 2) + c._2)%2==0)!c._1 else v)).zipWithIndex.filter(_._1.length > 0)
val f=r.nextInt(a.length)
val s=r.nextInt(a(f)._1.length)
val i=(a(f)._2,a(f)._1(s)._2)
Thread.sleep(1000)
m()
val b=q.updated(i._1, q(i._1).updated(i._2, !v))
b.zipWithIndex.map{r=>
r._1.zipWithIndex.map(c=>if(c._1)n("X")else if(((r._2 % 2)+c._2)%2==0)n("O")else n("_"))
n("\n")
}
b
}
}
}
Wie es funktioniert
Der Algorithmus füllt zuerst eine 2D-Sequenz mit falschen Werten. Anhand der eingegebenen Befehlszeilenargumente wird festgelegt, wie viele Iterationen (offene Kästchen) vorhanden sind. Es wird eine Falte mit diesem Wert als Obergrenze erstellt. Der ganzzahlige Wert der Falte wird nur implizit verwendet, um zu zählen, für wie viele Iterationen der Algorithmus ausgeführt werden soll. Die zuvor erstellte gefüllte Sequenz ist die Startsequenz für die Falte. Dies wird verwendet, um eine neue 2D-Sequenz falscher Werte mit ihren entsprechenden Abhängigkeiten zu generieren.
Beispielsweise,
[[false, true],
[true, false],
[true, true]]
Wird verwandelt in
[[(false, 0)], [(false, 1)]]
Beachten Sie, dass alle Listen, die vollständig wahr sind (eine Länge von 0 haben), in der Ergebnisliste weggelassen werden. Der Algorithmus nimmt dann diese Liste und wählt eine zufällige Liste in der äußersten Liste aus. Die Zufallsliste wird als die zufällige Zeile ausgewählt, die wir auswählen. Aus dieser Zufallszeile finden wir wiederum eine Zufallszahl, einen Spaltenindex. Sobald wir diese beiden Zufallsindizes gefunden haben, schlafen wir den Thread, auf dem wir uns befinden, für 1000 Millisekunden.
Nachdem wir schlafen gegangen sind, löschen wir den Bildschirm und erstellen ein neues Board mit einem true
Wert, der in den von uns erstellten Zufallsindizes aktualisiert wurde.
Um dies richtig auszudrucken, verwenden wir es map
und komprimieren es mit dem Index der Karte, damit wir das in unserem Kontext haben. Wir verwenden den Wahrheitswert der Sequenz, um festzustellen, ob wir ein X
oder eines O
oder drucken sollen _
. Für letztere verwenden wir den Indexwert als Richtwert.
Interessante Dinge zu beachten
Um herauszufinden, ob ein O
oder ein ausgegeben werden soll _
, wird die Bedingung ((r._2 % 2) + c._2) % 2 == 0
verwendet. r._2
verweist auf den aktuellen Zeilenindex, während c._2
auf die aktuelle Spalte verwiesen wird. Befindet man sich in einer ungeraden Zeile, r._2 % 2
so ist dies 1 und wird daher c._2
in der Bedingung um eins versetzt. Dies stellt sicher, dass in ungeraden Zeilen die Spalten wie vorgesehen um 1 verschoben werden.
Das "\033[H\033[2J\n"
Ausdrucken der Zeichenfolge löscht den Bildschirm gemäß einer von mir gelesenen Stackoverflow-Antwort. Es schreibt Bytes an das Terminal und erledigt ein paar unkonventionelle Dinge, die ich nicht wirklich verstehe. Aber ich habe festgestellt, dass es der einfachste Weg ist, dies zu tun. Auf dem Konsolenemulator von Intellij IDEA funktioniert dies jedoch nicht. Sie müssen es mit einem normalen Terminal ausführen.
Eine andere Gleichung, die man beim ersten Blick auf diesen Code als seltsam empfinden könnte, ist (l * k) / 2 - (l * k + 1) % 2
. Lassen Sie uns zuerst die Variablennamen entmystifizieren. l
verweist auf die ersten Argumente, die an das Programm übergeben werden, während k
auf das zweite Argument verwiesen wird . Übersetzen sie, (first * second) / 2 - (first * second + 1) % 2
. Das Ziel dieser Gleichung ist es, die genaue Anzahl der Iterationen zu ermitteln, die erforderlich sind, um eine Folge aller X zu erhalten. Das erste Mal, als ich das tat, tat ich einfach so, (first * second) / 2
wie es Sinn machte. Für jedes n
Element in jeder Unterliste gibt es n / 2
Blasen, die wir platzen lassen können. Dies bricht jedoch beim Umgang mit Eingaben wie(11 13)
. Wir müssen das Produkt der beiden Zahlen berechnen, es ungerade machen, wenn es gerade ist und gerade, wenn es ungerade ist, und dann die Modifikation um 2 nehmen. Dies funktioniert, weil Zeilen und Spalten, die ungerade sind, eine Iteration weniger erfordern um zum Endergebnis zu gelangen.
map
wird anstelle von a verwendet, forEach
da es weniger Zeichen enthält.
Dinge, die wahrscheinlich verbessert werden können
Eine Sache, die mich an dieser Lösung wirklich stört, ist die häufige Verwendung von zipWithIndex
. Es nimmt so viele Charaktere auf. Ich habe versucht, es so zu gestalten, dass ich meine eigene Ein-Zeichen-Funktion definieren kann, die nur zipWithIndex
mit dem übergebenen Wert ausgeführt wird. Es stellt sich jedoch heraus, dass Scala einer anonymen Funktion keine Typparameter erlaubt. Es gibt wahrscheinlich einen anderen Weg, um das zu tun, was ich mache, ohne es zu benutzen, zipWithIndex
aber ich habe nicht zu viel über einen klugen Weg nachgedacht, es zu tun.
Derzeit wird der Code in zwei Durchgängen ausgeführt. Der erste generiert eine neue Karte, während der zweite Durchgang sie druckt. Ich denke, dass, wenn man diese zwei Durchläufe in einem Durchlauf kombinieren würde, das ein paar Bytes sparen würde.
Dies ist das erste Codegolf, das ich gemacht habe, daher bin ich mir sicher, dass es viel Raum für Verbesserungen gibt. Wenn Sie den Code sehen möchten, bevor ich ihn so weit wie möglich auf Bytes optimiert habe, finden Sie ihn hier.
1
und0
anstelle vonO
und verwendenX
?