making an arrow

Write your question here.
I have been working on this all day and can not figure it out.
I need to get the end of the arrow shaft to make a point and my arrowhead
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[code] #include<iostream>
using namespace std;
int main()
{
	int L, W;
	cout << "What is the Length and Width of the arrow shaft?" << endl;
	cin >> L >> W;
	int O, I;
	cout << "what is the inner length and outer length of the arrow feathers?" << endl;
	cin >> I >> O;
	int X;
	cout << "what is the width of the arrowhead?" << endl;
	cin >> X;
	
	// top level
	for (int i = I; i <= O; ++i)
	{
		for (int j = 0; j < i; ++j)
		{
			cout << "* ";
			
		}
		for (int i = 0; i <= L-1; ++i)
		{
		cout << "  ";
		}
		for (int a = 1; a <= X; ++a)
		{
			for (int j = 1; j < a; ++j)
			{
				cout << "* ";
			}
		}
		cout << endl;
	}
	
	for (int i = 1; i <= W; ++i)
	{
		for (int j = 0; j < L + O + X; ++j)
		{
			cout << "+ ";
		}
		cout << endl;
		for (int i = O; i <= I; ++i)
		{
			for (int j = 0; j < i; ++j)
			{
				cout << "* ";
			}
			cout << endl;
		}
	}
}

the user input is:
shaft:10L/3W
feather:3I/7O
arrowhead:4X


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

It needs to look like this:

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

Last edited on
your problem is lack of information.
what if the feathers were shorter than the head?
important: what do you want to do if the shaft is even width?
important: what if the shaft width is 21 and the head is only 7 lines high?
are there other oddball inputs that need to be handled?

you have to figure out what the top row is made of (it could be feathers, or head, or shaft, or any combination of those). that is your baseline, and from there you need to know when to start adding in each of the parts that were not part of the first line.
here, the first line is only feathers. the head starts on the second row, the shaft on the 6th row.

you also need to know what column the head starts on.

if you figure all that out up front, the looping becomes much clearer.
also you need a consistent way to talk about the parts. I recommend just talking about them in terms of their screen width and screen height (regardless of how the user gives the info to you, convert it all to the same terms, it will be easier to craft code if its all in the same format).

once you do all that, the easy way to write it is something like this:

if(topmost == feathers)
for(feathers = 0; feathers < total feather height which includes the shaft; feathers++)
{
if(drawing shaft) //cout a row of *s adjusted for head
else if(drawing feathers and head)
{
loop to draw feathers up to current count
loop to draw spaces until spaces+feathers == column to start drawing head
loop to draw head up to current count
cout endl.
}
else loop to draw feathers and end of line.

else if (topmost == head)
// as above, same idea, but now you draw head until you hit feathers and/or shaft...

}

you need to track how many lines you have written so far so you can turn on things like "drawing shaft" and "drawing head" etc ideas above.
in your example, then... the
feathers is topmost item.
draw feathers... 1 line written.
when to start head? its line 1 (from 0). so drawing feathers and head both are now true conditions.
draw second line, which is feathers and head. is the row count right for shaft? no...
draw third line, which is feathers and head....
and so on. you get to the shaft and it just draws across since any feathering and head stuff is accounted for, mostly. you do need to know what line you are on, and the head dimensions, so you can extend the shaft to make the point as necessary for the head....

this is complex. if you make some assumptions (feathers first, head second, shaft third) about the input you can reduce some of the testing and juggling, and you may want to start there, get that working, then if needed add the conditions to handle the other cases.... even so, you still need to do the first things I said about getting it in common terms and precomputing enough info to draw the thing.

Which brings up the final point... you likely need to scrap what you have. It looks like "code first, think later" instead of "design first, code second" and I don't think it can be fixed or saved.
Thank you so much for your help I will definitely try to take everything you said into consideration when making my new code.
Putting this here for help/posterity.
I inverted the meaning of feather-inner and feather-outer from OPs description. I took inner to mean "closest to the shaft".
I create an arrow with random values for the different arrow dimensions. Instead of using asterisks everywhere, I use a different letter to form each of the component parts I constructed independently:
f = feather
a = arrowhead
s = shaft
m = midline of shaft
I hope this makes it easier to find in the code where each part is being printed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>

void PrintCharHowManyTimes(char c, int times)
{
    for (int i = 1; i <= times; i++) { std::cout << c; }
}

struct ArrowDescription
{
    int shaftLength;
    int shaftWidth;
    int featherInner;
    int featherOuter;
    int arrowhead;

    enum ArrowSide { TOP, BOTTOM };
    void printBeyondShaft(ArrowSide side);
    void printHalfOfShaft(ArrowSide side);
    void printShaftMidline();
    void Print();
};

void ArrowDescription::Print()
{
    std::cout << "Shaft length   : " << shaftLength << '\n';
    std::cout << "Shaft width    : " << shaftWidth << '\n';
    std::cout << "Feather (inner): " << featherInner << '\n';
    std::cout << "Feather (outer): " << featherOuter << '\n';
    std::cout << "Arrowhead      : " << arrowhead << '\n';

    printBeyondShaft(ArrowSide::TOP);
    printHalfOfShaft(ArrowSide::TOP);
    printShaftMidline();
    printHalfOfShaft(ArrowSide::BOTTOM);
    printBeyondShaft(ArrowSide::BOTTOM);
}

void ArrowDescription::printBeyondShaft(ArrowSide side)
{
    //get height of arrow - this is dictated by whether the feather
    //or the arrowhead extends highest
    int featherHeight = featherInner - featherOuter + 1;
    int maxHeightFromShaft = std::max(featherHeight, arrowhead);

    //create the loop variables based on whether we're drawing the
    //top side or bottom side of the arrow
    int start, stop, step;
    if (side == TOP)
    {
        start = maxHeightFromShaft;
        stop = 0;
        step = -1;
    }
    else if (side == BOTTOM)
    {
        start = 1;
        stop = maxHeightFromShaft + 1;
        step = 1;
    }

    //draw everything from the farthest-reaching end of the feather or
    //arrowhead to the edge of the shaft.
    for (int currHeight = start; currHeight != stop; currHeight += step)
    {
        int numFeatherChars = 0;
        int numSpaceChars = 0;

        //determine feather part
        if (currHeight > featherHeight)
        {
            //if we don't have any feather aspect this far away
            //from the shaft, just print spaces for the whole width
            //of the feather
            numSpaceChars = featherInner;
        }
        else
        {
            numFeatherChars = featherOuter;
            numFeatherChars += (featherHeight - currHeight);
            numSpaceChars = featherInner - numFeatherChars;
        }

        //determine space between the feather and arrowhead
        numSpaceChars += shaftLength;

        //determine arrowhead part
        int numArrowheadChars = 0;
        if (currHeight <= arrowhead)
        {
            numArrowheadChars = arrowhead - currHeight + 1;
        }

        //print feather part
        PrintCharHowManyTimes('f', numFeatherChars);
        PrintCharHowManyTimes(' ', numSpaceChars);

        //print arrowhead part
        PrintCharHowManyTimes('a', numArrowheadChars);

        std::cout << '\n';
    }
}

void ArrowDescription::printHalfOfShaft(ArrowSide side)
{
    //create the loop variables based on whether we're drawing the
    //top side or bottom side of the arrow
    int start, stop, step;
    if (side == TOP)
    {
        start = 1;
        stop = (shaftWidth / 2) + 1;
        step = 1;
    }
    else if (side == BOTTOM)
    {
        start = shaftWidth / 2;
        stop = 0;
        step = -1;
    }

    //draw the top or bottom half of the arrow shaft from tip to tip
    for (int i = start; i != stop; i += step)
    {
        //shaft to arrowhead border
        int numShaftBaseChars = featherInner + shaftLength + arrowhead;
        PrintCharHowManyTimes('s', numShaftBaseChars);

        //shaft point
        int numShaftPointChars = i;
        PrintCharHowManyTimes('p', numShaftPointChars);

        std::cout << '\n';
    }
}

void ArrowDescription::printShaftMidline()
{
    //print midline of shaft if necessary
    if (shaftWidth % 2 == 1)
    {
        int fullLength = featherInner + shaftLength + arrowhead + (shaftWidth / 2) + 1;
        PrintCharHowManyTimes('m', fullLength);
        std::cout << '\n';
    }
}

int main()
{
    std::srand(std::time(nullptr));

    ArrowDescription arrow;
    // pick random values between 1 and 10 for each dimension
    arrow.shaftLength = (std::rand() % 10) + 1;
    arrow.shaftWidth = (std::rand() % 10) + 1;
    arrow.featherInner = (std::rand() % 10) + 1;
    arrow.featherOuter = (std::rand() % 10) + 1;
    arrow.arrowhead = (std::rand() % 10) + 1;

    // make sure the feather width closer to the shaft
    // is larger than the feather width away from the shaft
    if (arrow.featherInner < arrow.featherOuter)
    {
        std::swap(arrow.featherInner, arrow.featherOuter);
    }

    arrow.Print();

    return 0;
}
Easily but not 'parametrised', primitive shapes and symmetry are another way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>

int WIDTH{0}, HEIGHT{0};;
char **SCREEN = nullptr;

void set_screen(int w, int h)
{
    SCREEN = new char*[h];
    for(int i = 0; i < h; ++i)
    {
        SCREEN[i] = new char[w];
    }
    
    for(int row = 0; row < HEIGHT; row++)
    {
        for(int col = 0; col < WIDTH; col++)
        {
            SCREEN[row][col] = ' ';
        }
    }
    
}

void display_screen()
{
    for(int row = 0; row < HEIGHT; row++)
    {
        for(int col = 0; col < WIDTH; col++)
        {
            std::cout << SCREEN[row][col];
        }
        std::cout << '\n';
    }
}

void rectangle(int x, int y, int width, int height)
{
    for(int row = 0; row < height; row++)
    {
        for(int col = 0; col < width; col++)
        {
            SCREEN[y + row][x + col] = 's';
        }
    }
}

void triangle(int x, int y, int height)
{
    for(int row = 0; row < height; row++)
    {
        for(int col = 0; col < row; col++)
        {
            SCREEN[y + row][x + col] = 't';
        }
    }
}

void symmetry()
{
    for(int row = 0; row < HEIGHT/2; row++)
    {
        for(int col = 0; col < WIDTH; col++)
        {
            SCREEN[HEIGHT - row - 1][col] = SCREEN[row][col];
        }
    }
}



int main()
{
    // SCREEN
    int x{0}, y{7}, w{22}, h{3};
    WIDTH = w + 1; HEIGHT = 2*y + h;
    set_screen(WIDTH,HEIGHT);
    
    // SHAFT
    rectangle(x, y, w, h);
    
    // FEATHER
    for(int i = 0; i < 3; i++)
    {
        triangle(i, 0, 7);
    }
    
    // POINT
    triangle(w-6, 1, 8);
    symmetry();
    
    display_screen();
    return 0;
}



ttt                    
tttt            t      
ttttt           tt     
tttttt          ttt    
ttttttt         tttt   
tttttttt        ttttt  
sssssssssssssssstttttt 
ssssssssssssssssttttttt
sssssssssssssssstttttt 
tttttttt        ttttt  
ttttttt         tttt   
tttttt          ttt    
ttttt           tt     
tttt            t      
ttt           
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

class Drawing
{
   vector<string> canvas;
   int ROWS, COLS;

public:
   Drawing( int r, int c ) : ROWS( r ), COLS( c ) { canvas = vector<string>( r, string( c, ' ' ) ); }
   void print() { for ( string s : canvas ) cout << s << '\n'; }

   void rectangle( int i0, int j0, int ni, int nj, char c  )
   {
      for ( int i = max( i0, 0); i < min( i0 + ni, ROWS ); i++ )
      {
         for ( int j = max( j0, 0 ); j < min( j0 + nj, COLS ); j++ ) canvas[i][j] = c;
      }
   }

   void lookRight( int i0, int j0, int right, char c  )
   {
      for ( int j = j0, i1 = i0 - right + 1, i2 = i0 + right - 1; j < j0 + right; j++, i1++, i2-- )
      {
         for ( int i = i1; i <= i2; i++ )
         {
            if ( i >= 0 && i < ROWS && j >= 0 && j < COLS ) canvas[i][j] = c;
         }
      }
   }
};


void arrow( int L, int W, int I, int O, int X, char c )        // W must be odd
{
   int rref = max( X, I - O + 1 );
   int mid = rref + ( W - 1 ) / 2;
   int height = W + 2 * rref;
   int width  = I + L + X + ( W + 1 ) / 2;
   Drawing drawing( height, width );
   // Feathers
   drawing.rectangle( rref - ( I - O + 1 ), 0, W + 2 * ( I - O + 1 ), O, c );
   drawing.lookRight( mid, O, I - O + ( W + 1 ) / 2, c );
   // Shaft
   drawing.rectangle( rref, I, W, L, c );
   // Head
   drawing.lookRight( mid, I + L, X + ( W + 1 ) / 2, c );
   drawing.print();
}

int main()
{
   arrow( 10, 3, 7, 3, 4, '*' );
}


***                    
****             *     
*****            **    
******           ***   
*******          ****  
********************** 
***********************
********************** 
*******          ****  
******           ***   
*****            **    
****             *     
***                    
Last edited on
Now that we're on a roll the next challenge is to rotate the arrow in any direction about the z-axis, perhaps by encapsulating the arrow and rotating it about its C of G
:).

Even better show it being fired (hence the initial angle) from a bow and follow the trajectory ie translation as well as rotation
That's the least aerodynamic arrow I've ever seen, @againtry! It would be lucky if it made it across the lecture theatre.
Reminds me of seeing this some time ago:
https://www.youtube.com/watch?v=3BNg4fDJC8A
Topic archived. No new replies allowed.