Как создать дизайн персонажей с помощью цикла do - PullRequest
0 голосов
/ 12 февраля 2019

Я пытаюсь создавать символы с выводом как таковым в Фортране, но я не знаю, как это сделать.Я сделал один с колонками звездочек, но теперь мне нужно, чтобы он изменился на связанное изображение.Я новичок в Фортране.

screenshot from given example

Вот мой код для столбцов:

program chardesign

    integer complete
    do complete = 1, 5
        write (*, 10, advance='no')
10      format ('  *  ')
    enddo
    !Newline to complete
    write (*, 10)
    stop

end program chardesign 

Как я могу это сделать

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Поскольку мы больше не можем сдерживать себя в предложении решений ...

Предположим, у нас есть файл с именем diamond.txt, в котором уже нарисована картинка:

    *    
   ***   
  *****  
 ******* 
*********
 ******* 
  *****  
   ***   
    *    

Я знаю, что этоздесь не видно, но каждая строка в diamond.txt имеет достаточно пробелов, чтобы сделать ее длиной 9 символов.Теперь нам просто нужна программа, которая копирует diamond.txt в свой вывод:

program diamond
   implicit none
   character(9) line
   open(10,file='diamond.txt',status='old')
   do
      read(10,'(a)',end=20) line
      write(*,'(a)') line
   end do
20 continue
end program diamond

У программы есть пара новых функций: во-первых, она имеет implicit none, которая заставляет программиста объявлять все переменные, таким образомизбегая общего источника трудно отслеживаемых ошибок программирования.Затем он объявляет символьную переменную character(9) line, которая создает переменную, которая всегда содержит 9 символов.Существуют правила, которые определяют, что произойдет, если вы попытаетесь присвоить его строке меньшей или большей длины, но здесь мы не будем этого делать.

Затем открывается файл diamond.txt.Номер блока 10 будет использоваться для ссылки на файл в последующих операторах ввода / вывода.Часть status='old' заставит программу прерваться, если она не сможет найти diamond.txt.
Тогда у нас есть оператор do, что означает do forever.Конечно, мы не хотим «делать вечно», поэтому должен быть какой-то способ выхода из цикла из его тела.

Теперь у нас есть оператор read, который читает из блока 10, который, согласно нашему предыдущему оператору open, является нашим файлом diamond.txt.Часть end=20 означает, что когда оператор read пытается прочитать прошедшее выполнение конца файла, происходит переход к оператору № 20, что выводит нас из цикла.Формат (a) делает символьный ввод / вывод.Это то же самое, что и (a9), потому что программа знает, что длина символьной переменной для чтения, line, равна 9, поэтому она попытается прочитать следующие 9 символов из diamond.txt и поместить их в переменную line.После завершения оператора read указатель файла переходит на следующую строку diamond.txt.

Тогда оператор write просто записывает переменную line в стандартный вывод, таким образом копируя текущую строку diamond.txt на экран.
Когда это сделано, ветвь end=20 берется, получаяпереходим к оператору 20 continue, после которого встречается строка end и выполнение прекращается.

Так как мы можем сделать это без внешнего файла?Мы могли бы просто преобразовать изображение в оператор format и затем напечатать в соответствии с format:

1 format('    *    '/ &
         '   ***   '/ &
         '  *****  '/ &
         ' ******* '/ &
         '*********'/ &
         ' ******* '/ &
         '  *****  '/ &
         '   ***   '/ &
         '    *    ')
print 1
end

Так что мы столкнулись с новым спецификатором формата, /, «косой чертой», которыйпродвигает ввод / вывод к следующей записи (или строке).Также символ продолжения произвольного формата &, «амперсанд», что означает, что текущая строка продолжается до следующей строки без комментария.Также оператор print, где здесь print 1 имеет тот же эффект, что и write(*,1).

Хорошо, но что, если мы захотим выполнить какой-то расчет для получения изображения?Если считать, что изображение лежит на растровом массиве, где строка i проходит от 1 вверху до 9 внизу, а столбец j - от столбца 1 слева до столбца 9 справа, мы можем наблюдать, что изображение симметричноо я = 5 и о J = 5.Если бы мы рассматривали i и j для запуска от -4 до 4, мы могли бы увидеть некоторые паттерны, которые позволяют нам теперь воспользоваться симметрией относительно оси y и оси x.Соответственно, мы пишем программу, которая будет выводить координаты ...

print"(9(1x:'(',i2,',',i2,')'))",[((i,j,j=-4,4),i=-4,4)];end

Теперь у нас есть пара новых программных элементов: есть конструктор массива [stuff], который создаст массив из перечисленных элементовв квадратных скобках.
[(more_stuff,i=-4,4)] - это ac-подразумеваемый-do , который эффективно создает список путем последовательной оценки more_stuff для каждого значения i от -4 до 4, таким образом,список из 9 вещей.
[((still_more_stuff,j=-4,4),i=-4,4)] является вложенным ac-impied-do , который для каждого значения i составляет список, последовательно оценивая still_more_stuff для каждого значения j изОт -4 до 4, таким образом, имеется список из 9 * 9 = 81 вещей.
Так как still_more_stuff равен i,j, то есть 2 вещи, конструктор массива создает массив из 162 вещей, каждая из которых (i,j) соединяется сj меняется быстрее, чем I.

Оператор print имеет строку формата, заключенную в " двойные кавычки вместо ' апострофов, так что мы можем использовать в формате строки, разделенные апострофом.
Часть 9(stuff) является счетчиком повторенийэто означает, что нужно выполнить форматы, указанные в stuff 9 раз.
Формат 1x говорит просто пропустить один пробел, а следующий двоеточие просто отделяет его от следующего элемента формата.Мы можем использовать , (запятая), : (двоеточие) или / (косая черта) для разделения элементов формата.Как помнит читатель, косая черта переходит к следующей записи;для целей или текущего обсуждения давайте проигнорируем различие между запятой и двоеточием.

Формат i2 выводит целое число в поле ширины 2. Если для печати целого числа требуется более 2 символов, вместо него будут напечатаны две звездочки **.
Так чтоФормат с количеством повторов выведет 2 * 9 = 18 целых чисел.Когда формат исчерпан, существуют правила, называемые реверсией формата, которые в этом случае приведут к переносу вывода на следующую строку и повторному использованию формата.

Наконец, в коде свободного формата можно записать следующую строку кода в текущей, если за текущим оператором следует точка с запятой ;.Таким образом, ;end помещает обязательный оператор end в конец программы.Обратите внимание, что вводный оператор program, хотя и в хорошем стиле, является необязательным.

Вывод программы следующий:

 (-4,-4) (-4,-3) (-4,-2) (-4,-1) (-4, 0) (-4, 1) (-4, 2) (-4, 3) (-4, 4)
 (-3,-4) (-3,-3) (-3,-2) (-3,-1) (-3, 0) (-3, 1) (-3, 2) (-3, 3) (-3, 4)
 (-2,-4) (-2,-3) (-2,-2) (-2,-1) (-2, 0) (-2, 1) (-2, 2) (-2, 3) (-2, 4)
 (-1,-4) (-1,-3) (-1,-2) (-1,-1) (-1, 0) (-1, 1) (-1, 2) (-1, 3) (-1, 4)
 ( 0,-4) ( 0,-3) ( 0,-2) ( 0,-1) ( 0, 0) ( 0, 1) ( 0, 2) ( 0, 3) ( 0, 4)
 ( 1,-4) ( 1,-3) ( 1,-2) ( 1,-1) ( 1, 0) ( 1, 1) ( 1, 2) ( 1, 3) ( 1, 4)
 ( 2,-4) ( 2,-3) ( 2,-2) ( 2,-1) ( 2, 0) ( 2, 1) ( 2, 2) ( 2, 3) ( 2, 4)
 ( 3,-4) ( 3,-3) ( 3,-2) ( 3,-1) ( 3, 0) ( 3, 1) ( 3, 2) ( 3, 3) ( 3, 4)
 ( 4,-4) ( 4,-3) ( 4,-2) ( 4,-1) ( 4, 0) ( 4, 1) ( 4, 2) ( 4, 3) ( 4, 4)

Глядя на эти результаты, мы можем наблюдать, что внутри алмаза | i | + | j | <= 4, когда он снаружи, |я | + | J |> = 5.Давайте создадим программу для проверки этого:

print'(9(L1))',[((abs(j)+abs(i)<5,j=-4,4),i=-4,4)];end

Аналогично предыдущей программе, но теперь still_more_stuff во внутреннем ac-implied-do , abs(j)+abs(i)<5 является logical выражение, которое спрашивает ': | j | + | i |меньше 5? ' Значение выражения будет .TRUE. или .FALSE., в зависимости от результата этого теста.
Формат L1 является спецификатором logical I / O, который выводитT для. TRUE.или F для .FALSE ..

Вывод программы выглядит следующим образом:

FFFFTFFFF
FFFTTTFFF
FFTTTTTFF
FTTTTTTTF
TTTTTTTTT
FTTTTTTTF
FFTTTTTFF
FFFTTTFFF
FFFFTFFFF

Мы можем видеть ромб, но нам нужно преобразовать в (пробелы) и* (звездочки):

print'(9a)',merge('*',' ',[((abs(j)+abs(i)<5,j=-4,4),i=-4,4)]);end

И это так!Функция merge обрабатывает наш массив logical (третий аргумент) и везде, где встречается элемент .TRUE., заменяет его звездочкой * (первый аргумент), а каждый элемент .FALSE. заменяется пробелом. (второй аргумент).

Результирующий массив из 81 элемента печатается по 9 элементов за раз в строке формата (9a), что приводит к желаемому результату.Вся программа, хотя и сложная для написания, была длиной всего 66 символов:)

0 голосов
/ 14 февраля 2019

Я предлагаю этот подход к реализации, потому что он дает вам гибкость в отношении длины строки символов для печати. ​​

program chardesign
  implicit none

  call print_diamond('*', 5, 1)
  call print_diamond('()', 3, 3)
  call print_diamond('.', 1, 4)
  call print_diamond('0', 0, 3)

contains

  subroutine print_diamond(str, depth, start)
    character(*), intent(in) :: str
    integer, intent(in) :: depth, start
    character(len(str)) :: spc
    integer :: i, span

    spc = ''
    span = start + (depth - 1) * 2
    print '(a)', (repeat(spc, (span - i) / 2) // repeat(str, i), i = start, span, 2)
    print '(a)', (repeat(spc, (span - i) / 2) // repeat(str, i), i = span - 2, start, -2)
  end
end

Это дает следующий вывод:

    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *

    ()()()
  ()()()()()
()()()()()()()
  ()()()()()
    ()()()

....
...