在六角形网格上运动


15

给定一系列代表六边形网格上运动的字符的输入,输出“指针”的最终坐标。

我们的六边形将按以下方式编号(想象一个矩形网格,每个奇数编号的列都会稍微向下移动):

  _____         _____         _____         _____
 /     \       /     \       /     \       /     \
/ -3,-2 \_____/ -1,-2 \_____/  1,-2 \_____/  3,-2 \
\       /     \       /     \       /     \       /
 \_____/ -2,-1 \_____/  0,-1 \_____/  2,-1 \_____/
 /     \       /     \       /     \       /     \
/ -3,-1 \_____/ -1,-1 \_____/  1,-1 \_____/  3,-1 \
\       /     \       /     \       /     \       /
 \_____/ -2,0  \_____/  0,0  \_____/  2,0  \_____/
 /     \       /     \       /     \       /     \
/ -3,0  \_____/ -1,0  \_____/  1,0  \_____/  3,0  \
\       /     \       /     \       /     \       /
 \_____/ -2,1  \_____/  0,1  \_____/  2,1  \_____/
 /     \       /     \       /     \       /     \
/ -3,1  \_____/ -1,1  \_____/  1,1  \_____/  3,1  \
\       /     \       /     \       /     \       /
 \_____/       \_____/       \_____/       \_____/

指针从(0,0)开始。

您必须支持的说明如下:

  • q:向左移动
  • w: 提升
  • e:右移
  • a:向左下移动
  • s:下移
  • d:向右下移动
  • r:顺时针旋转网格
  • R:逆时针旋转网格

旋转命令在使指针保持相同坐标的同时旋转整个网格。(为什么qweasd?它们与QWERTY键盘上的指示很好地匹配。)

为了使这一过程可视化,假设指针从中间开始,这是移动命令的作用:

         _____
        /     \
  _____/   w   \_____
 /     \       /     \
/   q   \_____/   e   \
\       /     \       /
 \_____/       \_____/
 /     \       /     \
/   a   \_____/   d   \
\       /     \       /
 \_____/   s   \_____/
       \       /
        \_____/

在顺时针旋转(r)之后,命令将重新映射为(将其想象为旋转整个十六进制网格,但仍将“ w”保持向上等),这等效于以下内容:

         _____
        /     \
  _____/   e   \_____
 /     \       /     \
/   w   \_____/   d   \
\       /     \       /
 \_____/       \_____/
 /     \       /     \
/   q   \_____/   s   \
\       /     \       /
 \_____/   a   \_____/
       \       /
        \_____/

同样,R此后逆时针旋转()将使网格恢复正常,再次逆时针旋转将“重新映射” qwedsaaqweds

输入必须以单个字符串形式给出,输出可以是由任何非数字字符(例如1 23,4)连接的单个字符串或整数数组。

由于这是,因此以字节为单位的最短代码将获胜。

测试用例:

In                         Out
---------------------------------
edeqaaaswwdqqs             -2, 0
dddddddddd                 10, 5
wswseaeadqdq               0, 0
<empty string>             0, 0
esaaqrweesrqrq             -1, 0
wrwrwrwrw                  -1, 0
RRssrrrs                   -1, -1
aRRRRwddrqrrqqq            -1, -4
rrrrrrrrrrrrRRRRRRrrrrrrq  -1, -1
rrRrRrrRrrrrRRrRrRR        0, 0

Answers:


2

Pyth,81个字节

J_K1=Y"qwedsa"A,ZZFNz=kxYN ?<kZ=Y?<x\rNZ.>Y1.<Y1A,+G@[JZ1KZJ)k+H@[J_2JK2K)k;,G/H2

输出是代表坐标的整数列表。

我的解决方案实际上很无聊。它只是在一个数组(qwedsa)中查找输入的字符,然后访问两个表示各自坐标变化的数组。例如,如果输入为w,则得到1(因为它是数组中的第二个字符)。然后,我们添加A[1]x(其中A是用于改变所述阵列x中对于不同的输入),并B[1]y(其中,B是用于改变y)。rR通过只旋转所述实现qwedsa阵列。

我确信有人可以使用Pyth做得更好。我将继续尝试寻找答案!

您可以在这里尝试。


12

视网膜353 339 178 175 150 130 129 117字节

R
5$*r
T`aq\we\ds`so`r.+
)`r(.*)
$1
^
:
a
sq
e
wd
+`(.+)q
w$1
+`(.+)d
s$1
+`sw

(.*)(\1w?):
$0$2
+`sw|ws

w+
-$0
\w
1

输出为一元,以冒号分隔。这意味着您不会真正在输出中看到零(尽管冒号的存在会告诉您两个坐标中的哪一个为零,如果只有一个)。

在线尝试!

这真的很有趣,而且结果出奇的短。:)

说明

首先有一些背景。有几种坐标系统可以描述六边形网格。要求使用偏移坐标。从本质上讲,这类似于矩形网格坐标,只是一个轴稍微“摆动”。特别是,该问题要求链接页面上显示的“ odd-q”布局。使用此坐标系有点烦人,因为在移动过程中坐标的变化方式不仅取决于移动的方向,还取决于当前位置。

另一个坐标系使用轴向坐标。实质上,这是将六边形网格想象为通过一定体积的立方体的对角线切片,然后使用两个轴(例如x和z)在2D平面上找到位置。在十六进制网格上,这意味着两个轴形成60(或120)度的角度。由于每个方向都对应一个固定的“增量”矢量,因此该系统的直观性较差,但使用起来更容易。(有关如何到达此坐标系的更好说明,请查看链接以及该处的漂亮图表和动画。)

因此,我们将执行以下操作:我们计算轴向坐标中的运动(按照挑战中的建议,通过重新映射命令的含义来注意旋转),完成后,将轴向转换为奇数q偏移坐标。

六个移动映射到(xz)轴向坐标中的以下增量矢量:

q => (-1,  0)
w => ( 0, -1)
e => ( 1, -1)
d => ( 1,  0)
s => ( 0,  1)
a => (-1,  1)

等等,这是Retina,我们将不得不处理一元数。我们如何处理负一元数?这个想法是使用两个不同的数字。一个代表+1另一个代表-1。这意味着无论我们1要从当前位置增加还是减少,我们始终可以通过添加数字来做到这一点。完成后,我们通过取消平衡数字将结果折叠成(相应数字的)大小。然后,我们根据剩余的数字找出符号,并用替换所有数字1

计划是:在输入的前面在a的左侧和右侧(作为分隔符)建立轴向x和z分量。w并且s将添加到右侧。q并且d将添加到左侧,e并且a将添加到两侧。由于ws已经在的正确的一边:(这将走在前面),我们将使用这些作为-1+1分别的数字。

让我们看一下代码。

R
5$*r

我们首先将它们R变成5 r秒。当然,在一个十六进制网格上,左转与五次右转相同,通过这样做,我们可以在重新映射步骤中进行大量复制。

T`aq\we\ds`so`r.+

这是音译阶段,如果六个命令在第一个命令之后找到r(因此处理第一个r),则旋转六个命令。w并且d需要进行转义以防止它们扩展为角色类。所述o插入源组入节省一束这些旋转任务字节目标集。因此,字符映射为:

aqweds
saqweds

s第二行的最后一个可以简单地忽略。

)`r(.*)
$1

r将从字符串中删除第一个,因为它已经被处理(我希望我已经实现了替换限制...)。该)还告诉视网膜运行各个阶段到这一个在一个循环,直到串停止变化。在随后的迭代中,第一阶段是空操作,因为不再有Rs,而第二阶段将应用另一个旋转,只要r字符串中还剩下s。

完成后,我们将所有命令映射到它们在未旋转网格上对应的方向,并可以开始处理这些命令。当然,该运动只是这些增量矢量的总和,并且总和是可交换的,因此,既然消除了旋转,那么我们按什么顺序对其进行处理实际上并不重要。

^
:

在前面插入坐标定界符。

现在我们真的不需要处理sw。它们是我们的+1-1数字,它们已经在正确的一面,:因此最终它们将根据需要退出。我们可以进一步简化:ais s + qeis w + d。让我们这样做:

a
sq
e
wd

同样,那些sw只会辍学。我们需要做的就是将那些qs和ds移到最前面,然后将它们本身变成ws和ss。我们通过两个单独的循环来做到这一点:

+`(.+)q
w$1
+`(.+)d
s$1

这样就完成了。从轴向坐标转换为偏移坐标的时间。为此,我们需要折叠数字。但是,目前我们只关心左侧。由于我们处理qs和ds的方式,我们知道s左侧的所有s都将出现在任何ws的前面,因此我们只需要检查一对即可折叠它们:

+`sw

现在进行实际转换。这是伪代码,取自上面的链接:

# convert cube to odd-q offset
col = x
row = z + (x - (x&1)) / 2

正确,因此左侧已经正确。尽管右侧需要校正项(x - (x&1)) / 2。取&1与模2相同。这基本上解析为x/2整数除法,四舍五入为负无穷大。因此,对于正数x,我们将增加一半的数字(四舍五入),对于负数x,我们将减少一半的数字(四舍五入)。可以用正则表达式简明扼要地表达这一点:

(.*)(\1w?):
$0$2

由于贪婪,对于偶数x,第1组将完全匹配数字\1的一半,另一半将完全匹配,我们可以忽略w?。我们在:x/2)之后插入一半。如果x是偶数,那么我们需要区分正面和负面。如果x为正,则w?永远不会匹配,因此两组仍必须匹配相同的数字。如果s只跳过第一个就没问题,因此我们舍入。如果x为负数且为奇数,则可能的匹配为与\1(一半x舍入)和那个optional w。由于这两个都归为组2,因此我们将按x/2四舍五入的幅度写(按要求)。

+`sw|ws

现在,我们折叠右侧的数字。这一次,我们不知道的顺序sw,所以我们需要考虑两对。

w+
-$0

现在,两个部分都减少为一个重复的数字(或什么都没有)。如果该数字为w,我们在前面插入减号。

\w
1

最后,我们把俱进w,并s成一个单一的一元合理的数字。(我想我可以通过使用ws作为一进制数字来保存一个字节,但这似乎有点麻烦。)


10
(我是唯一看到此答案的人出现在主页上,并非常希望它用六角形书写吗?)
Addison Crump

9
@FlagAsSpam当通过使用只能通过正则表达式处理其输入的语言来解决涉及带符号整数和六边形网格的挑战时,可能使8个人失望(并计数)时,此社区的需求正在急剧增加。;)
Martin Ender

1

的Python(3.5)193 185 182字节

我还计算轴向坐标并在最后进行转换。

我根据@MartinBüttner解决方案添加了一些优化:我用r * 5代替R,它不会更改字节数。但是,这种变化我们可以更换第二次测试elif j=='r'由刚else

解决方案假定输入中不能包含无效字符。

def f(i):
 x=y=0;u=-1,0,-1,1,0,1,1,0,1,-1,0,-1;v='dewqas'
 for j in i.replace('R','r'*5):
  w=v.find(j)*2
  if-1<w:x+=u[w];y+=u[w+1]
  else:u=u[2:]+u[:2]
 print(-x,-x-y+(x-(x%2))/2)

不打高尔夫球

def f(i):
  x=y=0
  u=-1,0,-1,1,0,1,1,0,1,-1,0,-1    # operations list xd,yd,xe,ye...
  v='dewqas'                       # letters list in clockwise order 
  i.replace('R','r'*5)             # replace 'R' by 5*'r'
  for j in i:
    w=v.find(j)*2                  # extract letter index
    if-1<w:
      x+=u[w]                      # apply operations
      y+=u[w+1]
    else:
      u=u[2:]+u[:2]                # rotate clockwise the operation string
  print(-x,-x-y+(x-(x%2))/2)       # convert coordinates axial to "odd-q"

用法

>>> f('wrwrwrwrw')
-1 0.0
>>> f('dddddddddd')
10 5.0
>>> f('edeqaaaswwdqqs')
-2 0.0

0

批,708个 636 586 569字节

我使用了两倍的y坐标,因为它简化了数学运算。我不确定我是否以最理想的方式考虑了轮换,但胜过计数rs 的次数。

编辑:通过改进对Rs 的处理,节省了72个字节。通过优化我的set/a语句节省了60个字节。保存了17个字节,并做了一些小的优化。

@echo off
set m=%1
set/ay=x=0
set r=r
set g=goto l
:l
set/a"z=y>>1
if "%m%"=="" echo %x% %z%&exit/b
set c=%m:~0,1%
set m=%m:~1%
goto %r:rrrrrr=%%c%
:a
:rq
:rrw
:rrre
:rrrrd
:rrrrrs
set/ax-=2
:w
:re
:rrd
:rrrs
:rrrra
:rrrrrq
set/ax+=1,y-=1
%g%
:q
:rw
:rre
:rrrd
:rrrrs
:rrrrra
set/ay-=2
%g%
:s
:ra
:rrq
:rrrw
:rrrre
:rrrrrd
set/ax-=2
:e
:rd
:rrs
:rrra
:rrrrq
:rrrrrw
set/ax+=+1,y+=1
%g%
:d
:rs
:rra
:rrrq
:rrrrw
:rrrrre
set/ay+=2
%g%
:r
:rr
:rrr
:rrrr
:rrrrr
:rrrrrr
if %c%==R set c=rrrrr
set r=%c%%r%
%g%

0

05AB1E,60 个字节

.•F?äM•U2Å0IvXy'rQiÀUëy'RQiÁUëykÐ5α‚ßsD3%_s3›·+‚<+]Ć`DÉ-2÷+‚

在线尝试验证所有测试用例

说明:

一般说明:

我们从字符串"qwedsa"和坐标开始[0,0],然后遍历输入的字符。
如果它是“ r”或“ R”,则分别向左或向右旋转此字符串。
如果不是,我们将在该字符串中获取从0开始的索引,并将其映射如下:

q → 0 → [-1,  0]
w → 1 → [ 0, -1]
e → 2 → [ 1, -1]
d → 3 → [ 1,  0]
s → 4 → [ 0,  1]
a → 5 → [-1,  1]

Xÿ

 x   indices     y   indices
-1 ← 0;5        -1 ← 1;2
 0 ← 1;4         0 ← 0;3
 1 ← 2;3         1 ← 4;5

ķ

X=一世ñķ一种bsķ-5-1个
ÿ=0ķ3+2ķ>3-1个

ÿXX

ÿ=ÿ+X-X22

代码说明:

.•FM         # Push compressed string "qwedsa"
       U        # Pop and store it in variable `X`
2Å0             # Push list [0,0]
                # (many 3-byte alternatives for this: `00S`; `т¦S`; `0D‚`; `1¾‰`; etc.)
   Iv           # Loop over each character `y` of the input:
     X          #  Push string `X`
      y'rQi    '#  If `y` equals "r":
           À    #   Rotate string `X` once towards the left
            U   #   And pop and store it as new value for `X`
      ëy'RQi   '#  Else-if `y` equals "R":
            ÁU  #   Do the same, but rotate right instead
      ë         #  Else:
       yk       #   Get the 0-based index of `y` in the string `X`
         Ð      #   Triplicate this index
          5α    #   Take the absolute difference with 5
            ‚ß  #   Pair it with the original index, and pop and push the minimum
                #   (maps 0→[0,5]→0; 1→[1,4]→1; 2→[2,3]→2;
                #         3→[3,2]→2; 4→[4,1]→1; 5→[5,0]→0)
         sD     #   Swap to get the original index again, and duplicate it
           3%   #   Take modulo 3
             _  #   And check if it's equals to 0 (1 if truthy; 0 if falsey)
          s3   #   Swap to take the index again, and check if it's larger than 
                #   (again, 1 if truthy; 0 if falsey)
             ·  #   Double this
          +     #   And add both checks together
                #   (maps 0→1+0→1; 1→0+0→0; 2→0+0→0;
                #         3→1+0→1; 4→0+2→2; 5→0+2→2)
               #   Pair both mapped values together
          <     #   Decrease both by 1, so it becomes: 0→-1; 1→0; 2→1
           +    #   And add it to the current coordinates
    ]           # After the loop with inner if-else statements:
     Ć          # Enclose the coordinate, appending its own head: [x,y] becomes [x,y,x]
      `         # Push all three values separated to the stack
       D        # Duplicate this x
        É       # Check if its odd (1 if truthy; 0 if falsey)
         -      # Subtract it from the duplicated x
          2÷    # Integer-divide it by 2
            +   # Add it to y
               # And pair it with the original x again
                # (after which the result is output implicitly)

看到这个05AB1E尖矿(部分如何压缩字符串不是字典的一部分吗?理解为什么.•F?äM•"qwedsa"


-1

Python 3,227字节

def G(s):
 q='qwedsa'
 d=[-1,0,1,1,0,-1,-1,-2,-1,1,2,1]
 X=Y=0
 for c in s:
  if c in q:
   n = q.find(c)
   X += d[n]
   Y += d[n+6]
  if c == 'r':
   q = q[1:]+q[0]
  if c == 'R':
   q = q[5]+q[0:5]
 print(X, int((Y-X%2)/2))

Python 3.5.0b3在MacOS上使用,虽然由于四舍五入而在5和6中确实出现错误,但其余都是正确的。(由于已通过“编辑”修复)。您正在使用哪个版本的Python?
奥斯丁·黑斯廷斯

1
@AustinHastings我在Debian不稳定的Python 3上。
Doorknob
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.