เดินของราชินีข้ามเกลียว


13

ในอาณาจักรที่ห่างไกลผู้เป็นราชินีแห่งหมากรุกใช้เวลาเดินข้ามเส้นทางวนทุกวันตั้งแต่ 1 ถึงnไม่สนใจที่จะตามเกลียวตัวเอง แต่เพียงแค่เคลื่อนไหวราชินีตามที่เธอต้องการบนกระดานหมากรุก ราชินีเป็นที่รักของอาสาสมัครของเธอและพวกเขาจดบันทึกทุก ๆ ตารางที่เธอไปเยี่ยมบนเส้นทางของเธอ เมื่อราชินีสามารถเริ่มเดินบนจัตุรัสใดก็ได้และจบลงที่จัตุรัสใด ๆ การเดินของราชินีที่สั้นที่สุดที่เธอสามารถทำได้คืออะไร?

ความท้าทาย

กำหนดเกลียวจำนวนเต็มบนกริดสี่เหลี่ยมให้เขียนฟังก์ชันที่ส่งคืนหนึ่งในเส้นทางที่สั้นที่สุด (นับจากจำนวนเซลล์ที่เดินทาง) ระหว่างสองตัวเลขบนกริดเกลียวนี้โดยใช้การเคลื่อนที่ของราชินีหมากรุก

ยกตัวอย่างเช่นจาก16การ25:

25 10 11 12 13
24  9  2  3 14
23  8  1  4 15
22  7  6  5 16
21 20 19 18 17

บางเส้นทางที่เป็นไปได้รวมและ16, 4, 2, 10, 2516, 5, 1, 9, 25

กฎระเบียบ

  • อินพุตจะเป็นจำนวนเต็มบวกสองค่าใด ๆ
  • ผลลัพธ์จะเป็นเส้นทางของจำนวนเต็ม (รวมทั้งจุดปลายทั้งสอง) ข้ามเกลียวโดยใช้การเคลื่อนที่แบบมุมฉากและแนวทแยง
  • ความยาวของเส้นทางถูกนับโดยจำนวนเซลล์ที่เดินทาง
  • คำตอบของคุณอาจเป็นโปรแกรมหรือฟังก์ชั่น
  • นี่คือรหัสกอล์ฟดังนั้นจำนวนไบต์ที่น้อยที่สุดจะเป็นผู้ชนะ

เช่นเคยหากปัญหายังไม่ชัดเจนโปรดแจ้งให้เราทราบ ขอให้โชคดีและการเล่นกอล์ฟที่ดี!

กรณีทดสอบ

>>> queen_spiral(4, 5)
4, 5
>>> queen_spiral(13, 20)
13, 3, 1, 7, 20
>>> queen_spiral(14, 14)
14
>>> queen_spiral(10, 3)
10, 11, 3
>>> queen_spiral(16, 25)
16, 4, 2, 10, 25
>>> queen_spiral(80, 1)
80, 48, 24, 8, 1

ที่เกี่ยวข้อง
Leun Nun

5
คุณอาจต้องการที่จะพูดถึงว่าคุณกำลังมองหาเส้นทางที่สั้นที่สุดจากจำนวนของเซลล์เดินทาง (เมื่อเทียบกับระยะ Euclidian พูด)
Martin Ender

1
สิ่งนี้จะไม่สมเหตุสมผลหรือไม่ในฐานะ "การเดินของกษัตริย์"?
Jo King

1
@ โจกิ้งอาตอนนี้ที่คุณพูดถึงมันควรจะเดินของกษัตริย์ อย่างไรก็ตามอาจมีความล่าช้าเล็กน้อยในการเปลี่ยนชื่อ
Sherlock9

คำตอบ:


5

APL (Dyalog Unicode) , 59 57 ไบต์SBCS

{v⍳+\v[⍺],↓⍉↑(|⍴¨×)⊃⍵⍺-.⊃⊂v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵}

ลองออนไลน์!

-2 ไบต์ต้องขอบคุณ @ngn

ฟังก์ชั่นไม่ระบุชื่อที่ยอมรับสองปลายทางเป็นอาร์กิวเมนต์ซ้ายและขวา

Ungolfed & มันทำงานอย่างไร

ย้ายราชินีทแยงมุมแรกดังนั้นมันเพียงพอที่จะ max(start,end)pre-คำนวณพิกัดของแต่ละหมายเลขขึ้นไป

อัลกอริทึมการสร้างพิกัดนั้นได้รับแรงบันดาลใจมาจากคำตอบหลายข้อในการท้าทายที่เกี่ยวข้องแต่แตกต่างจากคำตอบที่มีอยู่เล็กน้อย:

  • รับขอบเขตที่จำเป็นจาก 10
  • สร้างช่วง 1-based r=1 2 3 4 5 6 7 8 9 10
  • ใช้เพดานครึ่งหนึ่งของแต่ละหมายเลข n=1 1 2 2 3 3 4 4 5 5
  • ซ้ำรายการของแต่ละโดยrn1 2 3 3 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 9 10 10 10 10 10
  • ใช้ผลรวมสะสมของหน่วยจินตภาพโดยมีจุดเริ่มต้นเป็น 0 (ส่วนนี้เป็นเรื่องปกติของโซลูชัน Python ที่หลากหลายเพื่อความท้าทายที่เชื่อมโยง)

จากนั้นเมื่อเวกเตอร์ของพิกัดvพร้อมเราสามารถแปลงระหว่างดัชนีเกลียวและพิกัดการใช้v[i]และv⍳coord(การหาดัชนีแรกของcoordในv)

 Define a function; ⍺=start, ⍵=end
f←{
   Construct a vector of spiral coordinates v
  v9 11∘○¨+\0,0j1*{⍵/⍨⌈⍵÷2}⍳⍺⌈⍵
                             ⍺⌈⍵   max of start, end
                                  range of 1 to that number
                   {⍵/⍨⌈⍵÷2}   for each number n of above, copy itself ceil(n/2) times
               0j1*   raise imaginary unit to the power of above
           +\0,       prepend 0 and cumulative sum
                      (gives vector of coordinates as complex numbers)
    9 11∘○¨   convert each complex number into (real, imag) pair
  v          assign it to v

   Extract start and end coordinates
  a w←(⍺⊃v)(⍵⊃v)

   Compute the path the Queen will take
  v⍳+\(a),↓⍉↑(|⍴¨×)w-a
                    w-a   coordinate difference (end-start)
              (|⍴¨×)      generate abs(x) copies of signum(x) for both x- and y-coords
                          e.g. 4 -> (1 1 1 1), ¯3 -> 1 ¯1 ¯1)
           ↓⍉↑   promote to matrix (with 0 padding), transpose and split again
                 (gives list of steps the Queen will take)
    +\(a),      prepend the starting point and cumulative sum
                 (gives the path as coordinates)
  v   index into the spiral vector (gives the spiral numbers at those coordinates)
}

(⍵⊃v)-⍺⊃v->⊃⍵⍺-.⊃⊂
ngn

(⍺⌷v)->v[⍺]
ngn

3

Mathematica 615 530 ไบต์

สิ่งนี้จะสร้างตารางตัวเลขแปลงเป็นกราฟแล้วหาเส้นทางที่สั้นที่สุดระหว่างตัวเลขสองตัวที่เป็นอินพุต


UnGolfed

numberSpiralจาก Mathworld นายกรัฐมนตรีเกลียว มันสร้างเกลียว n โดย n Ulam (โดยไม่เน้นเฉพาะช่วงเวลา)

findPathแปลงตารางตัวเลขเป็นกราฟ ขอบเป็นการเลื่อนราชินีที่ถูกต้องบนกริดหมายเลข


numberSpiral[n_Integer?OddQ]:= 
  Module[{a,i=(n+1)/2,j=(n+1)/2,cnt=1,dir=0,len,parity,vec={{1,0},{0,-1},{-1,0},{0,1}}},a=Table[j+n(i-1),{i,n},{j,n}];Do[Do[Do[a[[j,i]]=cnt++;{i,j}+=vec[[dir+1]],{k,len}];dir=Mod[dir+1,4],{parity,0,1}],{len,n-1}];a];  

findPath[v1_, v2_] := 
  Module[{f, z, k},
    (*f  creates edges between each number and its neighboring squares *)
    f[sp_,n_]:=n<->#&/@(sp[[Sequence@@#]]&/@(Position[sp,n][[1]]/.{r_,c_}:>Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1}, {r+1,c-1}},{x_,y_}/; 0<x<k&&0<y<k]));k=If[EvenQ[
     z=\[LeftCeiling]Sqrt[Sort[{v1, v2}][[-1]]]\[RightCeiling]],z+1,z];
    FindShortestPath[Graph[Sort/@Flatten[f[ns=numberSpiral[k],#]&/@Range[k^2]] //Union],v1,v2]]

ตัวอย่าง

findPath[4,5]
findPath[13,22]
findPath[16,25]
numberSpiral[5]//Grid

{4,5}

{13,3,1,7,22}

{16,4,1,9,25}

ตะแกรง


เส้นทางที่สั้นที่สุดจาก 80 ถึง 1 ประกอบด้วย 5 ไม่ใช่ 6 จุดยอด

findPath[80,1]
numberSpiral[9]//Grid

{80, 48, 24, 8, 1}

แปดสิบเอ็ดตาราง


แข็งแรงเล่นกอล์ฟ

u=Module;
w@n_:=u[{a,i=(n+1)/2,j=(n+1)/2,c=1,d=0,l,p,v={{1,0},{0,-1},{-1,0},{0,1}}},
a=Table[j+n(i-1),{i,n},{j,n}];
Do[Do[Do[a[[j,i]]=c++;{i,j}+=v[[d+1]],{k,l}];d=Mod[d+1,4],{p,0,1}],{l,n-1}];a];
h[v1_,v2_]:=u[{f,z},
s_~f~n_:=n<->#&/@(s[[Sequence@@#]]&/@(Position[s,n][[1]]/.{r_,c_}:> 
Cases[{{r-1,c},{r+1,c},{r,c-1},{r,c+1},{r-1,c-1},{r-1,c+1},{r+1,c+1},{r+1,c-1}},{x_,y_}/;0<x<k&&0<y<k]));
k=If[EvenQ[z=\[LeftCeiling]Sqrt[Sort[{v1,v2}][[-1]]]\[RightCeiling]],z+1,z];
FindShortestPath[g=Graph[Sort/@Flatten[f[ns=w@k,#]&/@Union@Range[k^2]]],v1,v2]]

2

สกาลา (830 ไบต์)

สร้างเกลียวในอาร์เรย์ 2D แบบสี่เหลี่ยมโดยใช้ฟังก์ชั่นแบบเรียกซ้ำสี่แบบ การค้นหาแบบเรียกซ้ำเพื่อสร้างรายการพา ธ

def P(s:Int,e:Int):List[Int]={
import scala.math._
type G=Array[Array[Int]]
type I=Int
type T=(I,I)
def S(z:I)={def U(g:G,x:I,y:I,c:I,r:I):Unit={for(i<-0 to r.min(y)){g(y-i)(x)=c+i}
if(r<=y)R(g,x,y-r,c+r,r)}
def R(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x+i)=c+i}
D(g,x+r,y,c+r,r+1)}
def D(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y+i)(x)=c+i}
L(g,x,y+r,c+r,r)}
def L(g:G,x:I,y:I,c:I,r:I)={for(i<-0 to r){g(y)(x-i)=c+i}
U(g,x-r,y,c+r,r+1)}
val g=Array.ofDim[I](z,z)
U(g,z/2,z/2,1,1)
g}
def C(n:I,g:G):T={var(x,y)=(0,0)
for(i<-g.indices){val j=g(i).indexOf(n)
if(j>=0){x=j
y=i}}
(x,y)}
def N(n:Int)=if(n==0)0 else if(n<0)-1 else 1
def Q(a:T,b:T):List[T]={val u=N(b._1-a._1)
val v=N(b._2-a._2)
if(u==0&&v==0)b::Nil else a::Q((a._1+u,a._2+v),b)}
val z=ceil(sqrt(max(s,e))).toInt|1
val p=S(z)
Q(C(s,p),C(e,p)).map{case(x,y)=>p(y)(x)}}

Ungolfed

  import scala.math._
  type Grid=Array[Array[Int]]
  def spiral(size: Int) = {
    def up(grid:Grid, x: Int, y: Int, c: Int, r: Int): Unit = {
      for (i <- 0 to r.min(y)) {
        grid(y-i)(x) = c + i
      }
      if (r <= y)
        right(grid,x,y-r,c+r,r)
    }
    def right(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x+i) = c + i
      }
      down(grid,x+r,y,c+r,r+1)
    }
    def down(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y+i)(x) = c + i
      }
      left(grid,x,y+r,c+r,r)
    }
    def left(grid:Grid, x: Int, y: Int, c: Int, r: Int) = {
      for (i <- 0 to r) {
        grid(y)(x-i) = c + i
      }
      up(grid,x-r,y,c+r,r+1)
    }
    val grid = Array.ofDim[Int](size,size)
    up(grid,size/2,size/2,1,1)
    grid
  }
  def findPath(start: Int, end: Int): List[Int] = {
    def findCoords(n: Int, grid: Grid): (Int, Int) = {
      var (x,y)=(0,0)
      for (i <- grid.indices) {
        val j = grid(i).indexOf(n)
        if (j >= 0) {
          x = j
          y = i
        }
      }
      (x,y)
    }
    def sign(n: Int) = if (n == 0) 0 else if (n < 0) -1 else 1
    def path(stc: (Int, Int), enc: (Int, Int)) : List[(Int, Int)] = {
      val dx = sign(enc._1 - stc._1)
      val dy = sign(enc._2 - stc._2)
      if (dx == 0 && dy == 0) {
        enc :: Nil
      } else {
        stc :: path((stc._1 + dx, stc._2 + dy), enc)
      }
    }
    val size = ceil(sqrt(max(start, end))).toInt | 1
    val spir = spiral(size)
    path(findCoords(start, spir),findCoords(end, spir)).
      map { case (x, y) => spir(y)(x) }
  }

2

Ruby, 262 218 216 ไบต์

นี่คือพอร์ตของคำตอบหลามของฉัน ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ

แก้ไข: 45 ไบต์ขอบคุณไปจอร์แดนและข้อเสนอแนะของพวกเขาd=[0]*n=m*m;*e=c=0;*t=a, .rect, และ0<=>x x,y=(e[a]-g=e[b]).rect; t<<d[(g.real+x)*m+g.imag+y]ไบต์จากที่อื่นไป(x+y*1i)(x+y.i)

->a,b{m=([a,b].max**0.5).to_i+1;d=[0]*n=m*m;*e=c=0;*t=a
n.times{|k|d[c.real*m+c.imag]=k+1;e<<c;c+=1i**((4*k+1)**0.5-1).to_i}
x,y=(e[a]-g=e[b]).rect
(x+=0<=>x;y+=0<=>y;t<<d[(g.real+x)*m+g.imag+y])while(x+y.i).abs>0
t}

Ungolfed:

def q(a,b)
  m = ([a,b].max**0.5).to_i+1
  n = m*m
  d = [0]*n
  c = 0
  *e = c   # same as e=[0]
  *t = a   # same as t=[a]

  (1..n).each do |k|
    d[c.real * m + c.imag] = k+1
    e << c
    c += 1i**((4*k+1)**0.5-1).to_i
  end

  x, y = (e[a] - g=e[b]).rect

  while (x+y.i).abs > 0 do
    if x<0
      x += 1
    elsif x>0
      x += -1
    end

    if y<0
      y += 1
    elsif y>0
      y -= 1
    end

    t << d[(g.real+x)*m+g.imag+y]
  end

  return t
end

คุณควรลบq=คำตอบของคุณออกเนื่องจากคุณไม่นับจำนวนไบต์ สามารถลงไปc=0;e=[c];t=[a] *e=c=0;*t=aคุณสามารถแทนที่z=e[a]-e[b];x,y=z.real,z.imagด้วยx,y=(e[a]-e[b]).rectและx+=x<0?1:x>0?-1:0ด้วยx+=0<=>x(เหมือนกันสำหรับy) ฉันคิดว่ามันลดเหลือ 229 ไบต์
จอร์แดน

หากคุณเปลี่ยนเป็นอาเรย์แบบ 1 มิติคุณสามารถบันทึกได้อีก 6 ไบต์ แทนที่การเริ่มต้นของการdมีd=[0]*m*mแล้วแทนที่d[c.real][c.imag]ด้วยd[c.real*m+c.imag]และมีd[e[b].real+x][e[b].imag+y] d[(e[b].real+x)*m+e[b].imag+y]
จอร์แดน

การปรับปรุง 2 ไบต์ในความคิดเห็นก่อนหน้าของฉัน: t<<d[(e[b].real+x)*m+e[b].imag+y]สามารถย่อให้เล็กลงu,v=e[b].rect;t<<d[(u+x)*m+v+y]ได้
จอร์แดน

ไบต์ที่สองมากขึ้นโดยการเปลี่ยนd=[0]*m*mไปd=[0]*n=m*mและจะ(m*m).times n.times
จอร์แดน

คุณสามารถบันทึกสองไบต์เพิ่มเติมได้โดยเปลี่ยนx,y=(e[a]-e[b]).rectเป็นx,y=(e[a]-g=e[b]).rectลบu,v=e[b].rectและเปลี่ยนt<<d[(u+x)*m+v+y]เป็นt<<d[(g.real+x)*g.imag+v+y](โดยทั่วไปจะเป็นการแสดงความคิดเห็นที่สองเป็นครั้งสุดท้ายของฉัน)
จอร์แดน

1

Python 3, 316 ไบต์

คำตอบนี้ดูที่พิกัดของaและbบนเกลียว (โดยใช้ตัวเลขที่ซับซ้อน) และเพิ่มการเคลื่อนไหวในแนวทแยงก่อนจากนั้นการเคลื่อนที่แบบมุมฉาก

def q(a,b):
 m=int(max(a,b)**.5)+1;d=[];c=0;e=[c];t=[a]
 for i in range(m):d+=[[0]*m]
 for k in range(m*m):d[int(c.real)][int(c.imag)]=k+1;e+=[c];c+=1j**int((4*k+1)**.5-1)
 z=e[a]-e[b];x,y=int(z.real),int(z.imag)
 while abs(x+y*1j):x+=(x<0)^-(x>0);y+=(y<0)^-(y>0);t+=[d[int(e[b].real)+x][int(e[b].imag)+y]]
 return t

Ungolfed:

def queen_spiral(a,b):
    square_size = int(max(a,b)**.5)+1
    complex_to_spiral = []
    complex = 0
    spiral_to_complex = [c] # add 0 first, so that it's 1-indexed later
    result = [a]

    for i in range(square_size):
        complex_to_spiral.append([0]*square_size) # the rows of the spiral

    for k in range(square_size**2):
        row = int(complex.real)
        column = int(complex.imag)
        complex_to_spiral[row][column] = k+1 # 1-indexing

        spiral_to_complex.append(complex)

        quarter_turns = int((4*k+1)**.5-1)
        complex += 1j**quarter_turns

    z = spiral_to_complex[a] - spiral_to_complex[b]
    v = spiral_to_complex[b]
    x, y = int(z.real), int(z.imag)
    r, s = int(v.real), int(v.imag)

    while abs(x+y*1j):
        if x < 0:
            x += 1
        elif x > 0:
            x += -1
        # else x == 0, do nothing
        if y < 0:
            y += 1
        elif y > 0:
            y += -1

        vertex = complex_to_spiral[r+x][s+y]
        result.append(vertex)
    return result
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.