Scala , 764 octets
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
}
}
}
Comment ça marche
L'algorithme remplit d'abord une séquence 2D avec de fausses valeurs. Il détermine combien d'itérations (boîtes ouvertes) existent en fonction des arguments de ligne de commande insérés. Il crée un pli avec cette valeur comme limite supérieure. La valeur entière du repli n'est utilisée qu'implicitement comme moyen de compter le nombre d'itérations pour lesquelles l'algorithme doit s'exécuter. La séquence remplie que nous avons créée précédemment est la séquence de départ du pli. Ceci est utilisé pour générer une nouvelle séquence 2D de fausses valeurs avec leurs indécies co-répondantes.
Par exemple,
[[false, true],
[true, false],
[true, true]]
Sera transformé en
[[(false, 0)], [(false, 1)]]
Notez que toutes les listes qui sont complètement vraies (ont une longueur de 0) sont omises de la liste des résultats. L'algorithme prend ensuite cette liste et sélectionne une liste aléatoire dans la liste la plus externe. La liste aléatoire est choisie pour être la ligne aléatoire que nous choisissons. À partir de cette ligne aléatoire, nous trouvons à nouveau un nombre aléatoire, un index de colonne. Une fois que nous avons trouvé ces deux indices aléatoires, nous dormons le thread sur lequel nous sommes pendant 1000 millisecondes.
Après avoir dormi, nous effaçons l'écran et créons un nouveau tableau avec une truevaleur mise à jour dans les indices aléatoires que nous avons créés.
Pour l'imprimer correctement, nous l'utilisons mapet le compressons avec l'index de la carte, nous l'avons donc dans notre contexte. Nous utilisons la valeur de vérité de la séquence pour savoir si nous devons imprimer un Xou un Oou ou _. Pour choisir ce dernier, nous utilisons la valeur de l'indice comme guide.
Choses intéressantes à noter
Pour déterminer s'il doit imprimer un Oou un _, le conditionnel ((r._2 % 2) + c._2) % 2 == 0est utilisé. r._2fait référence à l'index de ligne actuel tandis que c._2fait référence à la colonne actuelle. Si l'un est sur une ligne impaire, r._2 % 2sera 1, donc compensé c._2par un au conditionnel. Cela garantit que sur les lignes impaires, les colonnes sont déplacées de 1 comme prévu.
L'impression de la chaîne "\033[H\033[2J\n", selon une réponse de Stackoverflow que j'ai lue, efface l'écran. Il écrit des octets sur le terminal et fait des trucs géniaux que je ne comprends pas vraiment. Mais j'ai trouvé que c'était la manière la plus simple de s'y prendre. Cependant, cela ne fonctionne pas sur l'émulateur de console d'Intellij IDEA. Vous devrez l'exécuter à l'aide d'un terminal standard.
Une autre équation que l'on pourrait trouver étrange lors de la première lecture de ce code est (l * k) / 2 - (l * k + 1) % 2. Tout d'abord, démystifions les noms de variables. lfait référence aux premiers arguments passés dans le programme tandis que kfait référence au second. Pour le traduire, (first * second) / 2 - (first * second + 1) % 2. Le but de cette équation est de trouver le nombre exact d'itérations nécessaires pour obtenir une séquence de tous les X. La première fois que j'ai fait ça, j'ai fait (first * second) / 2comme ça avait du sens. Pour chaque nélément de chaque sous-liste, il y a des n / 2bulles que nous pouvons faire éclater. Cependant, cela casse lorsqu'il s'agit d'entrées telles que(11 13). Nous devons calculer le produit des deux nombres, le rendre impair s'il est pair et même s'il est impair, puis prendre le mod de cela par 2. Cela fonctionne parce que les lignes et les colonnes qui sont impaires nécessiteront une itération de moins pour arriver au résultat final.
mapest utilisé à la place d'un forEachcar il contient moins de caractères.
Des choses qui peuvent probablement être améliorées
Une chose qui me dérange vraiment dans cette solution est l'utilisation fréquente de zipWithIndex. Cela prend tellement de personnages. J'ai essayé de faire en sorte que je puisse définir ma propre fonction à un caractère qui fonctionnerait simplement zipWithIndexavec la valeur transmise. Mais il s'avère que Scala ne permet pas à une fonction anonyme d'avoir des paramètres de type. Il y a probablement une autre façon de faire ce que je fais sans utiliser, zipWithIndexmais je n'ai pas trop réfléchi à une façon intelligente de le faire.
Actuellement, le code s'exécute en deux passes. La première génère une nouvelle carte tandis que la deuxième passe l'imprime. Je pense que si l'on devait combiner ces deux passes en une seule, cela économiserait quelques octets.
C'est le premier golf de code que j'ai fait, donc je suis sûr qu'il y a beaucoup de place pour l'amélioration. Si vous souhaitez voir le code avant d'optimiser autant que possible les octets, le voici.
1et0au lieu deOetX?