绘制一棵圣诞树

3
我正在尝试以以下形式绘制一棵树:
    *    
   ***
  *****
 *******
*********

正如您所见,我需要每一行都有空格和 "*" 星号,但是我无法得到想要的效果。

#!/bin/bash

display_tree() {
    local rows=$1
    local columns=$2

    for ((i=0; i<$rows; i++))
    do
        #spaces loop
        for ((j=0; j<$columns; j++))
        do
            echo -n " "
            #drawing tree loop
            for ((a=0; a<$(($i + 1)); a++))
            do
                echo -n "*"
            done
        done
    echo 
    done
}

if [ $# -eq 2 ]; then
    display_tree $1 $2
else
    echo "Usage: $0 rows columns"
fi

1
看起来你还没有确定在发射星号之前需要发射多少空格,而且你已经将内部循环包装起来,而不是使它们连续。当树高为3行时,第1行、第2行和第3行的第一个星号前需要放置多少个空格?你的代码如何确保这一点?(提示:它还没有——所以你必须修改它直到它实现这一点。) - Jonathan Leffler
如果你修改最内层循环以发出 printf "a=%s\ti=%s\tj=%s\n" $a $i $j > "/dev/tty????",你将更好地理解脚本的内部。在这里,???? 是在另一个窗口中运行 tty 的结果,并将该数字替换为我的示例中的 '????'。或者,你可以省略 > "/dev/tty..." 并将输出与你的圣诞树混合在一起。祝你好运。 - shellter
3个回答

3

这对我来说似乎有效。建议在“columns”参数中使用奇数。当列= 2 * 行-1时最漂亮。代码中最长的行执行一些基本的代数运算,特别是线性插值,用于确定在给定行中显示星号的数量。

#!/bin/bash
# Christmas tree ASCII drawer
# works nicest for odd integers

spaces() {
  for ((i=0; i<$1; i++)) ; do
    echo -n " "
  done 
}

stars() {
  for ((i=0; i<$1; i++)) ; do
    echo -n "*"
  done
  echo ""
}

display_tree() {
    local rows=$1
    local columns=$2

    # render
    for (( r=1; r <= $rows; r++ )); do
      s=$(( (((columns-1) * (r-1)/(rows-1) + 1)/2)*2 +1 ))
      spaces $(((columns-s)/2))
      stars $s
    done
}

if [ $# -eq 2 ]; then
    display_tree $1 $2
else
    echo "Usage: $0 rows columns"
fi

输出示例:

./display_tree.sh 5 21
          *
       *******
     ***********
  *****************
*********************

./display_tree.sh 30 59
                             *
                            ***
                           *****
                          *******
                         *********
                        ***********
                       *************
                      ***************
                     *****************
                    *******************
                   *********************
                  ***********************
                 *************************
                ***************************
               *****************************
              *******************************
             *********************************
            ***********************************
           *************************************
          ***************************************
         *****************************************
        *******************************************
       *********************************************
      ***********************************************
     *************************************************
    ***************************************************
   *****************************************************
  *******************************************************
 *********************************************************
***********************************************************

1
这个解决方案的逻辑非常简单,最好的解释方法可能是在文本编辑器中绘制几个树的层级,并计算每次迭代的星号和空格数。您很快就会意识到它涉及生成一组数字。例如: 3 1 2 3 1 5 0 7 现在你要做的就是设置一个起点($COLUMNS/2)。 $(eval ...) 部分只是一种不使用循环打印空格和星号的技巧。Eval 是必需的,因为括号 shell 扩展 {1..$var} 在没有它的情况下无法正常工作。
spaces=$(($COLUMNS/2)); 
for ((i=1; i < $LINES; i+=2)); 
    do echo "$(eval printf '\ %.0s' {1..$spaces}) $(eval printf '*%.0s' {1..$i})"; 
    ((spaces--));
done;

@Filnor 我以为逻辑很明显,但我想我错了。我会解释代码的工作原理。 - Dragan

0
letters=( \" \');while true;do clear; letter=${letters[$[RANDOM%${#letters[@]}]]}; [[ $letter == \" ]] && color=35 || color=32;m=2;i=77;p=$(($i/2-1)); while [[ $m -le $i ]];do printf "%${p}s" ;printf "\e[4;${color}m${letter}%.0s\e[m" $(seq $m);echo;m=$[m+2];((p--));done;sleep 1;done 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接