Напишем два варианта алгоритма на Java для вывода сердечка в консоль в форме текстового изображения — поздравим женщин с восьмым марта. Нарисуем график функции в форме сердечка и в дополнение нарисуем символ сердечко в форме картинки, а картинку выведем текстом — консольное поздравление с восьмым марта.
Нарисуем два полукруга и один полуромб, заполненные внутри и снаружи. В предыдущем примере мы выводили график функции в консоль — формулы для окружности и для ромба возьмём из него, а в этом примере добавим заполнение фигуры внутри и снаружи — вместо знака равно в формулах подставляем знаки меньше или больше. Условий получится много, в отличие от предыдущего примера.
Нарисуем картинку для наглядности.
Выводим верхнюю часть фигуры, нижнюю часть фигуры, закрашиваем в шахматном порядке и выводим координатные оси. Получаем несколько текстовых изображений, которые выглядят следующим образом.
Радиус: 5, внутри/снаружи/оси: true/true/true.
· · · · · ↑y · · · · ·
· · o o o o o · ¦ · o o o o o · ·
· o * * o · o * * o ·
· o * * * o ¦ o * * * o ·
o * * * * o * * * * o
· o * * * * * o * * * * * o ·
--o --* --* --* --* --+---* --* --* --* --o >x
· o * * * * ¦ * * * * o ·
· o * * * * * * * o ·
· · o * * * ¦ * * * o · ·
· · o * * * * * o · ·
· · · o * * ¦ * * o · · ·
· · · o * * * o · · ·
· · · · o * ¦ * o · · · ·
· · · · o * o · · · ·
· · · · · o ¦ o · · · · ·
· · · · · o · · · · ·
· · · · · · ¦ · · · · · ·
Радиус: 4, внутри/снаружи/оси: false/true/false.
· · · · · · · · · ·
· o o o o o · o o o o o ·
· o o o o o o o o ·
o o o o o o o
· o o o ·
o o
· o o ·
· o o ·
· · o o · ·
· · o o · ·
· · · o o · · ·
· · · o o · · ·
· · · · o o · · · ·
· · · · o · · · ·
· · · · · · · · · ·
Радиус: 3, внутри/снаружи/оси: true/false/false.
o o o o o o
o * * o o * * o
o * * * o * * * o
o * * * * * o
o * * * * o
o * * * o
o * * o
o * o
o o
o
Радиус: 2, внутри/снаружи/оси: false/false/false.
o o o o o o
o o o
o o
o o
o o
o o
o
Обходим диапазон координат двумя вложенными циклами for
: сначала по оси y
и затем по оси x
.
Каждую точку проверяем на соответствие условиям и выводим. В верхней части рисуем два полукруга и
опционально закрашиваем их внутри и снаружи. В нижней части рисуем полуромб и также опционально
закрашиваем внутри и снаружи.
/**
* @param r радиус
* @param gap отступ
* @param in заполнение внутри
* @param out заполнение снаружи
* @param axes координатные оси
*/
public static void printHeartGraph(
int r, int gap, boolean in, boolean out, boolean axes) {
// границы текстового изображения
int xMax = 2*r+gap, xMin = -xMax;
int yMax = r+gap, yMin = -r-yMax;
System.out.println( // заголовок с параметрами
"Радиус: "+r+", внутри/снаружи/оси: "+in+"/"+out+"/"+axes+".");
// вывод в консоль построчно слева направо сверху вниз
for (int y = yMax; y >= yMin; y--) {
for (int x = xMin; x <= xMax; x++) {
double[] circle = { // две окружности левая/правая
Math.round(Math.sqrt(Math.pow(x+r,2)+Math.pow(y,2))), // левая
Math.round(Math.sqrt(Math.pow(x-r,2)+Math.pow(y,2)))}; // правая
int rhombus = Math.abs(x)+Math.abs(y); // ромб
boolean inCh = in && (x+y)%2 == 0; // шахматный порядок внутри
boolean outCh = out && (x+y)%2 == 0; // шахматный порядок снаружи
// каждую точку проверяем на соответствие условиям и выводим
if (axes && y == 0 && x == 0)
System.out.print("+-"); // начало координат
else if (axes && y == 0 && x == xMax)
System.out.print(">x"); // максимум оси абсцисс (x)
else if (axes && x == 0 && y == yMax)
System.out.print("↑y"); // максимум оси ординат (y)
else if (y > 0 && (circle[0] == r || circle[1] == r))
System.out.print("o "); // два полукруга, верх
else if (y > 0 && inCh && (circle[0] < r || circle[1] < r))
System.out.print("* "); // верх внутри
else if (y > 0 && outCh && (circle[0] > r && circle[1] > r))
System.out.print("· "); // верх снаружи
else if (y <= 0 && rhombus == 2*r)
System.out.print("o "); // полуромб, низ
else if (y <= 0 && inCh && rhombus < 2*r)
System.out.print("* "); // низ внутри
else if (y <= 0 && outCh && rhombus > 2*r)
System.out.print("· "); // низ снаружи
else if (axes && y == 0)
System.out.print("--"); // ось абсцисс (x)
else if (axes && x == 0)
System.out.print("¦ "); // ось ординат (y)
else
System.out.print(" "); // пустое место
} // переход на новую строку
System.out.println();
}
}
// запускаем программу и выводим результат
public static void main(String[] args) {
printHeartGraph(5, 1, true, true, true);
printHeartGraph(4, 1, false, true, false);
printHeartGraph(3, 0, true, false, false);
printHeartGraph(2, 0, false, false, false);
}
В предыдущем примере мы рисовали простую капчу — алгоритм отрисовки шрифта возьмём из него, только на этот раз нарисуем бинарное чёрно-белое изображение моноширинным шрифтом, сглаживание не используем. Символ сердечко в форме картинки выглядит следующим образом.
Поскольку символ находится в середине строки, то на полученном изображении половина пикселей пустые. Обходим пиксели построчно и выводим только непустые строки, то есть центральную часть изображения.
Monospaced.plain, 22, символы: ♡
o o o
o o o o o o o
o o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o
Monospaced.plain, 28, символы: ♡
o o
o o o o o o o o
o o o o
o o o o
o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o
Monospaced.plain, 36, символы: ♡
o o o o o o o
o o o o o o o
o o o o
o o o o
o o o o
o o o
o o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
Рисуем строку текста в виде чёрно-белого изображения, затем обходим пиксели этого изображения и выводим их текстом в консоль построчно. Рисуем только центральную часть изображения с текстом, пустые строки пикселей не выводим.
// рисуем текст в форме картинки и картинку в форме текста
public static void printTextImage(String str, Font font) {
FontRenderContext ctx = // контекст отображения шрифта
new FontRenderContext(font.getTransform(), false, false);
// получаем размеры картинки с текстом при отрисовке
Rectangle bnd = font.getStringBounds(str, ctx).getBounds();
// создаём новое бинарное чёрно-белое изображение
BufferedImage image = new BufferedImage(
bnd.width, bnd.height, BufferedImage.TYPE_BYTE_BINARY);
// включаем режим редактирования нового изображения
Graphics2D graphics = image.createGraphics();
// шрифт для отрисовки, сглаживание не используем
graphics.setFont(font);
// рисуем картинку с текстом
graphics.drawString(str, bnd.x, -bnd.y);
// отключаем режим редактирования
graphics.dispose();
// выводим заголовок
System.out.println(
font.getFontName()+", "+font.getSize()+", символы: "+str);
// обходим пиксели построчно и выводим непустые строки
for (int y = 0; y < bnd.height; y++) {
StringBuilder line = new StringBuilder();
for (int x = 0; x < bnd.width; x++)
line.append(image.getRGB(x, y) == -1 ? "o " : " ");
// рисуем только непустые строки
if (line.indexOf("o") != -1) System.out.println(line);
}
}
// запускаем программу и выводим результат
public static void main(String[] args) {
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 22));
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 28));
printTextImage("♡", new Font(Font.MONOSPACED, Font.PLAIN, 36));
}
В последнем примере используется библиотека Java AWT.
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.image.BufferedImage;
© Головин Г.Г., Код с комментариями, 2023