Ключевое, что вам нужно здесь, это format
.Отлично подходит для вывода текста в текстовой форме фиксированной ширины.Теперь написание элементов формата для строки format
- это искусство (очень тесно связанное с выполнением того же для sprintf()
в C), которого в наше время не хватает многим, но что-то вроде этого - то, чего вы хотите, если бы вы простовыполнение n == 4
case:
puts [format "%d. %2d %2d %2d" $count $c1 $c2 $c3]
В этом случае, однако, у вас есть более сложная проблема, потому что у вас есть переменное количество полей.Это делает вещи сложнее;вы, вероятно, лучше всего разбираете вещи по частям с помощью процедуры, выполняющей форматирование одной строки:
proc generateLine {n i} {
set line [format "%d." $i]
for {set x 1} {$x <= $n} {incr x} {
# Double-ternary conditional operator
set v [expr {$i == $x*2-1 ? -3 : $i == $x*2 ? 3 : 0}]
append line [format " %2d" $v]
}
return $line
}
Теперь, когда у нас это есть, остальная часть программы достаточно проста:
# Assume that the n variable has been set already
for {set i 1} {$i <= $n*2} {incr i} {
puts [generateLine $n $i]
}
Очень часто в программировании легче всего разбить программу на несколько частей с разумными границами между ними.Знание того, где разделить, - это то, к чему вы лучше подходите с опытом, но очень часто разделение происходит в правильном месте, если вы можете дать разумное имя разделенному фрагменту.Например, выше я видел, что я хотел сделать некоторую работу для каждой строки и некоторую работу, чтобы перебрать все необходимые строки;это было очевидное место, чтобы разбить вещи на части и сделать процедуру, generateLine
.Внешняя часть также довольно именна (возможно generateListOfLines
?), Но это не так важно здесь.