C #, 660 байт
using System.Linq;using System;class P{int p=1,x,y,r;P l;static void Main(){var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V";var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();int i=0,t,s=7,u,v,w,p=I[3]*I[2];for(var D=new[]{new P{r=Math.Abs(I[3]),l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3}}}.ToList();i>=0;){P c=D[i++],l=c.l;for(;(l=l?.l)!=null&&(s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;);if(s==0&&l.p>2&p*c.p<0)for(i=-1;c.l.p<3;c=c.l)Console.WriteLine(c.x+","+c.y+","+c.r);for(t=0;s>0&t<66;t++)for(u=Q[t++]-36,v=Q[t++]-36,s=1;s++<5&Q[t]%9==c.r;w=u,u=v,v=-w,D.Add(new P{l=c,r=Q[t]/9-4,x=c.x+u,y=c.y+v,p=-c.p}));}}}
Спробуйте це в Інтернеті
Це було дуже весело !! Повна програма, приймає вхід від STDIN, вихід на STDOUT. Вихід - це передачі в порядку від кінця до початку. Використання:
Здійснює простий пошук першої ширини, який вирішує проблему з 4 передачами менше ніж за секунду. Коефіцієнт розгалуження насправді не настільки великий, тому він повинен бути хорошим для значно більше (не дуже перевіреного). На жаль, він використовує Linq.
QРядок являє собою таблицю всіх дозволених з'єднань передач (тобто r=3і підключення до r=1якщо dx=4і dy=0) в одному квадраті, який потім повертається , щоб знайти інші. Кожен набір з 3 -х байт є dx, dyі інформація радіус правового зв'язку. Вибір (як зміщення був дуже обдуманим: колись було весело обирати символ ASCII для приємних властивостей, а не відчайдушно намагатися знайти приємні властивості для нав'язаних символів ASCII.
Я, напевно, можу зробити кращу роботу з читанням матеріалів, але мені ще не пощастило, в останню чергу тому, що Linq оплачується потребою у списку. Я також дуже розчарований кодом обертання, я відчуваю, що це можна зробити в значно меншій кількості байтів.
Форматований та коментований код з Qгенератором:
using System.Linq; // seems to pay today
using System;
class P
{
static void GenQ()
{
int t, k = 0, m = 0;
Func<P, P, int> C = (P c, P l) => (t = c.x - l.x) * t + (t = c.y - l.y) * t - (t = c.r + l.r) * t; // ==0 -> touching, <0 -> not touching, >0 -> overlap
string str = "";
string T(int i) => "" + (char)('$' + i); // $ is zero, '$' == 36, so we can mod and div by 9, and greater than " so we don't have to escape it
foreach (int r in new[] { 1, 2, 3, 5 }) // at 0,0 (current gear)
foreach (int s in new[] { 1, 2, 3, 5 }) // gear to place
for (int i = 0; i <= r + s; i++) // x
for (int j = 1; j <= r + s; j++, m++) // y
if (C(new P { r = r }, new P { r = s, x = i, y = j }) == 0) //
{
str += T(i) + T(j) + T(r + s * 9);
k++;
}
System.Console.WriteLine("K : " + k);
System.Console.WriteLine("M : " + m);
System.Console.WriteLine(str);
System.Console.ReadKey(true);
return;
}
int p=1, // parity
x, // x
y, // y
r; // radias (TODO: store radias^2 ?)
P l; // previous in search list
static void Main()
{
//GenQ();
// '$' == 36 (4*9)
// 3char blocks: x,y,r+9*s
var Q="$&.$'7$(@$*R$'/$(8$)A'(A('A$+S$(0$)9'(9('9$*B$,T$*2$+;$,D$.V*,V,*V"; // quarter table
// primative read ints
var I=Console.ReadLine().Split(',').Select(int.Parse).ToList();
int i=0, // position in Due
t, // check differential cache, position in Q
s=7, // check cache, rotation counter (>0)
u, // rotation x
v, // rotation y
w, // rotation x cache
p=I[3]*I[2]; // parity (>0 -> same, even ; <0 -> different, odd)
// due (not point using a queue, the search space grows exponentially)
for(var D=new[]{
new P{r=Math.Abs(I[3]), // start (p==1)
l=new P{r=Math.Abs(I[2]),x=I[0],y=I[1],p=3} // terminal (detect with p==3)
}}.ToList();
i>=0;) // infinite number of configurations, no bounds, i is escape term
{
P c=D[i++], // current
l=c.l; // check, initially the one before the previous (we know we are touching last already)
// 'checks' c against l
//Func<int>C=()=>(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t; // ==0 -> touching, >0 -> not touching, <0 -> overlap
// check we arn't touching any before us (last thing we check is terminal)
for(;(l=l?.l)!=null&& // for each before us (skipping the first one)
(s=(t=c.x-l.x)*t+(t=c.y-l.y)*t-(t=c.r+l.r)*t)>0;); // check c against l and cache in s, ==0 -> touching, >0 -> not touching, <0 -> overlap
if(s==0&& // touching last checked?
l.p>2& // stopped on terminal?
p*c.p<0) // correct parity? -> win
for(i=-1; // escape
c.l.p<3;c=c.l) // for each that wasn't the first
Console.WriteLine(c.x+","+c.y+","+c.r);
// enumerate possible additions, and queue them in due
for(t=0;
s>0& // not touching or overlapping anything (including terminal)
t<66;t++) // 66 = Q.Length
for(
u=Q[t++]-36, // '$'
v=Q[t++]-36,
s=1;s++<5& // rotate 4 times
Q[t]%9==c.r; // our raidus matches
w=u, // chache y value
u=v, // rotate
v=-w,
D.Add(new P // add
{
l=c,
r=Q[t]/9-4, // radius
x=c.x+u,
y=c.y+v,
p=-c.p // flip parity
}));
}
}
}