Добрый день!
Занимаюсь решением задач из задачника Андрея Столярова. В процессе решения задачи 2.15. возник вопрос.
Задача следующая:
"Написать программу, запрашивающую два числа (высоту буквы и количество таких букв) и печатающую нужное количество букв Z заданной высоты, причем каждая следующая буква Z должна отстоять от предыдущей на один пробел по горизонтали и на половину высоты буквы по вертикали. Например, для чисел 7 и 3 картина должна получиться такая:
*******
     *
    *
******* *******
  *          *
 *          *
******* ******* *******
          *          *
         *          *
        ******* *******
                  *
                 *
                *******
Программу написал следующую:
rogram z_sequence;
procedure PrintChars(count: integer);
var
    i: integer;
begin
    for i := 1 to count do
        write('*')
end;
procedure PrintSpaces(count: integer);
var
    i: integer;
begin
    for i := 1 to count do
        write(' ')
end;
procedure PrintLineOfDiamondUp(i, z: integer);
begin
    if i = 1 then
        PrintChars(z)
    else
        begin
            PrintSpaces(z - i);
            PrintChars(1)
        end;
    writeln
end;
procedure PrintLineOfDiamondDown(i, z: integer);
begin
    if i = 1 then
        exit
    else
        begin
            PrintSpaces(i - 1);
            PrintChars(1)
        end
end;
procedure PrintFirstHalf(z: integer);
var
    i: integer;
begin
    for i := 1 to (z div 2) do
        PrintLineOfDiamondUp(i, z)
end;
procedure PrintFirstCenterBar(z, n: integer);
begin
    if n > 1 then
        begin
            PrintChars(z);
            PrintSpaces(1);
            PrintChars(z);
            writeln
        end
    else
        PrintChars(z);
        writeln
end;
procedure PrintHalf(i, a, z: integer);
var
    count: integer;
begin
    if i = 1 then
    begin
        for count := (z div 2) downto 2 do
            begin
                PrintSpaces(a * z + a);
                PrintLineOfDiamondDown(count, z);
                writeln
            end
    end;
    if i > 1 then
    begin
        for count := (z div 2) downto 2 do
            begin
                PrintSpaces(a * z + a);
                PrintLineOfDiamondDown(count, z);
                PrintSpaces((z div 2 + 1) + 1 + (z - 2));
                PrintChars(1);
                writeln
            end
    end
end;
procedure PrintBar(i, a, z: integer);
begin
    if i = 1 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        writeln
    end;
    if i = 2 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        writeln
    end;
    if i >= 3 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        writeln
    end
end;
var
    i, n, a, z: integer;
begin
    repeat
        writeln('Enter the letter''s height (5 or more, odd)');
        readln(z);
    until (z >= 5) and (z mod 2 = 1);
    repeat
        writeln('Enter the number of the letters');
        readln(n);
    until (n >= 1);
    PrintFirstHalf(z);
    PrintFirstCenterBar(z, n);
    a := 0;
    for i := n downto 1 do
        begin
            PrintHalf(i, a, z);
            PrintBar(i, a, z);
            a := a + 1
        end
end.
Однако, она выдавала такой результат:
*******
     *
    *
******* *******
  *          *
 *          *
******* ******* *******
          *          *
         *          *
        ******* *******
                  *
                 *
                *******
т.е. после первой центральной черты печатается лишний перенос строки.
Опытным путем понял, что если в процедуре PrintFirstCenterBar убрать writeln и напечатать вместо
procedure PrintFirstCenterBar(z, n: integer);
begin
    if n > 1 then
        begin
            PrintChars(z);
            PrintSpaces(1);
            PrintChars(z);
            writeln
        end
    else
        PrintChars(z);
        writeln
end;
procedure PrintFirstCenterBar(z, n: integer);
begin
    if n > 1 then
        begin
            PrintChars(z);
            PrintSpaces(1);
            PrintChars(z);
        end
    else
        PrintChars(z);
        writeln
end;
программа станет работать корректно.
Но почему так происходит?
Ни PrintChars ни PrintSpaces не печатает перенос строки. В условии после else стоит writeln и если попросить программу напечатать одну букву Z лишнего переноса не произойдет.
Подпрограмма PrintBar
procedure PrintBar(i, a, z: integer);
begin
    if i = 1 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        writeln
    end;
    if i = 2 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        writeln
    end;
    if i >= 3 then
    begin
        PrintSpaces(a * z + a);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        PrintSpaces(1);
        PrintChars(z);
        writeln
    end
end;
очень похожа по своей структуре на PrintFirstCenterBar, но там все writeln стоят на своём месте и никакого лишнего переноса строки не вызывают.
Так почему же тогда в подпрограмме PrintFirstCenterBar оператор writeln является лишним?



