Scala , 764 байт
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
}
}
}
Як це працює
Алгоритм спочатку заповнює 2D послідовність помилковими значеннями. Він визначає, скільки ітерацій (відкритих полів) існує на підставі аргументів командного рядка, що містяться. Це створює складку з цим значенням як верхню межу. Ціле значення згину використовується лише неявно як спосіб підрахунку кількості ітерацій, за якими повинен працювати алгоритм. Заповнена нами послідовність заповнена послідовністю є початковою послідовністю для складання. Це використовується для генерування нової 2D послідовності помилкових значень із співвідповідними індексами.
Наприклад,
[[false, true],
[true, false],
[true, true]]
Буде перетворений на
[[(false, 0)], [(false, 1)]]
Зауважте, що всі списки, які є повністю правдивими (мають довжину 0), у списку результатів опущені. Потім алгоритм приймає цей список і вибирає випадковий список у найбільш віддаленому списку. Випадковий список обирається як довільний рядок, який ми вибираємо. З цього випадкового рядка ми знову знаходимо випадкове число, індекс стовпця. Як тільки ми знайдемо ці два випадкові індекси, ми спимо нитку, на якій ми знаходимося, протягом 1000 мілісекунд.
Після закінчення сну ми очищаємо екран і створюємо нову дошку зі trueзначенням, оновленим у створених нами випадкових індексах.
Щоб правильно роздрукувати це, ми використовуємо mapта поштовуємо його індексом карти, щоб це було в нашому контексті. Ми використовуємо значення істинності послідовності щодо того, чи слід надрукувати Xабо, або Oабо _. Щоб вибрати останнє, ми використовуємо значення індексу як наш путівник.
Цікаві речі, що слід зазначити
Щоб зрозуміти, чи повинен він друкувати Oабо _, використовується умовний ((r._2 % 2) + c._2) % 2 == 0. r._2посилається на індекс поточного рядка, тоді як c._2посилається на поточний стовпець. Якщо один із непарних рядків, r._2 % 2буде 1, тому зміщується c._2на одне в умовному. Це гарантує, що на непарних рядках стовпці переміщуються на 1 за призначенням.
"\033[H\033[2J\n"Друкуючи рядок , згідно з деякою прочитаною вами відповіді Stackoverflow очищає екран. Це писати байти в термінал і робити якісь прикольні речі, які я насправді не розумію. Але я знайшов, що це найпростіший спосіб зробити це. Однак він не працює на емуляторі консолі Intellij IDEA. Вам доведеться запустити його за допомогою звичайного терміналу.
Ще одне рівняння, яке може бути дивним, коли ми вперше подивимось на цей код (l * k) / 2 - (l * k + 1) % 2. Спочатку давайте демістифікуємо імена змінних. lстосується перших аргументів, переданих у програму, тоді як kстосується другого. Щоб перекласти його (first * second) / 2 - (first * second + 1) % 2,. Мета цього рівняння - придумати точну кількість ітерацій, необхідних для отримання послідовності всіх X. Перший раз, коли я це робив, я просто робив це, (first * second) / 2як це мало сенс. Для всіх nелементів у кожному списку є n / 2бульбашки, які ми можемо випустити. Однак ця помилка під час роботи з такими входами, як(11 13). Нам потрібно обчислити добуток двох чисел, зробити його непарним, якщо це парне, і навіть якщо це непарне, а потім взяти мод на 2. Це працює, тому що рядки та стовпці, що непарно, потребують меншої ітерації щоб дійти до кінцевого результату.
mapвикористовується замість forEachсимволу a, оскільки він містить менше символів.
Речі, які, ймовірно, можуть бути покращені
Одне, що насправді клопоче мене про це рішення, - це часте використання zipWithIndex. Це займає стільки символів. Я намагався зробити це так, щоб я міг визначити свою власну функцію з одним символом, яка просто виконувала бzipWithIndex зі значенням, яке передається. Але виявляється, що Scala не дозволяє анонімній функції мати параметри типу. Можливо, є ще один спосіб робити те, що я роблю, не використовуючи, zipWithIndexале я не надто замислювався над розумним способом зробити це.
В даний час код працює в два проходи. Перша створює нову плату, а друга пропускає її. Я думаю, що якби поєднати ці два проходи в один прохід, це дозволить заощадити пару байтів.
Це перший гольф з кодом, який я зробив, тому впевнений, що є багато можливостей для вдосконалення. Якщо ви хочете побачити код, перш ніж я максимально оптимізував для байтів, ось він.
1і0замістьOіX?