问题: 编写一个程序,在 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))
不介意看到更高效的代码。可读性并不重要
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