Водопровод ASCII


19

Вступ

Розглянемо сітку таких символів f A\/, як

f  f  f  
      A  
   A / \ 
\ /     A
    A \/ 
   /     
 \/         

де:

  • f являє собою кран, який виливає струмінь води вниз
  • A роздвоює потік води вище, тому рівно половина йде вліво і рівно половина йде вправо
  • \ зміщує потік води вправо на одну одиницю
  • / зміщує потік води вліво на одну одиницю
  • комбінації \/створюють корито з нескінченною ємністю, що збирає над ним потоки води
  • [space] порожній простір, ніж вода може просуватися

Виходячи з цього, ми можемо уявити шлях, який пройшла би вода ( *), коли вона виходить зі змішувачів і потрапляє або в жолоби, або в зону сітки:

f  f  f    <-- first second and third faucets
*  * *A* 
* *A*/ \*
\*/ *  *A  <-- a '*' is not drawn to the right of this A because it would be out of the 9×7 bounds
 * *A*\/   <-- upper trough
 **/ *   
 \/  *     <-- lower trough

Якщо припустити, що три змішувачі виводять однакову кількість води одна за одною, ми можемо це бачити

  • Вся вода першого крана йде до нижнього жолоба.
  • Одна половина води другого крана йде до нижнього жолоба, а інша половина розділяється між нижньою жолобкою і падає з сітки.
  • Одна чверть води третього крана йде до нижнього жолоба, одна чверть випадає з нижньої частини сітки, одна чверть йде у верхнє жолоб, а одна чверть випадає з сітки праворуч.

З цього можна сказати, що (1 + 3/4 + 1/4 + 1/4) / 3 = 75%вода потрапляє в жолоби і (1/4 + 1/4 + 1/4) / 3 = 25%випадає з сітки.

Виклики

Ви можете виконати будь-які або всі ці виклики, пов'язані з цією установкою потоку води ASCII. Усі вони - код-гольф, найкоротша відповідь на кожен виклик - переможець. Прийнятою відповіддю буде особа, яка виконає більшість проблем, із загальною довжиною коду як краватка.

Завдання 1
Напишіть програму, яка видає частину води, яка стікає в жолоби для заданої сітки. Вихід з прикладу вище був би просто 0.75.

Завдання 2
Напишіть програму, яка, даючи сітку, малює *місця в місцях течії води, як я це робив вище. Не слід перезаписувати нічого, крім символів пробілу, а сітка не повинна змінювати розмір. Тож на щось подібне

 f
/A

нічого не потрібно робити, оскільки, хоча вода тече з обох боків А, її не можна витягнути ліворуч, не виймаючи, /і її неможливо втягнути вправо, не зробивши сітку 2 × 2 більшою.

Завдання 3 (оновлено)
Напишіть програму, яка приймає дві невід’ємні цілі числа, загальну кількість T та кількість, яка має зберегти K (T> = K). Створіть та намалюйте сітку саме з такоюf такою, що коли цей змішувач вилиє Т одиниці води, точно K перетече в жолоби. Якщо це неможливо зробити в кінцевій сітці для певної пари (T, K), тоді виведіть "Неможливо".

Роз'яснення (стосується всіх викликів)

  • Введення може здійснюватися через stdin, або файл, або навіть функціональний виклик у рядковому представленні сітки. Просто дайте зрозуміти, як запускати різні входи.
  • Вихід повинен перейти до stdout.
  • \Aі A/іAA також западини , як і слід було очікувати.
  • Сітка w by h завжди буде добре відформатованим прямокутником з w * h символів, не рахуючи нових рядків. Не буде пропущених пробілів і жодних подій* .
  • Розміри сітки можуть бути як 1 × 1, так і довільно великими. (Довільно велике в межах причини, int.maxValue або подібного є прийнятною межею. Те саме стосується T і K.)
  • fПрямо через нього тече потік над потоком.
  • Змішувачі можуть бути де завгодно, не тільки у верхньому ряду.
  • A завжди ділить кількість вилитої на нього води рівно навпіл.

Примітка. Такі речі подобаються /Aі //цілком дійсні. Вода робить вільно перетікати між символами (хоча для завдання 2 там не вистачає місця , щоб зробити це).

Отже, в налаштуваннях

ff

/A

Лівий fпотік ллється вниз, б'є /і зміщується вліво. Правий fпотік ллється вниз, б'є A, половина йде праворуч, а половина йде ліворуч між Aі /.

напр

 ff
 **
*/A*
** *
** *

3
+1 Приємний виклик. Що стосується виклику 3, то сітка вгорі не буде достовірною відповіддю, оскільки вона має 3 fс
edc65

@ edc65 Ах, хороший улов!
Захоплення Кальвіна


2
Для другого виклику вам потрібно вказати, як поводитись із входом, наприклад, /Aякщо вода потрапляє на воду A. Для всіх викликів було б добре уточнити, чи \Aце корито. Для третього виклику, чи слід Aвважати , що 3 одиниці, що падають на припущення, розбиваються 1.5 / 1.5(тож вхід є дійсно єдиним раціональним числом) чи це 2 / 1, у такому випадку, яка сторона отримує 2?
Пітер Тейлор

1
@PeterTaylor Дякую Я уточнив ці моменти. Я думаю, що T і K можуть бути поплавцями, але я зберігаю їх цілі числа для простоти. (Але якщо T = 3 вдарить, Aто обидві сторони отримують 1,5. Це залежить від кодера, щоб переконатися, що точність поплавця не є проблемою.)
Хобі Кальвіна

Відповіді:


3

Усі виклики C # 690 байт (416 байт + 274 байт)

Виклики 1 та 2 С # 579 446 416байт

Це повна програма, яка повинна виконувати Виклики 1 і 2, приблизно. Він читає рядки введення з stdin, поки не отримає порожній рядок. Він виводить результат для Challenge 2, а потім результат для Challenge 1. Використовує десятковий клас .NET, щоб сподіватися уникнути помилок округлення.

using C=System.Console;class P{static void Main(){decimal u,t=0,f=0;string c,z="";for(decimal[]n=null,o;(c=C.ReadLine())!="";z+='\n'){int s=c.Length,i=s,e;o=n;n=new decimal[s];for(o=o??n;i-->0;n[i]+=(e&2)*u/2){e=c[i]%13;u=o[i]/(e<1?2:1);if(e%8<1)if(i>0)if(c[i-1]%7<3)t+=u;else n[i-1]+=u;if(e<2)if(i<s-1)if(c[i+1]%2>0)t+=u;else n[i+1]+=u;if(e>9){u++;f++;}}for(;++i<s;)z+=c[i]<33&n[i]>0?'*':c[i];}C.WriteLine(z+t/f);}}

Менше гольфу:

using C=System.Console;
class P
{
    static void Main()
    {
        decimal u,t=0,f=0;
        string c,z="";

        for(decimal[]n=null,o;(c=C.ReadLine())!="";z+='\n')
        {
            int s=c.Length,i=s,e;
            o=n;
            n=new decimal[s];
            for(o=o??n;i-->0;n[i]+=(e&2)*u/2)
            {
                e=c[i]%13;
                u=o[i]/(e<1?2:1);

                if(e%8<1)
                    if(i>0)
                        if(c[i-1]%7<3)t+=u;
                        else n[i-1]+=u;
                if(e<2)
                    if(i<s-1)
                        if(c[i+1]%2>0)t+=u;
                        else n[i+1]+=u;
                if(e>9)
                {
                    u++;
                    f++;
                }
            }
            for(;++i<s;)
                z+=c[i]<33&n[i]>0?'*':c[i];
        }

        C.WriteLine(z+t/f);
    }
}

Тестовий пробіг (з відсутністю пробілів, які, я обіцяю, є):

f  f  f
      A
   A / \
\ /     A
    A \/
   /
 \/

f  f  f
*  * *A*
* *A*/ \*
\*/ *  *A
 * *A*\/
 **/ *
 \/  *
0.75

Завдання 3 C # 274байт

Це повна програма, яка повинна завершити виклик 3. Мені вдалося зберегти 6 байт, записавши власний цілочисельний аналізатор для читання введення, а не Spliting a ReadLineта використання long.Parse;

using C=System.Console;class P{static void Main(){long t=-1,f=t,k;for(;f<0;)for(f=t,t=0;(k=C.Read())>47;)t=t*10+k-48;var r="Impossible\n";for(k=t;k<t*f;)k*=2;if(f<1||(k/f)*f==k)for(r=" f \n";t>0&t<f;t-=(t/f)*f)r+=((t*=2)<f?" ":"A")+"A \n/ /\n";C.Write(r+(t<f?"":"AAA\n"));}}

Менше гольфу:

using C=System.Console;
class P
{
    static void Main()
    {
        long t=-1,f=t,k;
        for(;f<0;)
            for(f=t,t=0;(k=C.Read())>47;)
                t=t*10+k-48;

        var r="Impossible\n";
        for(k=t;k<t*f;)
            k*=2;
        if(f<1||(k/f)*f==k)
            for(r=" f \n";t>0&t<f;t-=(t/f)*f)
                r+=((t*=2)<f?" ":"A")+"A \n/ /\n";
        C.Write(r+(t<f?"":"AAA\n"));
    }
}

Тестовий пробіг (знову ж таки, з відсутністю пробілів, які я обіцяю, є):

32 17
 f
AA
/ /
 A
/ /
 A
/ /
 A
/ /
AA
/ /

3

Перш за все, у мене питання щодо виклику. Оскільки у мене недостатньо репутації, щоб коментувати це питання, я пишу його тут:

  • Яка поведінка /A(тече вода на А), //(вода тече з правого боку) та варіації цього принципу? Чи стікає вода на перше «вільне місце» збоку чи тече «нижче» свого сусіда?

Просто спроба, це може бути спрощено waaaaay (що я зроблю пізніше, редагуючи цю публікацію).

Правка: Друга версія, трохи менша. Я пішов на інший підхід: замість того, щоб шукати кожну клітинку, щоб перевірити, що відбувається зверху і з боків, я починаю з кранів і "течу" вниз з рекурсією.

Javascript, 226 байт (виклик 1)

function f(c){function h(b,a,d,e){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"==e||"A"==e?g+=d:h(b,a+1,d,"\\"):"/"==c[b][a]?"\\"==e||"A"==e?g+=d:h(b,a-1,d,"/"):"A"==c[b][a]?"A"==e||"\\"==e||"/"==e?g+=d:(h(b,a-1,d/2,"A"),h(b,a+1,d/2,"A")):h(b+1,a,d,c[b][a]))}for(var g=0,m=0,k=0;k<c.length;k++)for(var l=0;l<c[k].length;l++)"f"==c[k][l]&&(h(k+1,l,1),m++);alert(g/m)};

Javascript, 204 байти (виклик 2)

function f(c){function e(b,a,d){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"!=d&&"A"!=d&&e(b,a+1,"\\"):"/"==c[b][a]?"\\"!=d&&"A"!=d&&e(b,a-1,"/"):"A"==c[b][a]?"A"!=d&&"\\"!=d&&"/"!=d&&(e(b,a-1,"A"),e(b,a+1,"A")):(" "==c[b][a]&&(c[b][a]="*"),e(b+1,a,c[b][a])))}for(var g=0;g<c.length;g++)for(var h=0;h<c[g].length;h++)"f"==c[g][h]&&e(g+1,h)};

Javascript, 238 байт (виклик 1 + 2)

function f(c){function h(b,a,d,e){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"==e||"A"==e?g+=d:h(b,a+1,d,"\\"):"/"==c[b][a]?"\\"==e||"A"==e?g+=d:h(b,a-1,d,"/"):"A"==c[b][a]?"A"==e||"\\"==e||"/"==e?g+=d:(h(b,a-1,d/2,"A"),h(b,a+1,d/2,"A")):(" "==c[b][a]&&(c[b][a]="*"),h(b+1,a,d,c[b][a])))}for(var g=0,m=0,k=0;k<c.length;k++)for(var l=0;l<c[k].length;l++)"f"==c[k][l]&&(h(k+1,l,1),m++);alert(g/m)};

Як користуватись

Надайте двовимірне подання карти. Ось приклад, наведений у запитанні:

var input = [["f"," "," ","f"," "," ","f"," "," "],[" "," "," "," "," "," ","A"," "," "],[" "," "," ","A"," ","/"," ","\\"," "],["\\"," ","/"," "," "," "," "," ","A"],[" "," "," "," ","A"," ","\\","/"," "],[" "," "," ","/"," "," "," "," "," "],[" ","\\","/"," "," "," "," "," "," "]];
f(input);

Вихідні дані

Завдання 1: Це просто створить діалогове вікно (попередження) з результатом (0,75 для прикладу вище).

Завдання 2: Це безпосередньо змінить карту. Чи варто її надрукувати? Якщо так, чи приймається console.log? як дійсний вихід?

Завдання 1 + 2: І те, і інше вище, очевидно, ...


Вода продовжує текти між персонажами так, ніби вона обіймає лінії Aабо косі риски. Я це уточнив у питанні.
Захоплення Кальвіна

У питанні зазначеноOutput must go to stdout.
user80551

Ви вказували як формат введення, що у вас є набір рядків з одним символом на рядок, але майте на увазі, що ви можете індексувати str[0]у рядки. Це був би масив рядків замість масиву масивів символів.
tomsmeding

1
user80551 Дякую, я не знаю, чому це вислизнуло з мене. Я оновлю свій код якомога швидше. @tomsmeding Так, це працює на мою відповідь на виклик 1. Але для виклику 2 я безпосередньо змінюю вхід, і ви не можете змінити символ у рядку за допомогою str [i], отже, і використання масиву масивів.
refreshfr

2

Пітон 3, 186 байт (виклик 3)

Я взяв ідею для сітки з відповіді VisualMelon . Функція повинна надрукувати дійсну сітку для stdout для довільно великих T і K, якщо це можливо (сітка з кінцевим розміром).

from fractions import*
def c(T,K):
 p=print;g=gcd(T,K);K//=g;T//=g
 if T&(T-1):p('Impossible')
 else:
  p(' f ')
  while T-1:
   T//=2;p('A/'[K<T]+'A \n///')
   if K>=T:K-=T
  p('AAA'*K)

Як користуватись

Викличте cфункцію із загальною сумою та сумою, яку слід зберегти як аргументи.

>>> c(24, 9)
 f 
/A 
///
AA 
///
AA 
///

>>> c(6, 2)
Impossible
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.