C#, 118 bytes
n=>string.Join('\n',new int[3].Select((_,i)=>new string('#',n)+(n%2==i%2?"#"+new string('x',n).Replace("x"," -"):"")))
-5 bytes thanks to Stone_Red from The Programmers Hangout discord
Curse you C# and your verbose string repeating shakes fist
Try it on .NETFiddle
Explanation
n
is the size of the spaceship, i
is the 0-indexed current line being generated.
Select
is C#'s version of a map
function. When the provided predicate takes 2 arguments, the first will be the original value in the collection being enumerated, and the second will be the index of that value in the collection.
In our case we don't care about the original value, we're just using it as a shorter for(int i = 0; i < 3; i++)
. Likewise we don't care about the original type, because Select
will return a collection of whatever type the provided predicate function returns. In this case the predicate function returns a string, so Select
will return an IEnumerable<string>
regardless of the fact that it's enumerating over an int[]
. int
was chosen as it's the shortest standard type name in .NET.
Every line of output begins with new string('#',n)
, which is C#'s way to repeat a char n
times. Then the following ternary statement handles generating guns:
(n%2==i%2?"#"+new string('x',n).Replace("x"," -"):"")
The condition here is n%2==i%2
, which is true if the parity of the size and line number match. If n
's parity matches i
's parity, it's a gun line (even values for n
will have a gun on line 0 and 2, odd values will have a gun on line 1).
Guns have one extra #
, so we start with "#"+
.
new string('x',n).Replace("x"," -")
generates a string of n
x
characters, then replaces each x
with -
, this is the golfiest way I know of to repeat a string n
times, as the new string('#',n)
method only works for repeating a single char.
Finally the IEnumerable<string>
returned from Select
is passed to string.Join('\n',...)
, which simply concatenates the collection into a single string, with newlines between each line.