Reputation: 21
I have a problem that I hope you can help with.
The Java program should print hearts in ASCII-art style, based on the input N
given by a user.
Information:
N
determines the top part of the heart:
N
hearts in them.N
hearts in them.N
hearts wide.Examples:
My current code:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the number of hearts you want to print");
int userInput = scan.nextInt();
printTop(userInput);
}
public static void printTop(int userInput) {
String row = "";
int width = 2 * (userInput - 1) + 3 * userInput;
for (int height = 0; height < userInput; height++) {
for (int i = 0; i < userInput - 1; i++) {
row += "♡";
}
for (int i = 0; i < userInput; i++) {
row += "♥";
}
for (int i = 0; i < userInput; i++) {
row += "♡";
}
for (int i = 0; i < userInput; i++) {
row += "♥";
}
for (int i = 0; i < userInput - 1; i++) {
row += "♡";
}
row += "\n";
}
System.out.println(row);
}
Thoughts:
2 * (userInput - 1) + 3 * userInput
Questions:
Upvotes: 1
Views: 7360
Reputation: 4475
Nice challenge:
import java.util.Scanner;
public class A {
public static final char COLORED = '♥';
public static final char WHITE = '♡';
public static void printTop(int userInput) {
StringBuffer row = new StringBuffer();
int width = 2 * (userInput - 1) + 3 * userInput;
// white hearts at the outside
int outerHearts = userInput - 1;
// left colored section or complete
// colored line from the widest point
int heartsSection1 = userInput;
// right color section or 0 from the widest point
int heartsSection2 = userInput;
// white hearts between 2 colored sections
int innerHearts = userInput;
boolean upperPart = true;
while (heartsSection1 > 0) {
for (int i = 0; i < outerHearts; i++) {
row.append(WHITE);
}
for (int i = 0; i < heartsSection1; i++) {
row.append(COLORED);
}
for (int i = 0; i < innerHearts; i++) {
row.append(WHITE);
}
for (int i = 0; i < heartsSection2; i++) {
row.append(COLORED);
}
for (int i = 0; i < outerHearts; i++) {
row.append(WHITE);
}
row.append("\n");
if (upperPart) {
if (outerHearts > 0) {
outerHearts--;
innerHearts = Math.max(0, innerHearts - 2);
if (outerHearts == 0) {
heartsSection1 = width;
heartsSection2 = 0;
} else {
heartsSection1 += 2;
heartsSection2 += 2;
}
} else {
// line with only colored hearts,
// from now on the hearts reduce
upperPart = false;
}
}
if (!upperPart) {
outerHearts++;
heartsSection1 -= 2;
}
if (heartsSection1 <= 0)
break;
}
System.out.println(row.toString());
}
public static void main(String args[]) {
System.out.println("Enter the number of hearts you want to print");
Scanner scan = new Scanner(System.in);
int userInput = scan.nextInt();
printTop(userInput);
}
}
In my output it is not a perfect rectangle as the white heart is a little smaller than the colored heart.
Upvotes: 0
Reputation:
You can use the java.awt
package to draw these characters ♥♡
as a black and white picture:
And then you can print a 2D array of pixels as characters that make up this picture:
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡
♡ ♡
public static void main(String[] args) {
int[][] hearts = stringToPixels("♥♡", new Font(Font.SERIF, Font.PLAIN, 22), 0);
// output
for (int[] row : hearts) {
StringBuilder sb = new StringBuilder();
for (int i : row)
sb.append(i != 0 ? "♡ " : " ");
if (sb.indexOf("♡") > -1)
System.out.println(sb);
}
}
/**
* @param str source string to draw
* @param f font to render text
* @param pd padding as a precaution, in most cases 0
* @return the 2D array of pixels that make up this string
*/
static int[][] stringToPixels(String str, Font f, int pd) {
FontRenderContext ctx = new FontRenderContext(f.getTransform(), false, false);
Rectangle bounds = f.getStringBounds(str, ctx).getBounds();
int width = bounds.width + pd * 2;
int height = bounds.height + pd * 2;
BufferedImage image =
new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setFont(f);
graphics.drawString(str, pd + bounds.x, pd - bounds.y);
//ImageIO.write(image, "png", new File("str.png"));
int[][] pcx = new int[height][width];
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
if (image.getRGB(j, i) == 0xFFFFFFFF)
pcx[i][j] = 1;
return pcx;
}
Upvotes: 0
Reputation: 159106
The easiest is to build a char[]
for the line, fill it with blank hearts, then fill the sides with white hearts, and calculate and fill the center with white hearts.
The result is very concise and fast code, but the center calculation might seem complex, when though it's a simple formula.
public static void printHeart(int n) {
printHeart(n, '\u2665', '\u2661');
}
public static void printHeart(int n, char black, char white) {
if (n <= 0)
return;
int width = 5 * n - 2;
char[] buf = new char[width];
for (int i = 1 - n; i < (width + 1) / 2; i++) {
int outer = Math.abs(i), center = 2 - n - 2 * i;
Arrays.fill(buf, black);
Arrays.fill(buf, 0, outer, white);
Arrays.fill(buf, width - outer, width, white);
if (center > 0)
Arrays.fill(buf, (width - center) / 2, (width + center) / 2, white);
System.out.println(buf);
}
}
Notice how the code doesn't need separate sections for printing top and bottom halfs. This is a trick achieved by iterating i
from negative to positive numbers, e.g. for n=4
, i
is iterated from -3
to +8
, both inclusive.
Tests
Since the font on my browser don't use hearts of equal width, the result is bad, so the following test uses regular characters.
for (int n = 0; n <= 6; n++)
printHeart(n, 'X', '.');
Outputs
X.X
.X.
.XX..XX.
XXXXXXXX
.XXXXXX.
..XXXX..
...XX...
..XXX...XXX..
.XXXXX.XXXXX.
XXXXXXXXXXXXX
.XXXXXXXXXXX.
..XXXXXXXXX..
...XXXXXXX...
....XXXXX....
.....XXX.....
......X......
...XXXX....XXXX...
..XXXXXX..XXXXXX..
.XXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXX
.XXXXXXXXXXXXXXXX.
..XXXXXXXXXXXXXX..
...XXXXXXXXXXXX...
....XXXXXXXXXX....
.....XXXXXXXX.....
......XXXXXX......
.......XXXX.......
........XX........
....XXXXX.....XXXXX....
...XXXXXXX...XXXXXXX...
..XXXXXXXXX.XXXXXXXXX..
.XXXXXXXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXXXXXXX
.XXXXXXXXXXXXXXXXXXXXX.
..XXXXXXXXXXXXXXXXXXX..
...XXXXXXXXXXXXXXXXX...
....XXXXXXXXXXXXXXX....
.....XXXXXXXXXXXXX.....
......XXXXXXXXXXX......
.......XXXXXXXXX.......
........XXXXXXX........
.........XXXXX.........
..........XXX..........
...........X...........
.....XXXXXX......XXXXXX.....
....XXXXXXXX....XXXXXXXX....
...XXXXXXXXXX..XXXXXXXXXX...
..XXXXXXXXXXXXXXXXXXXXXXXX..
.XXXXXXXXXXXXXXXXXXXXXXXXXX.
XXXXXXXXXXXXXXXXXXXXXXXXXXXX
.XXXXXXXXXXXXXXXXXXXXXXXXXX.
..XXXXXXXXXXXXXXXXXXXXXXXX..
...XXXXXXXXXXXXXXXXXXXXXX...
....XXXXXXXXXXXXXXXXXXXX....
.....XXXXXXXXXXXXXXXXXX.....
......XXXXXXXXXXXXXXXX......
.......XXXXXXXXXXXXXX.......
........XXXXXXXXXXXX........
.........XXXXXXXXXX.........
..........XXXXXXXX..........
...........XXXXXX...........
............XXXX............
.............XX.............
Upvotes: 0
Reputation:
Imagine a coordinate plane and draw a figure that consists of two half-сircles and one half-rhombus.
Pictures 1 and 2:
Figure 1 - Try it online!
int n = 6;
for (int y = -n; y <= 2 * n; y++) {
for (int x = -2 * n; x <= 2 * n; x++)
if ((y <= 0 &&
((int) Math.sqrt((x+n)*(x+n) + y*y) <= n
|| (int) Math.sqrt((x-n)*(x-n) + y*y) <= n))
|| (y > 0 && Math.abs(x) <= 2 * n - y))
System.out.print("♥ ");
else
System.out.print("♡ ");
System.out.println();
}
Output 1:
♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡
♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡
♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡
♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥
♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥
♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥
♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥
♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡
♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡
♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
Figure 2 - Try it online!
int n = 6;
for (int y = -n; y <= 2 * n; y++) {
for (int x = -2 * n; x <= 2 * n; x++)
if ((y <= 0 &&
((int) Math.sqrt((x+n)*(x+n) + y*y) == n
|| (int) Math.sqrt((x-n)*(x-n) + y*y) == n))
|| (y > 0 && Math.abs(x) == 2 * n - y))
System.out.print("♥ ");
else
System.out.print("♡ ");
System.out.println();
}
Output 2:
♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡ ♡ ♡ ♥ ♥ ♥ ♥ ♥ ♥ ♥ ♡ ♡ ♡
♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡
♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡
♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥
♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥
♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥
♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥
♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡
♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡
♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♥ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡ ♡
See also:
• Print out an ASCII circle and axes with characters
• How to draw a double empty ASCII rhombus?
Upvotes: 4
Reputation: 21
I solved the task with the following code:
import java.util.Scanner;
public class ChristmasHearts {
private int userInput;
private int height;
private int width;
String topHeart = "";
String middleHeart = "";
String bottomHeart = "";
public ChristmasHearts(int input) {
this.userInput = input;
}
public void draw() {
calcWidthAndHeight(this.userInput);
drawTopOfHeart();
drawBottomOfHeart();
}
private void drawTopOfHeart() {
int whites = 0;
int blacks = 1;
int center = 1;
int heightOfTopHeart = 1;
int isEvenCenterLessSubtractor = 2;
int isNotEvenCenterLessSubtractor = 1;
if (this.userInput == 1) {
for (int i = 0; i < heightOfTopHeart; i++) {
this.topHeart += "♥";
this.topHeart += "♡";
this.topHeart += "♥";
}
System.out.println(topHeart);
} else {
whites = this.userInput - 1;
blacks = this.userInput;
center = this.userInput;
heightOfTopHeart = this.userInput - 1;
for (int i = 0; i < heightOfTopHeart; i++) {
for (int j = 0; j < whites; j++) {
this.topHeart += "♡";
}
for (int j = 0; j < blacks; j++) {
this.topHeart += "♥";
}
for (int j = 0; j < center; j++) {
this.topHeart += "♡";
}
if (this.userInput >= 5 && center <= 0) {
if (isEven(this.userInput) && center == 0) {
for (int j = 0; j < blacks; j++) {
this.topHeart += "♥";
}
} else if (isEven(this.userInput) && center < 0) {
int rightSideBlacks = blacks - isEvenCenterLessSubtractor;
for (int j = 0; j < rightSideBlacks; j++) {
this.topHeart += "♥";
}
isEvenCenterLessSubtractor += 2;
} else if (!isEven(this.userInput) && center < 0) {
int rightSideBlacks = blacks - isNotEvenCenterLessSubtractor;
for (int j = 0; j < rightSideBlacks; j++) {
this.topHeart += "♥";
}
isNotEvenCenterLessSubtractor += 2;
} else {
int factorToSubtract = 2;
int rightSideBlacks = blacks - factorToSubtract;
for (int j = 0; j < rightSideBlacks; j++) {
this.topHeart += "♥";
}
factorToSubtract += 2;
}
} else {
for (int j = 0; j < blacks; j++) {
this.topHeart += "♥";
}
}
for (int j = 0; j < whites; j++) {
this.topHeart += "♡";
}
whites -= 1;
blacks += 2;
center -= 2;
if (this.userInput == 0) {
this.topHeart = "";
}
System.out.println(topHeart);
topHeart = "";
}
}
}
private void drawMiddelOfHeart() {
for (int j = 0; j < this.width; j++) {
this.middleHeart += "♥";
}
if (this.userInput == 0) {
this.middleHeart = "";
}
System.out.println(this.middleHeart);
middleHeart = "";
}
private void drawBottomOfHeart() {
int whites = 1;
int blacks = 1;
int heightOfBottomHeart = 1;
if (this.userInput == 1) {
for (int i = 0; i < heightOfBottomHeart; i++) {
this.bottomHeart += "♡";
this.bottomHeart += "♥";
this.bottomHeart += "♡";
}
System.out.println(bottomHeart);
} else {
heightOfBottomHeart = this.height - this.userInput;
whites = 1;
blacks = this.width - 2;
drawMiddelOfHeart();
for (int i = 0; i < heightOfBottomHeart; i++) {
for (int j = 0; j < whites; j++) {
this.bottomHeart += "♡";
}
for (int j = 0; j < blacks; j++) {
this.bottomHeart += "♥";
}
for (int j = 0; j < whites; j++) {
this.bottomHeart += "♡";
}
blacks -= 2;
whites += 1;
if (this.userInput == 0) {
this.bottomHeart = "";
}
System.out.println(bottomHeart);
bottomHeart = "";
}
}
}
private boolean isEven(int n) {
return n % 2 == 0;
}
private void calcWidthAndHeight(int n) {
this.width = 3;
this.height = 2;
for (int counter = 1; counter <= (n - 1); counter++) {
this.width += 5;
if (isEven(counter)) {
this.height += 4;
} else {
this.height += 3;
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int input = scanner.nextInt();
scanner.close();
ChristmasHearts heart = new ChristmasHearts(input);
heart.draw();
}
}
Upvotes: 0