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
}
}
}
Bagaimana itu bekerja
Algoritme pertama mengisi Urutan 2D dengan nilai-nilai salah. Ini menentukan berapa banyak iterasi (kotak terbuka) yang ada berdasarkan argumen baris perintah yang dimasukkan. Ini menciptakan lipatan dengan nilai ini sebagai batas atas. Nilai integer dari lipatan hanya digunakan secara implisit sebagai cara untuk menghitung berapa banyak iterasi yang harus dijalankan oleh algoritma. Urutan diisi yang kita buat sebelumnya adalah urutan awal untuk lipatan. Ini digunakan dalam menghasilkan urutan 2D baru dari nilai palsu dengan indek cooresponding mereka.
Sebagai contoh,
[[false, true],
[true, false],
[true, true]]
Akan diubah menjadi
[[(false, 0)], [(false, 1)]]
Perhatikan bahwa semua daftar yang sepenuhnya benar (memiliki panjang 0) dihilangkan dari daftar hasil. Algoritme kemudian mengambil daftar ini dan memilih daftar acak di daftar terluar. Daftar acak dipilih sebagai baris acak yang kita pilih. Dari baris acak itu, kita kembali menemukan angka acak, indeks kolom. Setelah kami menemukan dua indeks acak ini, kami tidur utasnya selama 1000 milidetik.
Setelah kami selesai tidur, kami membersihkan layar dan membuat papan baru dengan true
nilai yang diperbarui dalam indeks acak yang telah kami buat.
Untuk mencetak ini dengan benar, kami menggunakan map
dan zip dengan indeks peta sehingga kami memilikinya dalam konteks kami. Kami menggunakan nilai kebenaran dari urutan, apakah kami harus mencetak X
atau salah satu O
atau_
. Untuk memilih yang terakhir, kami menggunakan nilai indeks sebagai panduan kami.
Hal-hal menarik untuk diperhatikan
Untuk mengetahui apakah harus mencetak O
atau _
, kondisi ((r._2 % 2) + c._2) % 2 == 0
digunakan. r._2
merujuk ke indeks baris saat ini sementara c._2
mengacu pada kolom saat ini. Jika seseorang berada di baris aneh, r._2 % 2
akan menjadi 1, oleh karena itu mengimbangi c._2
dengan satu di kondisi. Ini memastikan bahwa pada baris ganjil, kolom dipindahkan oleh 1 sebagaimana dimaksud.
Mencetak string "\033[H\033[2J\n"
, menurut beberapa jawaban Stackoverflow yang saya baca, membersihkan layar. Ini menulis byte ke terminal dan melakukan beberapa hal funky yang saya tidak begitu mengerti. Tetapi saya telah menemukan ini sebagai cara termudah untuk melakukannya. Ini tidak bekerja pada emulator konsol Intellij IDEA. Anda harus menjalankannya menggunakan terminal reguler.
Persamaan lain yang mungkin aneh untuk dilihat ketika pertama kali melihat kode ini adalah (l * k) / 2 - (l * k + 1) % 2
. Pertama, mari kita demistifikasikan nama-nama variabel. l
mengacu pada argumen pertama yang diteruskan ke program sementara k
mengacu pada argumen kedua. Untuk menerjemahkannya (first * second) / 2 - (first * second + 1) % 2
,. Tujuan dari persamaan ini adalah untuk menghasilkan jumlah iterasi yang dibutuhkan untuk mendapatkan urutan semua X. Pertama kali saya melakukan ini, saya hanya melakukan (first * second) / 2
itu masuk akal. Untuk setiap n
elemen di setiap sublist, ada n / 2
gelembung yang dapat kami pop. Namun, ini rusak ketika berhadapan dengan input seperti(11 13)
. Kita perlu menghitung produk dari dua angka, membuatnya aneh jika itu genap, dan bahkan jika itu aneh, dan kemudian mengambil mod itu dengan 2. Ini bekerja karena baris dan kolom yang aneh akan membutuhkan satu iterasi lebih sedikit untuk sampai ke hasil akhir.
map
digunakan sebagai ganti forEach
karena memiliki lebih sedikit karakter.
Hal-hal yang mungkin bisa diperbaiki
Satu hal yang benar-benar mengganggu saya tentang solusi ini adalah seringnya menggunakan zipWithIndex
. Itu mengambil begitu banyak karakter. Saya mencoba membuatnya sehingga saya bisa mendefinisikan fungsi satu karakter saya sendiri yang hanya akan tampil zipWithIndex
dengan nilai yang diteruskan. Tetapi ternyata Scala tidak mengizinkan fungsi anonim memiliki parameter tipe. Mungkin ada cara lain untuk melakukan apa yang saya lakukan tanpa menggunakan zipWithIndex
tetapi saya belum terlalu memikirkan cara cerdas untuk melakukannya.
Saat ini, kode berjalan dalam dua lintasan. Yang pertama menghasilkan papan baru sementara yang kedua mencetaknya. Saya pikir jika seseorang menggabungkan dua lintasan ini menjadi satu lintasan, itu akan menghemat beberapa byte.
Ini adalah golf kode pertama yang saya lakukan sehingga saya yakin ada banyak ruang untuk perbaikan. Jika Anda ingin melihat kode sebelum saya mengoptimalkan byte sebanyak mungkin, ini dia.
1
dan0
bukannyaO
danX
?