Scala , 764 byte
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
}
}
}
Come funziona
L'algoritmo riempie prima una sequenza 2D con valori falsi. Determina quante iterazioni (caselle aperte) esistono in base agli argomenti della riga di comando inseriti. Crea una piega con questo valore come limite superiore. Il valore intero della piega viene utilizzato implicitamente solo come modo per contare il numero di iterazioni per cui dovrebbe essere eseguito l'algoritmo. La sequenza riempita che abbiamo creato in precedenza è la sequenza iniziale per la piega. Questo è usato per generare una nuova sequenza 2D di valori falsi con le loro indecie rispondenti alle risposte.
Per esempio,
[[false, true],
[true, false],
[true, true]]
Sarà trasformato in
[[(false, 0)], [(false, 1)]]
Si noti che tutti gli elenchi che sono completamente veri (hanno una lunghezza di 0) vengono omessi dall'elenco dei risultati. L'algoritmo quindi prende questo elenco e seleziona un elenco casuale nell'elenco più esterno. L'elenco casuale viene scelto per essere la riga casuale che scegliamo. Da quella riga casuale, troviamo di nuovo un numero casuale, un indice di colonna. Una volta trovati questi due indici casuali, dormiamo il thread su cui ci troviamo per 1000 milisecondi.
Dopo aver finito di dormire, cancelliamo lo schermo e creiamo una nuova scheda con un true
valore aggiornato negli indici casuali che abbiamo creato.
Per stamparlo correttamente, lo utilizziamo map
e lo comprimiamo con l'indice della mappa in modo da tenerlo nel nostro contesto. Usiamo il valore di verità della sequenza sul fatto se dovremmo stampare un X
o o un O
o _
. Per scegliere quest'ultimo, utilizziamo il valore dell'indice come nostra guida.
Cose interessanti da notare
Per capire se dovrebbe stampare un O
o un _
, ((r._2 % 2) + c._2) % 2 == 0
viene utilizzato il condizionale . r._2
si riferisce all'indice di riga corrente mentre si c._2
riferisce alla colonna corrente. Se uno è su una riga dispari, r._2 % 2
sarà 1, quindi compensato c._2
da uno nel condizionale. Ciò garantisce che sulle righe dispari, le colonne vengano spostate di 1 come previsto.
La stampa della stringa "\033[H\033[2J\n"
, secondo alcune risposte StackOverflow che ho letto, cancella lo schermo. Scrive byte sul terminale e fa cose funky che non capisco davvero. Ma l'ho trovato il modo più semplice per farlo. Tuttavia, non funziona sull'emulatore di console di Intellij IDEA. Dovrai eseguirlo usando un terminale normale.
Un'altra equazione che potresti trovare strana da vedere quando si guarda questo codice per la prima volta (l * k) / 2 - (l * k + 1) % 2
. Innanzitutto, demistificare i nomi delle variabili. l
fa riferimento ai primi argomenti passati nel programma mentre k
fa riferimento al secondo. Per tradurlo, (first * second) / 2 - (first * second + 1) % 2
. L'obiettivo di questa equazione è trovare l'esatta quantità di iterazioni necessarie per ottenere una sequenza di tutte le X. La prima volta che l'ho fatto, ho fatto semplicemente (first * second) / 2
quello che aveva senso. Per ogni n
elemento in ciascun elenco secondario, ci sono n / 2
bolle che possiamo far scoppiare. Tuttavia, ciò si interrompe quando si tratta di input come(11 13)
. Dobbiamo calcolare il prodotto dei due numeri, renderlo dispari se è pari e anche se è dispari, quindi prendere la mod di quello per 2. Funziona perché le righe e le colonne che sono dispari richiedono una iterazione in meno per arrivare al risultato finale.
map
è usato al posto di a forEach
perché ha meno caratteri.
Cose che probabilmente possono essere migliorate
Una cosa che mi infastidisce davvero di questa soluzione è l'uso frequente di zipWithIndex
. Sta prendendo così tanti personaggi. Ho provato a farlo in modo da poter definire la mia funzione di un carattere che si limiterebbe a eseguire zipWithIndex
con il valore passato. Ma si scopre che Scala non consente a una funzione anonima di avere parametri di tipo. C'è probabilmente un altro modo di fare quello che sto facendo senza usare, zipWithIndex
ma non ho pensato troppo a un modo intelligente per farlo.
Attualmente, il codice viene eseguito in due passaggi. Il primo genera una nuova scheda mentre il secondo passaggio la stampa. Penso che se si combinassero questi due passaggi in un unico passaggio, si risparmierebbero un paio di byte.
Questo è il primo codice golf che ho fatto, quindi sono sicuro che ci sia molto spazio per miglioramenti. Se desideri vedere il codice prima che io abbia ottimizzato il più possibile i byte, eccolo qui.
1
e0
invece diO
eX
?