Ваш автомобіль повертає лише праворуч!


49

Вступ

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

Механіка

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

  1. Просуньте один квадрат вперед, або
  2. Поверніть на 90 градусів за годинниковою стрілкою, а потім рухайтеся на один квадрат вперед

Зауважте, що автомобіль не в змозі повернути досить різко, щоб здійснити 180-градусний поворот на одному квадраті.

Деякі квадрати - це перешкоди. Якщо автомобіль потрапить у квадрат перешкод, він врізається. Все поза межами курсу 8х8 вважається перешкодами, тому від'їзд з курсу рівносильний краху.

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

Завдання

Ви повинні написати програму або функцію, яка приймає за свій вхід масив 8x8 (матриця, список списків тощо), що представляє курс перешкод. Програма повертає або друкує булеве або щось подібне до цього. Якщо автомобіль може доїхати до безпечної площі без збоїв (тобто, якщо карта вирішальна), вихід True, інакше, є False.

Оцінка балів

Стандартні правила гольф-коду - переможець - код з найменшою кількістю байтів.

Бонуси:

  • Якщо для вирішуваної карти ваш код видає дійсну серію вводів для водіїв, які спрямовують автомобіль до безпечної площі, відрахуйте 10 відсоткових балів від вашої оцінки. Приклад виведення формату може бути SRSSR(із зазначенням Прямий, Правий, Прямий, Прямий, Правий). Цей вихід замінить стандартний Trueвихід.

  • Якщо для нерозв'язної карти вихідний код розрізняє ситуації, коли аварія неминуча, і ситуації, коли можна проїхати смугу перешкод назавжди, відрахуйте 10 відсоткових балів від вашого результату. Прикладом виходу може бути, Crashякщо аварія неминуча або Stuckякщо машина назавжди застрягла в перешкоді. Ці виходи замінять стандартний Falseвихід для нерозв'язної карти.

Приклад

Якщо програмі надано масив 8x8, такий як цей:

[[0, 0, 0, 0, 0, 1, 0, 0],
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [1, 1, 0, 0, 0, 0, 0, 0], 
 [0, 1, 0, 1, 0, 0, 0, 0], 
 [0, 0, 1, 1, 0, 0, 0, 0], 
 [0, 0, 0, 0, 1, 0, 1, 0], 
 [0, 0, 0, 0, 0, 0, 1, 0], 
 [0, 1, 1, 0, 0, 0, 1, 0]]

Це трактуватиметься як така карта, на якій чорні квадрати вказують на перешкоди:

введіть тут опис зображення

І можливим рішенням може бути:

введіть тут опис зображення

Оскільки рішення існує, програма повинна повернути / роздрукувати Trueдля цієї карти. Послідовність наведених тут рухів така SSSSRSRRRSRSSRRRSSRSSS.


2
Я написав кілька неймовірно простих тестових випадків для Crashта Stuck. Вони тут через те, як довго вони стоять. Рядок 2 заповнений, все інше порожнє -> Crash. Ряд 7 заповнений, все інше порожнє ->Stuck
підземний

3
Мене плутають відсоткові пункти (на відміну від відсотків). Отримавши або бонус, множимо рахунок на 0,9. Чи отримує обидва, помноживши його на 0,8 або 0,9 ^ 2?
підземниймонорельс

3
Звичайно, S і C - це добре. Мої результати були лише пропозиціями.
фосген

13
"Дві кривди не мають права, але три ліви". - Тато.
hoosierEE

2
"Ваш автомобіль може зробити лише нуль або три ліва!"
feersum

Відповіді:


17

JavaScript (ES6) - 122 124 148 162 172 178 187 190 193 208 байт

Дякую Оптимізатору та DocMax за корисні пропозиції щодо вдосконалення цього коду:

F=a=>(D=(x,y,d)=>!D[i=[x,y,d]]&&(D[i]=1,x-=~d%2,y-=~-~d%2,x*y==49||!((x|y)&8||a[y][x])&&(D(x,y,d)||D(x,y,~-d%4))),D(-1,0))

Повертається true(truthy) для вирішуваного та false(falesy) для нерозв’язного.

На сьогоднішній день працює лише у Firefox завдяки функціям JavaScript 1.7.

Тестова дошка


1
Це становить 193 байт: D=(x,y,d,t,a)=>!t[i=x+y*8+d*64]&&(t[i]=1,x+=d==0?1:d==2?-1:0,y+=d==1?1:d==3?-1:0,x==7&&y==7||!((x|y)&~7||a[y][x])&&G(x,y,d,t,a));G=(x,y,d,t,a)=>D(x,y,d,t,a)||D(x,y,d+1&3,t,a);F=a=>G(0,0,0,[],a).
Оптимізатор

1
172: D=d=>!t[i=x+y*8+d/4]&&(t[i]=1,x+=d?d^2?0:-1:1,y+=d^1?d^3?0:-1:1,x==7&&y==7||!((x|y)&~7||b[y][x])&&G(x,y,d));G=(X,Y,d)=>D(d,x=X,y=Y)||D(d+1&3,x=X,y=Y);F=a=>G(0,0,0,b=a,t={})- Випробувано.
Оптимізатор

1
@Optimizer Я все ще справджуся для другого тестового випадку [[0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]. Це повинно дати помилкове значення.
я та моя кішка

2
Це відбувається тому , що так xі yобидва Глобал, ви не можете запустити два testcases перед завантаженням сторінки ...
оптимізатор

1
Ви можете зберегти в цілому 9 більш заміною x+=d?d^2?0:-1:1з x+=d&1?0:1-dі y+=d^1?d^3?0:-1:1з y+=d&1&&2-d.
DocMax

10

Пітон 2 - 123 125 133 146 148 150 154 160

Trueна успіх, Falseна невдачу.

def f(h=1,v=0,b=0,x=0,y=0,c=[]):s=x,y,h,v;a=b,x+h,y+v,c+[s];return(s in c)==(x|y)&8==b[y][x]<(x&y>6or f(h,v,*a)|f(-v,h,*a))

Ви повинні надати вхід типу f(b=var_containing_board).

Версія лямбда - 154

Повертається 0(помилково) за невдачу, Trueза успіх.

F=lambda b,x=0,y=0,h=1,v=0,c=[]:0if[x,y,h,v]in c or x|y>7or x|y<0 or b[y][x]else x&y==7or F(b,x+h,y+v,h,v,c+[[x,y,h,v]])or F(b,x+h,y+v,-v,h,c+[[x,y,h,v]])

Завдяки Віллу та Брендону за те, що вони зробили функцію коротшою, ніж лямбда. Також для додавання більше горизонтальної прокрутки: D

Завдяки xnor за чудову біт-башінг та логіку!

Редагувати примітку: Я впевнено впевнений, що b[y][x]ніколи не буде виконаний, коли виходить за межі дальності. Оскільки ми знаходимось поза дошкою, перевірка історії s in cвідбудеться False. Тоді межа перевірки (x|y)&8буде 8. Тоді python навіть не перевірить останнє значення, ==оскільки перші два вже різні.


1
Функціональна версія може поєднувати два ifs, які обидва повертаються; як повернення в одиночку повертається Жоден, який є фальшивим, вам також не потрібно повертати 0.. Просто повертаючи послугу;)
Буде

Якщо ви перевернете чеки, ви можете також поєднати обидва ifs
буде

Чи можете ви поєднати обидва заяви повернення?
Брендон

1
@Буду спасибі, я знав, що є кращий спосіб зробити це: D Гм, я не зміг знайти жодних пробілів для видалення, які не викликають у мене синтаксичної помилки. Я насправді не розумію, чому x|y>7orпрацює, але x|y<0orне ...
FryAmTheEggman

1
Ви можете скласти восьмеричний буквальний початок з 0o.
feersum

9

C (GNU-C), 163 байт * 0,9 = 146,7

#C (GNU-C), 186 байт * 0,9 = 167,4

Моя нова версія використовує підписане, а не неподписане ціле число. Раніше я боявся підписаного правильного зсуву, але я зрозумів, оскільки біт знаку - це мета квадрата, неважливо, що буде після цього.

Функція приймає масив бітів (вони представляють блоковані квадрати) у вигляді 64-бітного цілого числа. Біти розташовуються якнайменше до найбільш значущих так само, як ви читали книгу. Він повертає -1 за аварію, 0 - назавжди за рухом, або 1 - для втечі до правого нижнього кута.

g(long long o) {
    typeof(o) a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;
    for( ;i--;d = D<<8&~o)
        a |= D = d|r,
        r = (r|u)*2&~M&~o,
        u = (u|l)>>8&~o,
        l = ((l|d)&~M)/2&~o;
    return a<0?:-!(d|r|u|l);
}

Тестова програма

f(long long o){typeof(o)a=0,i=255,r=1,u=0,l=0,d=0,M=~0LLU/i,D;for(;i--;d=D<<8&~o)a|=D=d|r,r=(r|u)*2&~M&~o,u=(u|l)>>8&~o,l=((l|d)&~M)/2&~o;return a<0?:-!(d|r|u|l);}
{
    char* s[] = {"Crash", "Stuck", "Escape"};
    #define P(x) puts(s[f(x)+1])
    L ex = 0x4640500C0A034020;
    P(ex);
    L blocked = 0x4040404040404040;
    P(blocked);

    L dead = 0x10002;
    P(dead);

    return 0;
}

Вихід

Escape
Stuck
Crash

Перетворювач масиву в шістнадцятковий Python:

a2b=lambda(A):"0x%X"%sum(A[i/8][i%8]<<i for i in range(64))

1
Замініть memset(&M,~1,8)(15 символів) на M=~(-1ULL/255)(14 символів).
Р ..

@R .. Гарний! -4 байти від цього.
feersum

2
Мені подобається формат введення - дуже круто!
фосген

Я отримую "крах" для P(0x00fefefefefefefe);= (Потрібно прямо постріляти вгорі праворуч, один поворот, прямо в кут. Те саме для P(0x00eeeeeeeeeeeeee);(тупик на 4-му стовпчику). Я не думаю, що вам потрібно призначити aспочатку.

@tolos Ви перемістили замовлення на рядок / стовпець. Щоб відкритий верхній рядок і правий стовпець мали бути відкритими 0x7f7f7f7f7f7f7f00. Також необхідно ініціалізувати, aоскільки пізніше він змінюється лише ORing додатковими бітами, тому я не можу дозволити собі встановити небажаний біт спочатку.
feersum

6

Пітон, 187 213

207 символів, 10% бонус за шлях друку

b=map(ord," "*9+" ".join("".join("o "[i]for i in j)for j in input())+" "*9)
def r(p,d,s):
 p+=(1,9,-1,-9)[d]
 if b[p]&1<<d:b[p]^=1<<d;return(s+"S")*(p==79)or r(p,d,s+"S")or r(p,(d+1)%4,s+"R")
print r(8,0,"")

На тестовому вході він знаходить дещо інший шлях: SSSSRSRSRRSSRSSRRSRSSRSSSSS

Загальний підхід полягає в тому, щоб спочатку перетворити вхід у пробіли та os. Пробіли мають шістнадцятковий розмір 20, тому всі чотири нижні біти не встановлені. oмає шістнадцятковий 6Fрозмір, тому всі чотири біти з низьким рівнем встановлені.

На oборту розміщена межа s, тому нам не потрібно турбуватися про погані показники.

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

Тоді ми робимо рекурсивний пошук безпечного шляху.


3
"Ваш автомобіль починається в лівому верхньому куті карти 8x8" - ви не можете встановити жорсткий код 9на місці w=len(b[0])+1тощо?
FryAmTheEggman

@FryAmTheEggman дякую, як я міг це не помітити? : D
Буде

Ви можете змінити свою потрійну заяву та замінити p==79на p-79. Я отримав синтаксичну помилку, роблячи це обома способами без пробілу перед else. Я думаю, що цей трюк працює лише з цим if.
FryAmTheEggman

@FryAmTheEggman Я думаю, тест на глибину повинен бути до рецидиву? Я натомість грав із множенням на булеве.
Буде

7
Я щойно знайшов дійсно акуратний трюк. Ви, мабуть, знаєте, що -~x==, x+1але обидва одинарні оператори мають вищий пріоритет, ніж множення, ділення та модуль! Так (d+1)%4могло бути -~d%4! Це також буде працювати з, x-1але просто використовувати ~-xзамість цього.
FryAmTheEggman

6

Javascript - 270 - 20% = 216 262 - 20% = 210 байт

Оскільки має бути принаймні одне рішення, яке отримує обидва бонуси (і не призводить до смішної глибини стека;) ...

Мінімізовано:

V=I=>{n=[N=[0,0,0]];v={};v[N]='';O='C';for(S='';n[0];){m=[];n.map(h=>{[x,y,d]=h;D=i=>[1,0,-1,0][d+i&3];p=v[h];for(j=2;j--;){O=v[c=[X=x+D(j),Y=y+D(3-3*j)),d+j&3]]?'K':O;J=X|Y;J<0||J>7||I[Y][X]||v[c]?O:(m.push(c),v[c]=p+'SR'[j])}S=(x&y)>6?p:S});n=m;}return S||O;};

Розширено:

V = I => {
    n = [N=[0,0,0]];
    v = {};
    v[N] = '';
    O = 'C';

    for( S = ''; n[0]; ) {
        m = [];
        n.map( h => {
            [x,y,d] = h;
            D = i => [1,0,-1,0][d+i&3];
            p = v[h];
            for( j = 2; j--; ) {
                O = v[c = [X = x+D(j),Y = y+D(3-3*j),d+j&3]] ? 'K' : O;
                J = X|Y;
                J<0 || J>7 || I[Y][X] || v[c] ? O : (
                    m.push( c ),
                    v[c] = p + 'SR'[j]
                );
            }

            S = (x&y) > 6 ? p : S;
        } );
        n = m;
    }
    return S || O;
};

vє хеш-таблицею з ключами, які є трійками стану, що (x,y,d)відповідають координаті (x, y) та напрямку введення d. Кожен ключ має пов’язане значення, яке є рядком S(прямий) та R(поворот праворуч), необхідний для досягнення стану, представленого ключем.

Код також підтримує стек з трійки (в змінній n), які ще не були оброблені. Стек спочатку містить лише трійку (0,0,0), що відповідає стану, коли автомобіль стикається праворуч у комірці (0,0). У зовнішньому циклі for( S = ... )рутина перевіряє, чи залишилися якісь необроблені трійки. Якщо так, то вона проходить кожен необроблена потрійний через внутрішню петлю, n.map( ....

Внутрішня петля робить п'ять речей:

  1. обчислює два можливі рухи (рух прямо, поворот праворуч) з поточного стану
  2. якщо будь-який з цих рухів призводить до стану, вже зареєстрованого в хештелі, він ігнорується для подальшої обробки. Ми позначаємо ЛЕГИЙ вихід як K(застряг), однак, оскільки ми знайшли принаймні одну петлю, де автомобіль може продовжувати кружляти назавжди без збоїв.
  3. якщо стан є законним і новим, він додається до хешбелу ( v) та до стеку необроблених трійки ( m) для наступного проходу зовнішньої петлі
  4. коли новий стан зареєстровано в v, його значення встановлюється на значення вихідного стану (послідовність рухів) плюс Rабо Sзасноване на поточному переміщенні
  5. якщо xі yє 7, значення початкового стану (послідовність кроків, здійснених для досягнення вихідного стану) копіюється в S, оскільки ця послідовність переміщення є рішенням проблеми

Після завершення внутрішнього циклу n(стек) замінюється на m(новий стек).

Після закінчення зовнішньої петлі (не було досягнуто нових станів) функція повертає свій вихід. Якщо клітина (7,7) була досягнута, Sбуде містити послідовність рухів, що ведуть до цієї комірки, і це буде виведено. Якщо клітинка не була досягнута, Sбуде порожній рядок, і звичайна програма потрапляє до виводу O, який буде містити K(застряг), якщо і лише якщо був знайдений цикл, або C(аварія), якщо машина неминуче вийде з ладу.


1
Отримавши підтвердження від ОП, ви можете перейменувати "Збій" та "Застряг" у "С" і "S".
FryAmTheEggman

Ага. Це трохи економить. Дякую. ;)
COTO

Чи можете ви пояснити, що робить ваш код? Я не можу робити ні голови, ні хвости.
фосген

@phosgene: Я включив детальне пояснення в рядку.
COTO

Це розумна процедура. Нічого не марно.
фосген

4

Python 339 - 10% = 305 байт

Я використовував рекурсивний пошук по глибині, який закінчується на початку успіху через exit. Також друк шлях на успіх у вигляді 00001010101010101010101110100111001000, 0по прямій, 1по праву. Відповідь буде довшою, ніж оптимальною, оскільки вона є першою глибиною. Я впевнений, що деякі оптимізації в алгоритмі можуть змусити кількість байтів зовсім небагато.

b=input()
D=[(-1,0),(0,-1),(1,0),(0,1)]
def a(l):
 x,y=0,0
 v=2
 for d in l:
  if d=='1':v=(v+1) % 4
  x+=D[v][0]
  y+=D[v][1]
  if x<0 or x>7 or y<0 or y>7:return 0,x,y
  if b[y][x]:return -1,x,y
 return 1,x,y
def c(l):
 if len(l) < 39:
  t,x,y=a(l)
  if t==1:
   if (x,y)==(7,7):
    print l;exit(0)
   c(l+"0")
   c(l+"1")
c("")
print 0

3
Оскільки це Python 2, ви можете змішувати вкладки та пробіли для відступів, як у циклі as for. Також вам не потрібні місця навколо операторів, наприклад (v+1) % 4-> (v+1)%4. Ви також можете приєднати декілька висловлювань до одного рядка, використовуючи, ;якщо у рядку немає ifабо forтощо, наприклад c(l+"0");c(l+"1"). Деякі інші гольфи: x,y,v=0,0,2, x|y>7 or x|y<0, x==y==7. Удачі :)
FryAmTheEggman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.