bash 中随机游走 10x10 数组

问题描述 投票:0回答:1

问题: 编写一个程序,在 10 x 10 数组中生成“随机游走”。数组 将包含字符(最初都是

'.'
)。程序必须随机“行走” 从一个元素到另一个元素,总是向上、向下、向左或向右移动一个元素。 程序访问的元素将通过字母
A
进行标记
Z
,按访问顺序。这是所需输出的示例:

A . . . . . . . . .
B C D . . . . . . .
. F E . . . . . . .
H G . . . . . . . .
I . . . . . . . . .
J . . . . . . . Z .
K . . R S T U V Y .
L M P Q . . . W X .
. N O . . . . . . .
. . . . . . . . . .

在执行移动之前,请检查 (a) 不会超出数组,并且 (b) 它不会将我们带到一个元素 已经分配了一封信。如果违反任一条件,请尝试搬入 另一个方向。如果所有四个方向都被阻止,则程序必须 终止。这是提前终止的示例:

A B G H I . . . . .
. C F . J K . . . .
. D E . M L . . . .
. . . . N O . . . .
. . W X Y P Q . . .
. . V U T S R . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .

Y
四个边都被挡住了,所以没地方放
Z

预期输出:

A . . . . . . . . .
B C D . . . . . . .
. F E . . . . . . .
H G . . . . . . . .
I . . . . . . . . .
J . . . . . . . Z .
K . . R S T U V Y .
L M P Q . . . W X .
. N O . . . . . . .
. . . . . . . . . .

实际产量:

.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi
.abcdefghi

这是 C 语言练习,但我正在尝试用 bash 编写它

我的代码不想工作

#!/bin/bash
#set -x
rows=10
cols=10
UP=0
DOWN=1
RIGHT=2
LEFT=3
i=0
b=0
#initialising and filling array with "."
while [ $i -lt $rows ]; do
    while [ $b -lt $cols ]; do
    my_array[$i,$b]='.'
    ((b++))
    done
    b=0
    ((i++))
done

#initialising array with letters from alphabet in each element in ascending order
abc=({a..z})

b=0
r=0
c=0
#set -x
#core section where movements are done with checking boundaries of array and neighboring elements
while [ "$b" -lt "${#abc[@]}" ]; do
move=$(($RANDOM % 4))
case $move in
$UP) if [ $(($r+1)) -lt $rows ] && [ "${my_array[$r+1,$c]}" == "." ]; then
     ((r++))
     my_array[$r,$c]=${abc[$b]}
     ((b++))
     elif [ $(($r-1)) -ge 0 ] && [ "${my_array[$r-1,$c]}" == "." ]; then
     ((r--))
     my_array[$r,$c]=${abc[$b]}
     ((b++))
     elif [ $(($c+1)) -lt $cols ] && [ "${my_array[$r,$c+1]}" == "." ]; then
     ((c++))
     my_array[$r,$c]=${abc[$b]}
     ((b++))
     elif [ $(($c-1)) -ge 0 ] && [ "${my_array[$r,$c-1]}" == "." ]; then
     ((c--))
     my_array[$r,$c]=${abc[$b]}
     ((b++))
     else
     b=${#abc[@]}
     fi;;
$DOWN) if [ $(($r-1)) -ge 0 ] && [ "${my_array[$r-1,$c]}" == "." ]; then
    ((r--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($r+1)) -lt $rows ] && [ "${my_array[$r+1,$c]}" == "." ]; then
    ((r++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($c+1)) -lt $cols ] && [ "${my_array[$r,$c+1]}" == "." ]; then
    ((c++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($c-1)) -ge 0 ] && [ "${my_array[$r,$c-1]}" == "." ]; then
    ((c--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    else 
    b=${#abc[@]}
    fi;;
$RIGHT) if [ $(($c+1)) -lt $cols ] && [ "${my_array[$r,$c+1]}" == "." ]; then
    ((c++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($c-1)) -ge 0 ] && [ "${my_array[$r,$c-1]}" == "." ]; then
    ((c--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($r+1)) -lt $rows ] && [ "${my_array[$r+1,$c]}" == "." ]; then
    ((r++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($r-1)) -ge 0 ] && [ "${my_array[$r-1,$c]}" == "." ]; then
    ((r--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    else
    b=${#abc[@]}
    fi;;
$LEFT) if [ $(($c-1)) -ge 0 ] && [ "${my_array[$r,$c-1]}" == "." ]; then
    ((c--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($c+1)) -lt $cols ] && [ "${my_array[$r,$c+1]}" == "." ]; then
    ((c++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($r+1)) -lt $rows ] && [ "${my_array[$r+1,$c]}" == "." ]; then
    ((r++))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    elif [ $(($r-1)) -ge 0 ] && [ "${my_array[$r-1,$c]}" == "." ]; then
    ((r--))
    my_array[$r,$c]=${abc[$b]}
    ((b++))
    else
    b=${#abc[@]}
    fi;;
*) echo "Something went wrong..."
   exit 1;;
esac
done

i=0
b=0
#set -x

#printing whats in the array
while [ $i -lt $rows ]; do
   b=0
    while [ $b -lt $cols ]; do
    echo -n "${my_array[$i,$b]}"
    ((b++))
    done
    echo
    ((i++))
done

exit 0

编辑: 解决了问题 忘记显式声明关联数组“declare -A my_array” 检查动作时忘记在 my_array 中使用 $(($r+n))

不介意看到更高效的代码。可读性并不重要

arrays bash multidimensional-array random random-walk
1个回答
0
投票

bash 没有多维数组。

my_array[$i,$b]='.'
的行为类似于
my_array[$b]='.'
;因此,您只有 10 个元素的数组,而不是 10x10。

在 bash 4.0+ 上,您可以访问关联数组(基本上是 Python 的

dict
)。您需要提前声明:

declare -A my_array

这有点类似于 Python 中的

my_array = {}
。这样,
my_array[$i,$b]='.'
将表现得像 Python 的
my_array[f"{i},{b}"] = '.'

但是,这意味着您不再拥有整数索引,因此

${my_array[$r-1,$c]}
的行为将类似于 Python 的
my_array[f"{r}-1,{c}"]
 ,即如果
$r=5
$c=3
,它将尝试访问键
5-1,3
而不是
 下的元素4,3
。正确的做法是
${my_array[$((r-1)),$c]}

或者,您可以使用一维字符串数组,例如

${my_array[0]}
".........."
。鉴于 bash 不允许您更改单个字符,这仍然有点尴尬。这也适用于较旧的 bash(例如 Mac OS 上默认提供的 bash)。这是 bash 3.2 兼容的实现:

#!/bin/bash
rows=10
cols=10

# make a prototypal row (`$rows` dots)
# https://stackoverflow.com/a/5349796/240443
dots=$(printf "%${rows}s" | tr ' ' .)
# make an array by repeating the row `$rows` times
read -d '' -r -a my_array < <(yes "$dots" | head -n "$rows")

abc=({a..z})

b=0
r=0
c=0

# start with the first letter
# can't directly change string at index, so we have to do some cutting
prefix="${my_array[r]:0:c}"
suffix="${my_array[r]:c+1}"
letter="${abc[b++]}"
my_array[r]="$letter$suffix"

while [ "$b" -lt "${#abc[@]}" ]
do
  # random order of the four directions, plus the case when they all fail
  for move in $(shuf -e UP DOWN LEFT RIGHT) ELSE
  do
    # calculate the new coordinates
    case $move in
      UP)
        nr=$((r-1))
        nc=$c
        ;;
      DOWN)
        nr=$((r+1))
        nc=$c
        ;;
      LEFT)
        nr=$r
        nc=$((c-1))
        ;;
      RIGHT)
        nr=$r
        nc=$((c+1))
        ;;
      ELSE)
        # no valid move left
        break 2
        ;;
    esac
    # skip invalid coordinates
    if [[
      $nc -ge $cols || $nc -lt 0 || $nr -ge $rows || $nr -lt 0 ||
      ${my_array[nr]:nc:1} != .
    ]]
    then
      continue
    fi
    # move, then set the letter
    r="$nr"
    c="$nc"
    prefix="${my_array[r]:0:c}"
    suffix="${my_array[r]:c+1}"
    letter="${abc[b++]}"
    my_array[r]="$prefix$letter$suffix"
    # no need to try other moves
    break
  done
done

for row in "${my_array[@]}"
do
  echo $row
done
© www.soinside.com 2019 - 2024. All rights reserved.