Робот находит котенка


52

Соревнование

Самый короткий код по количеству символов, чтобы помочь роботу найти котенка за наименьшее количество шагов.

Гольфисты, это время кризиса - Котенок пропал без вести, и работа Робота - найти его! Робот должен добраться до котенка по кратчайшему пути. Однако на пути Робота много препятствий, и ему нужно, чтобы вы запрограммировали решение для него.

Раньше у робота была программа, делающая это за него, но эта программа была потеряна, и у робота нет резервной копии :(.

Время выполнения робота не самое лучшее, и наименьшее количество символов, которое робот должен прочитать из исходного кода, меньше времени, которое он потратит на обработку, а это значит, что котенок будет найден быстрее!

Память робота содержит карту местоположения, в котором он находится в данный момент: верхняя часть представляет север, нижняя - юг, правая - восток, а левая - запад. Робот всегда находится в прямоугольной комнате неизвестного размера, окруженной стенами, представленной на #его радиолокационной карте. Области, в которые может ходить робот, представлены пространством .

Радар робота также сканирует множество препятствий в комнате и отмечает их различными буквами ASCII. Робот не может преодолеть эти препятствия. Радар пометит Киттена как специальный символ ASCII K, в то время как местоположение робота будет отмечено с помощью R.

Навигационная система робота работает следующим образом: он может понять пару направлений и количество единиц движения, к которым он должен идти - например, N 3означает «перейти на север 3 единицы движения». Карта радара робота сделана так, что единицей движения является один символ ASCII. Робот может двигаться только в 4 направлениях и не может двигаться по диагонали.

Ваша задача, храбрый котенок-спасатель, - прочитать радиолокационную карту робота один раз и вывести наименьшее количество направлений с наименьшим расстоянием перемещения юнита. Робот гарантированно имеет хотя бы один путь к котенку.

Чтобы робот не тратил время на выполнение работающей со сбоями программы, которая не поможет роботу найти котенка, я призываю вас, отважный хранитель котят, использовать этот вывод из прошлой программы робота, чтобы не тратить время на поиск котенка!

Контрольные примеры

Input:
    ######################
    #  d      3    Kj    #
    #                    #
    # R                  #
    #      q             #
    ######################
Output:
    E 13
    N 2

Input:
    ######################
    #  d  r   3    Kj    #
    #    p        p      #
    #         T        X #
    #      q   s   t     #
    #                    #
    #  R o    d     W    #
    #                    #
    #    g      t     U  #
    #                    #
    ######################
Output:
    N 1
    E 10
    N 4
    E 2

Input:
    ######################
    #  spdfmsdlwe9mw WEK3#
    #    we    hi        #
    #   rdf         fsszr#
    #     sdfg  gjkti    #
    #   fc  d g i        #
    #     dfg    sdd     #
    #    g        zfg    #
    #  df   df           #
    #             xcf   R#
    ######################
Output:
    N 1
    W 9
    N 5
    E 4
    N 1
    E 4
    N 1

Количество кодов включает в себя ввод / вывод (т.е. полную программу).


1
Возможно, вдохновлен этой игрой? kongregate.com/games/Hamumu/robot-wants-kitty
Набб


4
Цель не однозначна. msgstr "вывести наименьшее количество направлений с наименьшим расстоянием перемещения единицы движения." Может быть способ с n направлениями и m шагами, а другой может быть с менее чем n направлениями, но большим количеством шагов или большим количеством направлений и меньшим количеством шагов. Есть ли обменный курс?
пользователь неизвестен

2
Количество шагов лучше, чем количество направлений.
LiraNuna

1
Если идея состоит в наименьшем количестве шагов и разрыве связей по наименьшему количеству направлений, то второй пример имеет неправильное решение. Смотрите мой ответ для кратчайшего пути.
Даниэль С. Собрал

Ответы:


10

C ++ 1002 899 799 символов

Примечание требует использования C ++ 0x для устранения пробела между>> в шаблонах.

Он находит маршрут с минимальным количеством поворотов.

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<memory>
#define D make_pair
#define F first
#define S second
using namespace std;typedef pair<int,int>L;typedef vector<L>R;typedef multiset<pair<float,pair<L,R>>>B;vector<string> M;string l;int z,c,r=0;set<L> s;B b;L n;B::iterator f;R v;void A(int x,int y,int w){n=f->S.F;for(c=1;(z=M[n.S+=y][n.F+=x])==32||(z==75);++c)v.back()=D(w,c),b.insert(D(f->F+c+1./c,D(n,v)));}int main(){for(;getline(cin,l);++r){if((c=l.find(82))!=string::npos)b.insert(D(0,D(D(c,r),R())));M.push_back(l);}while(!b.empty()){f=b.begin();n=f->S.F;v=f->S.S;if(M[n.S][n.F]==75)break;if(s.find(n)==s.end()){s.insert(n);v.push_back(L());A(0,1,83);A(0,-1,78);A(1,0,69);A(-1,0,87);}b.erase(f);}for(c=v.size(),r=0;r<c;++r)n=v[r],printf("%c %d\n",n.F,n.S);}

Это Dijkstra's Algorithmдля решения проблемы кратчайшего пути.
Чтобы различать несколько маршрутов одинакового размера, длинная прямая линия имеет меньший вес, чем несколько коротких (это благоприятствует маршрутам с меньшим количеством поворотов).

Cost of a path:  Len + 1/Len

Looking at Test Case 1:
========================
Thus Path E13 + N2 has a cost of 
      13 + 1/13 + 2 + 1/2
An alternative path E9 + N2 + E4 has a cost of
      9 + 1/9 + 2 + 1/2 + 4 + 1/4

The difference is
      Straight Path:   1/13 <   Bendy Path: (1/9 + 1/4)

В более читаемой форме:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<memory>

using namespace std;
typedef pair<int,int>                   L;
typedef vector<L>                       R;
typedef multiset<pair<float,pair<L,R>>> B;
vector<string>                          M;

string      l;
int         z,c,r=0;
set<L>      s;
B           b;
L           n;
B::iterator f;
R           v;

void A(int x,int y,int w)
{
    n=f->second.first;
    for(c=1;(z=M[n.second+=y][n.first+=x])==32||(z==75);++c)
        v.back()=make_pair(w,c),
        b.insert(make_pair(f->first+c+1./c,make_pair(n,v)));
}

int main()
{
    for(;getline(cin,l);++r)
    {
        if((c=l.find(82))!=string::npos)
            b.insert(make_pair(0,make_pair(make_pair(c,r),R())));
        M.push_back(l);
    }

    while(!b.empty())
    {
        f=b.begin();
        n=f->second.first;
        v=f->second.second;

        if(M[n.second][n.first]==75)
            break;

        if(s.find(n)==s.end())
        {
            s.insert(n);
            v.push_back(L());
            A(0,1,83);
            A(0,-1,78);
            A(1,0,69);
            A(-1,0,87);
        }
        b.erase(f);
    }

    for(c=v.size(),r=0;r<c;++r)
        n=v[r],
        printf("%c %d\n",n.first,n.second);
}

9

Scala 2.8 (451 символов)

... но это не решает связи в пользу наименьшего количества направлений (хотя и находит наименьшее количество шагов).

val m=io.Source.stdin.getLines.map(_.toArray).toSeq
var l=m.indexWhere(_ contains'R')
var c=m(l)indexOf'R'
val q=collection.mutable.Queue(l->c->"")
def s{val((l,c),p)=q.dequeue
if("R "contains m(l)(c))for((i,j,k)<-Seq((-1,0,"N"),(0,1,"E"),(1,0,"S"),(0,-1,"W")))q.enqueue(((l+i,c+j),p+k))
m(l)(c)='X'}
def P(s:String){if(s.nonEmpty){val (h,t)=s.span(s.head==)
println(s.head+" "+h.size)
P(t)}}
def Q{s
val((l,c),p)=q.head
if (m(l)(c)=='K')P(p)else Q}
Q

Scala 2.8, 642 символа, правильно решает связи;

val m=io.Source.stdin.getLines.toSeq
var b=Map(0->0->0).withDefault(_=>Int.MaxValue)
var l=m.indexWhere(_ contains'R')
var c=m(l)indexOf'R'
val q=collection.mutable.PriorityQueue(l->c->List((' ',0)))(Ordering.by(t=>(-t._2.map(_._2).sum,-t._2.size)))
def s{val(p@(l,c),u@(h@(d,n))::t)=q.dequeue
if("R ".contains(m(l)(c))&&u.map(_._2).sum<=b(p)){b=b.updated(p,u.map(_._2).sum)
for((i,j,k)<-Seq((-1,0,'N'),(0,1,'E'),(1,0,'S'),(0,-1,'W'))){
val o=if(k==d)(d,n+1)::t else (k,1)::h::t
q.enqueue(((l+i,c+j),o))}}}
def P(l:List[(Char,Int)]){l.reverse.tail.foreach{t=>println(t._1+" "+t._2)}}
def Q{s;val((l,c),p)=q.head;if (m(l)(c)=='K')P(p)else Q}
Q

Он обнаружил более короткий путь для второго примера, чем тот, который приведен в задаче:

N 1
E 10
N 4
E 2

4

Python 2.6 (504 символа)

import sys,itertools
W,Q=len,list   
M=[]
B=[]
for l in sys.stdin.readlines():
    r=Q(l.strip())
    B.append([0]*W(r))
    M.append(r)
    if "R" in r:x,y=r.index("R"),W(B)-1
def S(B,M,x,y,P):
    c=M[y][x]
    b=B[y][x]
    if b and W(P)>b:return 0
    B[y][x]=W(P)
    if c=="K":return P  
    elif c=="R" and P:return 0
    if c in "R ":
        b=[]
        for q,w,s in((1,0,"E"),(-1,0,"W"),(0,-1,"N"),(0,1,"S")):
            r=S(B,M,x+q,y+w,P+s)
            if r and(W(r)<W(b)or not b):b=r
        if b:return b
    return 0
print "\n".join(k+str(W(Q(g)))for k,g in itertools.groupby(S(B,M,x,y,"")))

Это, кажется, не решает связи в пользу наименьших шагов.
Даниэль С. Собрал

4

Python 2.6 (535 символов)

exec 'eJzNlLFugzAQhneewhki2/KBworksVOkDu3QgVqVE2hBioFgCDhV371nJ1VbKR3SKYtl/jvs77MwtenafiBVqbs9WGcjLW05MB69tj05QEfqhpTNaMpeDyXDhsQORd3wLCK+YwT7u6PzFVK/Ep9Tsn6gmU50UTA2woHzc01KuqYZ20PPZSh85/iCO2etzBnTG8tcvlLxnovTPFVxzyGEC4lpiBay5xiuYMXBcRVtzxqTfP+IpqrelaRFsheoYJbBNvFj13asxd23gXHGmZU7bTaFDgiZH+MUYydtKBuZRuS0nvPmOt564Sl3CmlxcWAG6D3lXIkpeUMGB7nyfj82HW3FWvjTTVSYCXNJEUupEimannu+nl04WyM8XoB1F13E9S6Pt+ki0vDZXOdyd5su8X9cnm7DBa/tLGW4yh7yKCn1rIF+9vSTj/HiBeqCS1M3bMrnwOvbl5Ysi+eGLlkBhosjxl1fNwM5Ak7xH6CiT3SdT4U='.decode('base64').decode('zlib')

Распаковывает в строго неправильно обработанную A * реализацию. Читает stdin. Ищет решения с минимальным общим расстоянием. Разрывает связи, предпочитая минимальное количество направлений. Списки перемещаются в стандартный вывод. Находит котят.

Распаковано :

В некоторых местах источник был вручную защищен от гольфа, чтобы получить сжатое представление меньшего размера. Например, был развернут цикл for по направлениям компаса.

import heapq,sys 
a=set() 
for v,p in enumerate(sys.stdin): 
 for u,s in enumerate(p): 
  if s in' KR':a.add((u,v)) 
  if s=='K':(q,r)=(u,v) 
  if s=='R':y=(u,v) 
o=[((abs(y[0]-q)+abs(y[1]-r),(y[0]!=q)+(y[1]!=r)),(0,0),y)] 
c=set() 
w={} 
while o: 
 _,h,x=heapq.heappop(o) 
 c.add(x) 
 s=lambda(u,v):(u,v-1) 
 y=s(x) 
 m=1 
 while y in a-c: 
  w[y]=[(h,x,(m,'N'))]+w.get(y,[]) 
  heapq.heappush(o,((abs(y[0]-q)+abs(y[1]-r)+h[0]+m,(y[0]!=q)+(y[1]!=r)+h[1]+1),(h[0]+m,h[1]+1),y)) 
  m+=1 
  y=s(y) 
 s=lambda(u,v):(u,v+1) 
 y=s(x) 
 m=1 
 while y in a-c: 
  w[y]=[(h,x,(m,'S'))]+w.get(y,[]) 
  heapq.heappush(o,((abs(y[0]-q)+abs(y[1]-r)+h[0]+m,(y[0]!=q)+(y[1]!=r)+h[1]+1),(h[0]+m,h[1]+1),y)) 
  m+=1 
  y=s(y) 
 s=lambda(u,v):(u+1,v) 
 y=s(x) 
 m=1 
 while y in a-c: 
  w[y]=[(h,x,(m,'E'))]+w.get(y,[]) 
  heapq.heappush(o,((abs(y[0]-q)+abs(y[1]-r)+h[0]+m,(y[0]!=q)+(y[1]!=r)+h[1]+1),(h[0]+m,h[1]+1),y)) 
  m+=1 
  y=s(y) 
 s=lambda(u,v):(u-1,v) 
 y=s(x) 
 m=1 
 while y in a-c: 
  w[y]=[(h,x,(m,'W'))]+w.get(y,[]) 
  heapq.heappush(o,((abs(y[0]-q)+abs(y[1]-r)+h[0]+m,(y[0]!=q)+(y[1]!=r)+h[1]+1),(h[0]+m,h[1]+1),y)) 
  m+=1 
  y=s(y) 
 if x==(q,r): 
  z='' 
  while x in w: 
   _,x,(m,d)=min(w[x]) 
   z='%s %d\n'%(d,m)+z 
  print z, 
  o=[]

3

c ++ - 681 необходимый символ

#include <string>
#include <iostream>
#include <sstream>
using namespace std;
int d[]={-1,0,1,0},i,j,k,l,L=0,p=41,S;string I,m,D("ESWN");
int r(int o,int s){S=s;while((m[o]==32||m[o]==37)&&m[o+S]-35)
if(m[o+S]-p)S+=s;else return o+S;return 0;}
void w(int o){for(i=0;i<m.length();++i)for(j=0;j<4;++j)
if(k=r(o,d[j])){stringstream O;O<<D[j]<<" "<<int((k-o)/d[j])<<"\n"<<I;
I=O.str();if(p-41)--p,m[k]=37,w(k);cout<<I;exit(0);}}
int main(){while(getline(cin,I))m+=I,l=I.length();
d[1]-=d[3]=l;I="";for(i=0;i<m.length();++i)
switch(m[i]){case 82:case 75:m[i]/=2;case 32:break;default:m[i]=35;}
do{for(i=0;i<m.length();++i)if(r(i,-1)+r(i,-l)+r(i,1)+r(i,l))
{if(m[i]==37)w(i);m[i]=p+1;}}while(++p);}

Сначала он заменяет все препятствия на карте на #s (и изменяет значения Kи R, чтобы оставить запас в пространстве символов для очень длинных путей. Затем он набрасывает на карте. Итерационный процесс отмечает все последовательно доступные квадраты до тех пор, пока может добраться до котенка за один ход. После этого используется та же самая процедура проверки доступности, чтобы найти строку положений, которые приводят к началу в минимальных инструкциях. Эти инструкции загружаются в строку путем предварительного ожидания, так что они печатать в правильном порядке.

Я не собираюсь играть в гольф дальше, поскольку он не разрешает должным образом связи и не может быть легко адаптирован для этого.

Это терпит неудачу на

#####
#   #
# # #
#R#K#
#   #
#####

производства

 $ ./a.out < kitten_4.txt
N 2
E 2
S 2

Более или менее читаемая версия:

#include <string>
#include <iostream>
#include <sstream>
using namespace std;

int d[]={-1,0,1,0}
  , i, j, k
  , l      /* length of a line on input */
  , L=0    /* length of the whole map */
  , p=41   /* previous count  ( starts 'R'/2 ) */
  , S      /* step accumulator for step function */
  ; 
string I/*nput line, later the instructions*/
  , m/*ap*/
  , D("ESWN"); /* Reversed sence for back tracking the path */

int r/*eachable?*/(int o/*ffset*/, int s/*step*/){
//   cerr << "\tReachable?" 
//        << endl
//        << "\t\tOffset: " << o << " (" << o/5 << ", " << o%5 << ")" 
//        << "  [" << m[o] << "]" << endl
//        << "\t\tStep: " << s 
//        << endl
//        << "\t\tSeeking: " << "[" << char(p) << "]" 
//        << endl
//        << "\t\tWall:    " << "[" << char(35) << "]" 
//        << endl;
  S=s;
  while ( ( (m[o]==32)      /* Current character is a space */ 
        || (m[o]==37) ) /* Current character is a kitten */ 
      && (m[o+S]-35) /* Target character is not a wall */ 
      )
    {
//     cerr << "\t\tTry: " << o+S << "(" << (o+S)/5 << ", " << (o+S)%5 << ")" 
//   << "  [" << m[o+S] << "]" << endl;
    if (m[o+S]-p       /* Target character is not the previous count */ 
    ) {
//       cerr << "\t\twrong " << "  [" << m[o+S] << "] !!!" << endl;
      S+=s;
    }
    else  {             /* Target character *is* the previous count */
//       cerr << "\t\tFound " << "  [" << m[o+S] << "] !!!" << endl;
      return o+S;
    } 
  /* while ends */
      }
  return 0;
}

void w/*on*/(int o/*ffset*/){
//   cerr << "\tWON" << endl
//        << "\t\tOffset: " << o << "(" << o/5 << ", " << o%5 << ")" 
//        << "  [" << m[o] << "]" 
//        << endl
//        << "\t\tSeeking: " << "[" << char(p) << "]" 
//        << endl;
  for(i=0;i<m.length();++i) /* On all map squares */
    for(j=0;j<4;++j)
      if (k=r(o,d[j])) {
//  cerr << "found path segment..." 
//       << (k-o)/d[j] << " in the " << d[j] << " direction." << endl;
    stringstream O;
    O << D[j] 
      << " " 
      << int((k-o)/d[j]) 
      << "\n" 
      << I;
    I = O.str();
//  cerr << I << endl;
    /* test for final solution */
    if (p-41) 
      --p,m[k]=37, w(k); /* recur for further steps */
    cout << I;
    exit(0);
      }
    /* inner for ends */
  /* outer for ends */
}


int main(){
  while(getline(cin,I))
    m+=I,l=I.length();
//   cerr << "Read the map: '" << m << "'." << endl;
  d[1]-=d[3]=l;I="";
//   cerr << "Direction array:    " << D << endl;
//   cerr << "Displacement array: " << d[0] << d[1] << d[2] << d[3] << endl;
//   cerr << "Line length: " << l << endl;
  /* Rewrite the map so that all obstacles are '#' and the start and
     goal are '%' and ')' respectively. Now I can do pathfinding *on*
     the map. */
  for(i=0;i<m.length();++i)
    switch (m[i]) {
    case 82:         /* ASCII 82 == 'R' (41 == ')'  ) */
    case 75:m[i]/=2; /* ASCII 75 == 'K' (37 == '%' ) */
    case ' ':break;
    default: m[i]=35; /* ASCII 35 == '#' */ 
    };
//   cerr << "Re-wrote the map: '" << m << "'." << endl;
  do { /* For each needed count */
//     cerr << "Starting to mark up for step count " 
//   << p-41+1  << " '" << char(p) << "'" << endl;
    for(i=0;i<m.length();++i){ /* On all map squares */
//        cerr << "\tTrying position (" << i/l << ", " << i%l << ")" 
//      << "  [" << m[i] << "]"
//      << endl;
      if ( r(i, -1) /* west  */ +
       r(i, -l) /* north */ +
       r(i,  1) /* east  */ +
       r(i,  l) /* south */ 
       ) {
//    cerr << "Got a hit on : '" << m << "'." << endl;
//    cerr << "\twith '" << char(m[i]) <<" at position " << i << endl;
//    cerr << "target is " << char(37) << endl;
    if(m[i]==37)
      w(i); /* jump into the win routine which never returns */
    m[i]=p+1;
//  cerr << "Marked on map: '" << m << "'." << endl;
      }
    }
  } while(++p);
}

3

Рубин - 539 символов

Может быть сделано с большим количеством улучшений, но это работает для кратчайших шагов, а также указаний.

M=[*$<]
r=M.map{|q|q.index('R')||0}
k=M.map{|q|q.index('K')||0}
D=M.map{|q|q.split('').map{[99,[]]}} 
def c h 
h.map{|i|i.inject([[]]){|a,b|a.last[0]!=b ? a<<[b, 1]:a.last[1]+=1;a}}.sort_by{|a|a.length}[0]
end
def t x,y,s,i
z,w=D[x][y][0],D[x][y][1]
if [' ','R','K'].index(M[x][y, 1])&&(z>s||z==s&&c(w).length>=c([i]).length)
D[x][y]=[s,z==s ? w<<i:[i]]
s+=1
t x+1,y,s,i+['S']
t x-1,y,s,i+['N']
t x,y+1,s,i+['E']
t x,y-1,s,i+['W']
end
end
t r.index(r.max), r.max, 0, []
puts c(D[k.index(k.max)][k.max][1]).map{|a|a*''}

1

Рубин - 648 символов

Еще один, который не проходит проверку наименьшего числа направлений, так как я не могу придумать простой способ вставить его в A *.

m=$<.read.gsub /[^RK\n ]/,'#'
l=m.index($/)+1
s=m.index'R'
g=m.index'K'
h=->y{(g%l-y%l).abs+(g/l-y/l).abs}
n=->y{[y+1,y-1,y+l,y-l].reject{|i|m[i]=='#'}}
a=o=[s]
d=Array.new(m.length,9e9)
c,k,f=[],[],[]
d[s]=0
f[s]=h[s]
r=->y,u{u<<y;(y=k[y])?redo:u}
(x=o.min_by{|y|f[y]}
x==g ? (a=r[x,[]].reverse;break):0
o-=[x];c<<x
n[x].map{|y|c&[y]!=[]?0:(t=d[x]+1
o&[y]==[]?(o<<y;b=true):b=t<d[y]
b ? (k[y]=x;d[y]=t;f[y]=t+h[y]):0)})until o==[]
k=a.inject([[],nil]){|k,u|(c=k[1]) ? (k[0]<<(c==u-1?'E':c==u+1?'W':c==u+l ? 'N':'S')) : 0;[k[0],u]}[0].inject(["","",0]){|k,v|k[1]==v ? k[2]+=1 : (k[0]+=k[1]+" #{k[2]}\n";k[1]=v;k[2]=1);k}
puts k[0][3,9e9]+k[1]+" #{k[2]}\n"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.