Reputation: 71
The exercise asks me to create a program which receives an integer number n
and prints the following pattern with a 2*n
height.
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
What I've already done is:
void arte(int n)
{
int i, barrasE, aux, espacobarrasE, ebE, espaco;
aux = n;
for(i = 1; i <= n; i++)
{
if(aux < n) //Prints the spaces on the superior part.
{
espacobarrasE = n - aux;
for(ebE = 0; ebE < espacobarrasE; ebE++)
printf(" ");
}
for(barrasE = 1; barrasE <= aux; barrasE++) //Prints the backslashes on the superior part.
{
printf("\\");
break;
}
for(espaco = 1; espaco < n; espaco++)
{
printf(" ");
}
aux = aux - 1;
printf("\n");
}
}
This only prints the backslashes on the top and I don't know how to continue the code. I would like to know if it's a good way to do it and what is the better way to continue the code.
Upvotes: 3
Views: 148
Reputation: 753675
I'd develop the solution in stages, roughly like this. My solution insists on the n
parameter (for which I use N
in the code) is an odd number. The question doesn't show how to present the result if it is even. The insistence is backed up by assertions.
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
int main(void)
{
print_line(0, BSLASH, 4, '*', 1, FSLASH);
print_line(1, BSLASH, 2, '*', 3, FSLASH);
print_line(2, BSLASH, 0, '*', 5, FSLASH);
print_line(3, BSLASH, 0, '*', 3, FSLASH);
print_line(4, BSLASH, 0, '*', 1, FSLASH);
print_line(4, FSLASH, 0, '*', 1, BSLASH);
print_line(3, FSLASH, 0, '*', 3, BSLASH);
print_line(2, FSLASH, 0, '*', 5, BSLASH);
print_line(1, FSLASH, 2, '*', 3, BSLASH);
print_line(0, FSLASH, 4, '*', 1, BSLASH);
putchar('\n');
return 0;
}
The repeat_char()
function is a very simple little loop that prints the specified character the specified number of times. By making it static inline
, there's a good chance that the compiler will not make a function call but will place the body of function into the calling code.
The print_line()
function characterizes each line as:
c1
nc
occurrences of c2
(that must be an odd number)c3
The code in main()
calls that function with appropriate arguments written out manually. It generates the output:
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
This looks like what you're after for N=5. But those argument lists to the the function have an awful lot of regularity to them. There must be a way to generate the calls with those numbers replaced by expressions. This observation leads to stage 2.
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static inline int max(int x, int y) { return (x > y) ? x : y; }
static inline int min(int x, int y) { return (x < y) ? x : y; }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
static void driver_1(int N)
{
assert(N % 2 == 1 && N > 0);
for (int i = 0; i < N; i++)
{
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
print_line(i, BSLASH, 2*nb, '*', db, FSLASH);
}
for (int i = N-1; i >= 0; i--)
{
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
print_line(i, FSLASH, 2*nb, '*', db, BSLASH);
}
putchar('\n');
}
int main(void)
{
int N = 5;
assert(N % 2 == 1);
driver_1(N);
driver_1(N+2);
driver_1(N-2);
return 0;
}
The repeat_char()
and print_line()
functions are unchanged from before. The new function, driver_1()
, contains two loops, one to process the rows with 0, 1, … N-1 leading blanks, and the other to process the rows with N-1, N-2, … 0 leading blanks. The min()
and max()
functions are again static inline
so that their use is unlikely to incur function call overhead. The loop index, i
, controls the number of leading blanks. The expressions for nb
and db
calculate how many blanks and asterisks to output. Those expressions are the same in both loops; the differences are in the direction of counting (up vs down) and the order of the slash character arguments.
This generates the output:
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/ ***** \
/ *** \
/ * \
\ * /
\***/
\*/
/*\
/***\
/ * \
This demonstrates that the functions work with different sizes of output requested.
The final version of the code uses the symmetries of the two loops in driver_1()
and uses a single loop over the range 0
.. 2* N - 1
to generate the correct call to print_line()
. The only changes are in the driver function, renamed to driver_2()
(in part because it was developed in a single executable which also had driver_1()
in it). Again, the repeat_char()
and print_line()
functions are unchanged; and min()
and max()
are reused too.
The loop determines the value corresponding to i
in driver_1()
using the expression (strictly, that's a definition, not an expression, but it contains an expression) int i = min(j, 2*N-1-j);
. The j
term counts up; the 2*N-1-j
term counts down; the value used is the smaller of those two. The test for j == i
allows the correct choice of first and last character.
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static inline int max(int x, int y) { return (x > y) ? x : y; }
static inline int min(int x, int y) { return (x < y) ? x : y; }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
static void driver_2(int N)
{
assert(N % 2 == 1 && N > 0);
for (int j = 0; j < 2*N; j++)
{
int i = min(j, 2*N-1-j);
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
char c1 = (j == i) ? BSLASH : FSLASH;
char c3 = (j == i) ? FSLASH : BSLASH;
print_line(i, c1, 2*nb, '*', db, c3);
}
putchar('\n');
}
int main(void)
{
int N = 5;
assert(N % 2 == 1);
driver_2(N);
driver_2(N+2);
driver_2(N+4);
driver_2(N-2);
driver_2(N-4);
return 0;
}
This generates the output (note the almost degenerate case for N=1):
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/ ***** \
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\ ******* /
\*********/
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/*********\
/ ******* \
/ ***** \
/ *** \
/ * \
\ * /
\***/
\*/
/*\
/***\
/ * \
\*/
/*\
So, there you have it. A complete development cycle in 3 stages. Get something working and demonstrate that it works. Then make the solution more general.
Upvotes: 3
Reputation: 71
There are many ways to achieve this. One of them is the following
void print_pattern(int n) {
int padding=0;
int width=0;
char char_begin='\\', char_end='/';
assert(n>0);
for(int x=0; x<n*2; x++) {
if(padding==n) {
padding--;
char_begin='/';
char_end='\\';
}
width=(n*2)-padding;
for(int y=0;y<=width; y++) {
if(y==padding)
printf("%c",char_begin);
else
if (y==width)
printf("%c",char_end);
else
if (y>padding && y>=n-padding && y<=n+padding)
printf("*");
else
printf(" ");
}
printf("\n");
if(x<n)
padding++;
else
padding--;
}
}
Upvotes: 2