별 찍기 다이아몬드
문제
0 1 2 3 4 5 6 7 8
0 *
1 * * *
2 * * * * *
3 * * * * * * *
4 * * * * * * * * *
5 * * * * * * *
6 * * * * *
7 * * *
8 *
해답
다이아몬드는 가운데 행인 4행을 기준으로 위아래 대칭이다.
행마다 별의 개수는 1, 3, 5, 7, 9, 7, 5, 3, 1이고, 가운데 행까지 2개씩 늘어났다가 다시 2개씩 줄어든다.
가운데 행에서 떨어진 거리를 n이라고 하면, 별 앞에는 공백이 n개 온다.
- 0행: 공백 4개, 별 1개
- 1행: 공백 3개, 별 3개
- 2행: 공백 2개, 별 5개
- 3행: 공백 1개, 별 7개
- 4행: 공백 0개, 별 9개
- 5행: 공백 1개, 별 7개
- 6행: 공백 2개, 별 5개
- 7행: 공백 3개, 별 3개
- 8행: 공백 4개, 별 1개
공백과 별 개수를 계산해서 출력
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int size = 9;
const int middle_index = size / 2;
for (int row = 0; row < size; row++)
{
int distance = abs(row - middle_index);
int depth = middle_index - distance;
int space_count = distance;
int star_count = 2 * depth + 1;
for (int col = 0; col < space_count; col++)
{
printf(" ");
}
for (int col = 0; col < star_count; col++)
{
printf("*");
}
printf("\n");
}
}
변수 middle_index는 가운데 행 번호인 4를 저장한다.
변수 distance는 현재 행이 가운데 행에서 얼마나 떨어져 있는지를 나타낸다.
변수 depth는 distance와 반대로 현재 행이 얼마나 깊이 들어와 있는지를 나타낸다.
현재 0행이라면, distance는 4이고 depth는 0이다.
현재 1행이라면, distance는 3이고 depth는 1이다.
depth 값은 0, 1, 2, 3, 4, 3, 2, 1, 0 순서로 변하고, 여기에 2 * depth + 1을 적용하면 별 개수 1, 3, 5, 7, 9, 7, 5, 3, 1을 얻을 수 있다.
별 앞에 오는 공백 개수는 가운데 행에서 멀어진 거리와 같으므로 space_count = distance가 된다.
각 칸마다 조건 판단해 출력
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int size = 9;
const int middle_index = size / 2;
for (int row = 0; row < size; row++)
{
for (int col = 0; col < size; col++)
{
int row_distance = abs(row - middle_index);
int col_distance = abs(col - middle_index);
if (row_distance + col_distance <= middle_index)
{
printf("*");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
이 방식은 행마다 공백과 별의 개수를 계산하지 않고, 9 x 9 = 81칸을 모두 검사한다.
다이아몬드 그림에서 각 칸을 (row, col) 좌표로 보면, 별이 찍히는 칸에는 다음 규칙이 있다.
중심 (4, 4)로부터의 행 거리와 열 거리의 합이 4 이하인 칸에 별을 찍는다.
(2, 3)은 중심 (4, 4)로부터 행 거리 2, 열 거리 1만큼 떨어져 있다.
두 거리의 합은 3으로 4 이하이므로 별을 출력한다.
(6, 1)은 중심 (4, 4)로부터 행 거리 2, 열 거리 3만큼 떨어져 있다.
두 거리의 합은 5로 4를 초과하므로 공백을 출력한다.
for문 하나로 전체 칸 순회
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int size = 9;
const int middle_index = size / 2;
const int total_cells = size * size;
for (int cell = 0; cell < total_cells; cell++)
{
int row = cell / size;
int col = cell % size;
int row_distance = abs(row - middle_index);
int col_distance = abs(col - middle_index);
if (row_distance + col_distance <= middle_index)
{
printf("*");
}
else
{
printf(" ");
}
if (col == size - 1)
{
printf("\n");
}
}
}
앞의 “각 칸마다 조건 판단해 출력”에서는 2중 for문으로 전체 81칸을 처리했다.
이번에는 같은 81칸을 for문 하나로 순회할 수 있다.
핵심은 0부터 80까지 증가하는 인덱스 값 cell에 연산을 해서 행 번호와 열 번호를 구하는 것이다.
이렇게 (row, col) 좌표를 구한 뒤에는 앞의 방식처럼 행 방향 거리와 열 방향 거리의 합을 기준으로 공백과 별을 출력한다.
하드 코딩
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int size = 9;
const int middle_index = size / 2;
for (int row = 0; row < size; row++)
{
int distance = abs(row - middle_index);
if (distance == 4)
{
printf(" *\n");
}
else if (distance == 3)
{
printf(" ***\n");
}
else if (distance == 2)
{
printf(" *****\n");
}
else if (distance == 1)
{
printf(" *******\n");
}
else if (distance == 0)
{
printf("*********\n");
}
}
}
이 코드는 현재 행이 가운데 행에서 얼마나 떨어져 있는지를 나타내는 변수 distance만 보고 한 행을 통째로 출력한다.
다만 코드 유연성이 떨어지므로 참고용으로만 살펴보자.