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
}
}
}
Làm thế nào nó hoạt động
Thuật toán trước tiên điền vào Chuỗi 2D với các giá trị sai. Nó xác định có bao nhiêu lần lặp (hộp mở) tồn tại dựa trên các đối số dòng lệnh được đặt vào. Nó tạo ra một nếp gấp với giá trị này là giới hạn trên. Giá trị nguyên của nếp gấp chỉ được sử dụng ngầm như một cách để đếm số lần lặp mà thuật toán nên chạy. Trình tự điền mà chúng ta đã tạo trước đây là trình tự bắt đầu cho nếp gấp. Điều này được sử dụng trong việc tạo ra một chuỗi 2D mới của các giá trị sai với các phân đoạn cooresponding của chúng.
Ví dụ,
[[false, true],
[true, false],
[true, true]]
Sẽ bị biến thành
[[(false, 0)], [(false, 1)]]
Lưu ý rằng tất cả các danh sách hoàn toàn đúng (có độ dài bằng 0) được bỏ qua khỏi danh sách kết quả. Thuật toán sau đó lấy danh sách này và chọn một danh sách ngẫu nhiên trong danh sách ngoài cùng. Danh sách ngẫu nhiên được chọn là hàng ngẫu nhiên chúng tôi chọn. Từ hàng ngẫu nhiên đó, chúng ta lại tìm thấy một số ngẫu nhiên, một chỉ mục cột. Khi chúng tôi tìm thấy hai chỉ số ngẫu nhiên này, chúng tôi ngủ chuỗi chúng tôi đang ở trong 1000 giây.
Sau khi ngủ xong, chúng tôi xóa màn hình và tạo một bảng mới với true
giá trị được cập nhật trong các chỉ số ngẫu nhiên mà chúng tôi đã tạo.
Để in nó ra một cách chính xác, chúng tôi sử dụng map
và nén nó với chỉ mục của bản đồ để chúng tôi có nó trong bối cảnh của chúng tôi. Chúng tôi sử dụng giá trị thật của chuỗi để xem chúng tôi nên in một X
hoặc một O
hoặc _
. Để chọn cái sau, chúng tôi sử dụng giá trị chỉ mục làm hướng dẫn.
Những điều thú vị cần lưu ý
Để tìm ra nếu nó nên in một O
hoặc một _
, điều kiện ((r._2 % 2) + c._2) % 2 == 0
được sử dụng. r._2
đề cập đến chỉ số hàng hiện tại trong khi c._2
đề cập đến cột hiện tại. Nếu một trong một hàng lẻ, r._2 % 2
sẽ là 1, do đó bù đắp c._2
cho một trong điều kiện. Điều này đảm bảo rằng trên các hàng lẻ, các cột được di chuyển qua 1 như dự định.
In ra chuỗi "\033[H\033[2J\n"
, theo một số câu trả lời Stackoverflow tôi đọc, xóa màn hình. Đó là viết byte cho thiết bị đầu cuối và làm một số thứ thú vị mà tôi không thực sự hiểu. Nhưng tôi đã tìm thấy nó là cách dễ nhất để đi về nó. Mặc dù vậy, nó không hoạt động trên trình giả lập giao diện điều khiển của Intellij IDEA. Bạn sẽ phải chạy nó bằng thiết bị đầu cuối thông thường.
Một phương trình khác người ta có thể thấy lạ khi lần đầu tiên nhìn vào mã này (l * k) / 2 - (l * k + 1) % 2
. Đầu tiên, hãy làm sáng tỏ tên biến. l
đề cập đến các đối số đầu tiên được truyền vào chương trình trong khi k
đề cập đến đối số thứ hai. Để dịch nó , (first * second) / 2 - (first * second + 1) % 2
. Mục tiêu của phương trình này là đưa ra số lần lặp chính xác cần thiết để có được một chuỗi tất cả X. Lần đầu tiên tôi làm điều này, tôi chỉ làm (first * second) / 2
điều đó có ý nghĩa. Đối với mỗi n
yếu tố trong mỗi danh sách phụ, có những n / 2
bong bóng chúng ta có thể bật. Tuy nhiên, điều này bị phá vỡ khi xử lý các đầu vào như(11 13)
. Chúng ta cần tính toán tích của hai số, làm cho số lẻ thành số chẵn và thậm chí nếu nó là số lẻ, sau đó lấy mod của số đó bằng 2. Điều này hoạt động vì các hàng và cột lẻ sẽ yêu cầu một lần lặp ít hơn để đi đến kết quả cuối cùng.
map
được sử dụng thay forEach
vì bởi vì nó có ít ký tự hơn.
Những điều có lẽ có thể được cải thiện
Một điều thực sự làm tôi khó chịu về giải pháp này là việc sử dụng thường xuyên zipWithIndex
. Nó chiếm quá nhiều nhân vật. Tôi đã cố gắng làm cho nó để tôi có thể xác định hàm một ký tự của riêng mình sẽ thực hiện zipWithIndex
với giá trị được truyền vào. Nhưng hóa ra Scala không cho phép một hàm ẩn danh có các tham số loại. Có lẽ có một cách khác để làm những gì tôi đang làm mà không sử dụng zipWithIndex
nhưng tôi đã không nghĩ quá nhiều về một cách thông minh để làm điều đó.
Hiện tại, mã chạy trong hai lần. Cái đầu tiên tạo ra một bảng mới trong khi cái thứ hai in nó ra. Tôi nghĩ rằng nếu một người kết hợp hai đường chuyền này thành một đường chuyền, điều đó sẽ tiết kiệm được một vài byte.
Đây là mã golf đầu tiên tôi đã thực hiện nên tôi chắc chắn có rất nhiều chỗ để cải thiện. Nếu bạn muốn xem mã trước khi tôi tối ưu hóa cho byte càng nhiều càng tốt, thì đây là.
1
và0
thay vìO
vàX
?