Draw the Stickman Wars

Picture of me drafting this challenge with my advanced drawing skills.

Background

The Stickman wars happened long ago, when Earth's dominant species was made of nothing but sticks. Historians regret the fact that there were no painters or cameras back then, we could use some pictures of that war in today's history books. That's where your coding powers become useful. Stickmen are very easily drawed and Historians managed to find some data about how many stickmen fought the wars¹. Now it's up to you to recreate an image of the moment right before the war began!

Here are the brave stickmen involved in the war:

  O  /
|/|\/
| |
/ \  Swordsman

O A
/|\|
| |
/ \| Spearman

.
.' *.
' O *
' \|/ .
.  |  *
'./ \*. Mage

O
/|\
|
/ \ Villager

O
/|\
/ \ Infant



Input

Receive via stdin or equivalent a representation of every stickman who appeared on each side of the battlefield. For example, if two Swordmen fought on the right side and two spearmen on the left side, your input can be {Sword: 2}, {Spear: 2}, [2,0,0,0,0], [0,2,0,0,0] or a "WW", "SS".

Output

A representation of every brave stickmen in a battle field, according to the rules below. It can be shown on stdout or saved to a file, whatever rocks your boat.

Rules

1. On the left side will be every stickmen of the first array/string/object your program received.
2. Those stickmen must look exactly like the ones shown before on this question.
3. The order of the left side army must be Infants Villagers Mages Swordsmen Spearmen.
4. The right side army will behave just the same, but with the characters and the order mirrored.
5. Each stickman will be separated by 1 space.
6. Each class will be separated by 3 spaces.
7. The armies will be separated by 8 spaces.
8. Since stickmen don't fly, you must draw the ground using hyphen-minuses -.
9. The ground must end on the same column the last stickman of the right army ends.

Example

Let's assume my program expects two arrays with length 5 and each value in the array represents, in order, Infants Villagers Mages Swordsmen Spearmen.

Input: [1,1,2,3,1] [0,0,1,1,1]

               .       .                                                           .
.' *.   .' *.                                                       .* '.
O     ' O *   ' O *      O  /   O  /   O  /    O A        A O   \  O      * O '
O    /|\   ' \|/ . ' \|/ .   |/|\/  |/|\/  |/|\/    /|\|        |/|\   \/|\|   . \|/ '
/|\    |    .  |  * .  |  *   | |    | |    | |       | |        | |      | |   *  |  .
/ \   / \   './ \*. './ \*.    / \    / \    / \     / \|        |/ \    / \    .*/ \'.
---------------------------------------------------------------------------------------


Final Considerations

Please note that standard loopholes apply and that the mage is completely asymmetrical just because.

The result of most upvoted answer will be the "cover image" of this challenge. The shortest answer by the end of the month (08/31/2014) will be selected as the winner.

This is , so the shortest code, in bytes, wins.

¹Citation needed

• "the mage is completely asymmetrical just because" ... twitch... you just had to, didn't you? :P
– Doorknob
Aug 9 '14 at 12:15
• @Doorknob ¯\ _(ツ)_/¯ Aug 9 '14 at 12:26
• Is ok a function with 2 array arguments or you require input parsing from a string? Aug 9 '14 at 15:58
• There's a column missing between the villager and the mage. Also would a representation like IVMMWWWS SWM be within the limit of "anything that helps you"? Aug 9 '14 at 17:33
• I just wanted to say this challenge is awesome and I really appreciate that you made it. Jun 3 '20 at 14:30

JavaScript (E6) 336 344 356 369 424 478 522 570

Edit 6 Last edit was buggy. Bug fix and shortened. That's all I hope.

Edit 5 Finally found a way to get rid of multiply by 23 - bothered me from start. Plus another change to the input (@William shout when it's too much). Now the function expects one array parameter, containing 2 subarrays. Without this change it's 349 - still an improvement

Edit 4 Shaved some more bytes and a little change to input format. With the new input format a missing class is represented as an empty array element. So D([1,,2,3,1],[,3,1,1,2]) instead of D([1,0,2,3,1],[0,3,1,1,2]). I think it still obeys the rules.

Edit 3 Golfed more. No changes to the algorithm, but abusing a lot of array.map and local functions to avoid for loops.

Edit 2 String compression, the right way ...

Edit Added string compression, a lot of work and not much gained. Now the mirror stickmen are generated from a template, not stored.

Made a few tries, first running. To be golfed. NB Kolmogorow-business still to be tackled.

Test In FireFox console. Change 'return' with Add 'alert(...)' to have an output statement (albeit not useful at all)

console.log(D([[1,,2,3,1],[,3,1,1,2]]))

Output

         .       .                                                                 .
.' *.   .' *.                                                             .* '.
' O *   ' O *      O  /   O  /   O  /    O A        A O  A O    \  O      * O '     O   O   O
O    ' \|/ . ' \|/ .   |/|\/  |/|\/  |/|\/    /|\|        |/|\ |/|\    \/|\|   . \|/ '   /|\ /|\ /|\
/|\   .  |  * .  |  *   | |    | |    | |       | |        | |  | |       | |   *  |  .    |   |   |
/ \   './ \*. './ \*.    / \    / \    / \     / \|        |/ \ |/ \     / \    .*/ \.'   / \ / \ / \
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯


Golfed Code

D=a=>
(J=v=>v.join(''))((l=[r=n=' ',3,6,13,19,23]).map(_=>f=(F=f=>J(a[f].map((c,q)=>
("9.299.' *.87O2' O *3O21 O A O 1|0' 0|1 .|1|01 1|0|1|0 | .2|2*| |4| |1 01 0'.1 0*. 1 021 0|"[R='replace'](/[2-9]/g,x=>n.repeat(x))
.slice(l[q]-r,l[q+1]-r)[R](/\d/g,x=>'\\/'[x^f])+n).repeat(c)+n+n
))+n)(0)+J([...F(1)].reverse(r-=23))+'\n'))+f[R](/./g,'¯')


Code (edit 2)

D=(a,b)=>{
F=(s,f)=>(s=s[R](/\d/g,x=>'/\\'[x^f]),f?s:[...s].reverse().join('')),
v="9.299.' *.87O2' O *3O21 O A O 1|0' 0|1 .|1|01 1|0|1|0 | .2|2*| |4| |1 01 0'.1 0*. 1 021 0|"
[R='replace'](/\d/g,x=>x>1?' '.repeat(x):x),
l=[0,3,6,13,19,23];
for(o='',r=0;v[r];r+=23,f=F(z,1)+'  '+F(w,0),o+=f+'\n',f=f[R](/./g,'¯'))
for(z=w=p='';p<10;++p)
if(c=(p<5?a:b)[q=p%5])x=(v.slice(r+l[q],r+l[q+1])+' ').repeat(c)+'  ',p<5?z+=x:w+=x
return o+f
}


Ungolfed code (1st version)

D=(a,b)=>{
v="         .                .                    .' *.            .* '.               O  ' O *   O  / O A * O ' \\  O  A O  O /|\\' \\|/ .|/|\\/ /|\\|. \\|/ ' \\/|\\||/|\\/|\\ | .  |  *| |    | |*  |  .   | || | / \\/ \\'./ \\*. / \\  / \\|.*/ \\'.  / \\ |/ \\"
l=[0,3,6,13,19,23,30,36,40]
o=''
for(r=0;r<6;++r)
{
z=w=''
for(p=0;p<10;p++)
{
c=a[p]||b[p-5];
if (c)
{
q = p<7 ? p%5 : p-2
x = (v.slice(r*40+l[q],r*40+l[q+1])+' ').repeat(c)
if (p<5)
z+=x+'  ';
else
w=x+'  '+w
}
}
f = z + '     ' + w
o += f + '\n'
f = '¯'.repeat(f.length-3)
}
return o+f
}


Python 362 353

Edit: Removing one for-loop and using the exec statement saved 9 bytes

z,x,t,j=" ",input(),str.replace,0
w=0,3,6,13,19,23
a=9*z+"."+20*z+".' *."+15*z+"o  ' o *   o  a o A o a|b' b|a .|a|ba a|b|a|b | .  |  *| |    | |a ba b'.a b*. a b  a b|"
exec"b=''\nfor c in 0,1:b+=z*8*c+t(t('   '.join([z.join([a[w[k]+j:w[k+1]+j]]*v)for k,v in enumerate(x[c])if v])[::1-2*c],'a','\/'[c<1]),'b','\/'[c])\nprint b;j+=23;"*6
print'-'*len(b)


Input:

[0,0,2,1,1],[1,0,2,1,2]


Output:

   .       .                                                   .       .
.' *.   .' *.                                               .* '.   .* '.
' o *   ' o *      o  /    o A        A o  A o    \  o      * o '   * o '
' \|/ . ' \|/ .   |/|\/    /|\|        |/|\ |/|\    \/|\|   . \|/ ' . \|/ '    o
.  |  * .  |  *   | |       | |        | |  | |       | |   *  |  . *  |  .   /|\
'./ \*. './ \*.    / \     / \|        |/ \ |/ \     / \    .*/ \.' .*/ \.'   / \
---------------------------------------------------------------------------------

• Noticed you use lowercase Os. Aug 19 '14 at 17:08

C, 418414 404

−10 bytes thanks to ceilingcat

Example input:

stickwar.exe IVMMWWWS SWM

Example output:


.       .                                                            .
.' *.   .' *.                                                        .* '.
O     ' O *   ' O *      O  /   O  /   O  /    O A        A O    \  O      * O '
O    /|\   ' \|/ . ' \|/ .   |/|\/  |/|\/  |/|\/    /|\|        |/|\    \/|\|   . \|/ '
/|\    |    .  |  * .  |  *   | |    | |    | |       | |        | |       | |   *  |  .
/ \   / \   './ \*. './ \*.    / \    / \    / \     / \|        |/ \     / \    .*/ \'.
----------------------------------------------------------------------------------------


Golfed code:

char*s,d[8][999],*a;p,f,t,x,y,c,l;main(o,g)char**g;{for(memset(d,32,6993);o-=2,a=*++g;p+=3)for(;f=*a;t-4-o||strcpy(d[5]+p-1,"'."),p+=l&-o,f^*++a?p+=2:0)for(t=f%27%5,l=t*3%12%5+4,p+=l&o,y=6,s="(A(21;\0(A2:B(212;F\08A*B*0210KP\0-70A47/RT-A20G=CD?5D7_\0(A:(21;"+"V3'? "[t]-32;c=*s++;d[y][p+o*x]="/\\|O*'A."[c&7])x=c/16-2+(c&8?--y*0:x),c^=o-1&&!(c&6);for(y=!memset(d[6],45,p-=4);*(s=d[y++]);s[p]=0,puts(s));}


Maximal width of the battlefield is 999 (I could save 2 chars by limiting it to 99). I used a control structure of 1 byte per output character (non-space), drawing the figures from the bottom up.

• 1 bit for y-coordinate (either "stay" or "go up")
• 3 bits for x-coordinate displacement (0...4)
• 3 bits for output char (fortunately, there are only 8 different chars)

There are 5 offsets into the control structure.

Some other obscure bits:

• The code f%27%5 translates the characters VWSMI to numbers 0, 1, 2, 3, 4
• The code t*3%12%5+4 calculates the width of the stickman of type t
• The code t^3|~o||(s=d[5]+p,*s--=46,*s=39) accounts for the left/right asymmetry
• I use the fact that argc=3 to generate drawing direction flags 1 and -1

Ungolfed code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char k[] = "(A(21;\0(A2:B(212;F\08A*B*0210KP\0-70A47/RT-A20G=CD?5D7_\0(A:(21;";

char d[8][999], // data of the battlefield
*s, // control string
*a; // cmdline argument
p, // position in the battlefield
f, // figure (char)
t, // type of the figure (0...4)
x,y, // coordinates while drawing the stickman
c; // control char, specifying what to draw

main(o, g) char**g; // o means "orientation" (+1, then -1)
{
freopen("out.txt", "w", stdout);
memset(d, ' ', 6993);

for (; o -= 2, a=*++g;)
{
for (; f=*a;)
{
t = f%27%5;

if (o<0)
p += t*3%12%5+4; // go to the next stickman

y = 6;
for (s=k+"V3'? "[t]-32; c = *s++;) // loop over the control
{
if (c & 8) // bit 3: next line; set x to 0
--y, x = 0;
x += c / 16 - 2; // bits 6...4: x coordinate
if (o == -1 && !(c & 6)) // mirror \ <-> /
c ^= 1;
d[y][p + o * x] = "/\\|O*'A."[c & 7];
}
if (t == 3 && o<0) // fix the asymmetrical mage
{
s=d[5]+p;
*s--='.';
*s='\'';
}

if (o>0)
p += t*3%12%5+4; // go to the next stickman
if (f != *++a) // is next stickman of different type?
p += 2;
}
p += 3; // separate the armies
}

p -= 4;
memset(d[6], '-', p); // draw the ground

for (y = 0; *(s=d[y++]); ) // print the battle field
{
s[p] = 0;
puts(s);
}
}

• Why are you able to not have the includes in the golfed version? Also why not change the semi-colon after *a to a comma? That gets rid of a warning and has the same number of bytes.
– Fsmv
Aug 19 '14 at 15:11
• C has the "implicit declaration" rule; it's unsafe to rely on it but it works in practice so it's pretty standard in golfing. As for the semi-colon: I use the expression f=*a as the stopping condition; compiler may complain but I mean it. I cannot remove it because there should be two semicolons in the for-loop syntax. Aug 19 '14 at 15:19
• 402 bytes Jun 7 '20 at 19:08

Input Format

([1,1,2,3,1],[0,1,1,0,1])


Order: [Infant, Villager, Mage, Swordsman, Spearman], [Spearman, Swordsman, Mage, Villager, Infant]

Sample Output

               .        .                                                       .
.' *.    .' *.                                                   .* '.
O     ' O *    ' O *       O  /   O  /   O  /    O A        \  O       * O '
O    /|\   ' \|/ .  ' \|/ .    |/|\/  |/|\/  |/|\/    /|\|         \/|\|    . \|/ '    O
/|\    |    .  |  *  .  |  *    | |    | |    | |       | |           | |    *  |  .   /|\
/ \   / \   './ \*.  './ \*.     / \    / \    / \     / \|          / \     .*/ \.'   / \
------------------------------------------------------------------------------------------


Code

(?)=replicate
v=reverse
g=map
e=length
s=foldr1
p=zip[3,3,8,6,4]$g lines[" O\n/|\\\n/ \\"," O\n/|\\\n |\n/ \\"," . \n .' *.\n ' O * \n' \\|/ .\n. | *\n'./ \\*."," O /\n|/|\\/\n| |\n / \\"," O A\n/|\\|\n | |\n/ \\|"] r n x a=a++(n-e a)?x x '\\'='/';x '/'='\\';x c=c y(w,p)=(w,g(v.dropWhile(==' ').g x.r w ' ')p) m n(a,p)(b,q)=(a+b+n,[r(a+n)' ' c++d|(c,d)<-zip(h p)(h q)])where h=v.r(max(e p)(e q))[].v p%c|sum c==0=(0,[])|1<2=s(m 3)[s(m 1)$d?(p!!i)|(i,d)<-zip[0..]c,d>0]
f(w,p)=p++[w?'-']
main=interact((\(a,b)->unlines.f$m 8(p%a)((g y.v$p)%b)).read)


Ungolfed

type Pic = (Int, [String])

pics :: [Pic]
pics = zip[3,3,8,6,4]$map lines[" O\n/|\\\n/ \\"," O\n/|\\\n |\n/ \\"," . \n .' *.\n ' O * \n' \\|/ .\n. | *\n'./ \\*."," O /\n|/|\\/\n| |\n / \\"," O A\n/|\\|\n | |\n/ \\|"] mirrorChar '\\' = '/' mirrorChar '/' = '\\' mirrorChar c = c padL, padR :: Int -> a -> [a] -> [a] padL n x a = replicate (n - length a) x ++ a padR n x a = a ++ replicate (n - length a) x mirrorPic :: Pic -> Pic mirrorPic (w, pic) = (w, map (reverse . dropWhile (==' ') . map mirrorChar . padR w ' ') pic) merge n (w1, pic1) (w2, pic2) = let h = max (length pic1) (length pic2) in (w1 + n + w2, [padR (w1 + n) ' ' line1 ++ line2 | (line1, line2) <- zip (padL h [] pic1) (padL h [] pic2)]) makeArmy :: [Pic] -> [Int] -> Pic makeArmy pics counts | sum counts == 0 = (0, []) | otherwise = foldr1 (merge 3) [ foldr1 (merge 1) . replicate count$ pics !! i | (i, count) <- zip [0..] counts, count > 0]

addField :: Pic -> [String]
addField (w, pic) = pic ++ [replicate w '-']

main = do
(counts1, counts2)<- return . read =<< getLine
putStr . unlines . addField $merge 8 (makeArmy pics counts1) (makeArmy (map mirrorPic . reverse$ pics) counts2)

• I didn't test, but according to your sample output you forgot to mirror the characters on the right side Aug 9 '14 at 23:22
• @WilliamBarbosa Fixed with a totally different solution.
– Ray
Aug 10 '14 at 21:11

Haskell (736733 720 Bytes)

import System.Environment
import Data.List
a=1<2
h="   "
n="      "
o="    "
b (x:y)|x<0=[]|a=x:(b y)
c (x:y)|x>=0=c y|a=y
d [] _=[]
d (x:y)z|z/=x=[-5,x]++(d y x)|a=[x]++(d y x)
e x y|x< -5="        "|x<0=h|a=(([[h,h,"   .   ",n,o],[h,h," .' *. ",n,o],[h," o "," ' O * ","  O  /"," O A"],[" o ","/|\\", "' \\|/ .","|/|\\/ ","/|\\|"],["/|\\"," | ",".  |  *","| |   "," | |"],["/ \\","/ \\","'./ \\*."," / \\  ","/ \\|"]]!!(div z 5))!!(mod z 5))++" "where z=5*y+x
(§)=map
g=putStrLn
m=concat
main=do
z<-getArgs
let w=sort(b y)
let v=reverse(sort(c y))
let u=(\(t,i)->(\s->e s i)§t)§(zip(take 6(cycle[((d w (w!!0))++[-9]++(d v (v!!0)))]))[0..5])
mapM(\x->g(m x))u
g(replicate(length(m(u!!0)))'-')


Call with ./stickmanwars 2 3 1 3 4 -1 3 2 4 1 0 4 2 1. The -1 marks the delimiter for the two arrays. I hope that is okay.

Well, my first code golf challenge and the first time I've used haskell for a real application after I learned it this semester at my university. Probably not even close to being the best or shortest solution but I had fun creating it and it was a good exercise :) Critique and feedback is highly appreciated.

Golfed it out of this:

import System.Environment
import Data.List

layers = [
["   ", "   ",  "   .   ",  "      ",  "    "],
["   ", "   ",  " .' *. ",  "      ",  "    "],
["   ", " o ",  " ' O * ",  "  O  /",  " O A"],
[" o ", "/|\\", "' \\|/ .", "|/|\\/ ", "/|\\|"],
["/|\\"," | ",  ".  |  *",  "| |   "," | |"],
["/ \\","/ \\", "'./ \\*.", " / \\  ","/ \\|"],
["¯¯¯", "¯¯¯",  "¯¯¯¯¯¯¯",  "¯¯¯¯¯¯", "¯¯¯¯"]]

getLeftSide :: [Int] -> [Int]
getLeftSide (x:xs) | x < 0 = []
| otherwise = x : (getLeftSide xs)

getRightSide :: [Int] -> [Int]
getRightSide (x:xs) | x >= 0 = getRightSide xs
| otherwise = xs

addSpacing :: [Int] -> Int -> [Int]
addSpacing [] _ = []
addSpacing (x:xs) old | old /= x = [(-50),x] ++ (addSpacing xs x)
| otherwise = [x] ++ (addSpacing xs x)

getLayerStr :: Int -> Int -> String
getLayerStr item dimension | item < (-50) = "        "
getLayerStr item dimension | item < 0  = "   "
| otherwise = ((layers !! i) !! j) ++ " "
where
value = (item + (5 * dimension))
i = div value 5
j = mod value 5

main = do
-- Read Arguments from command line
a <- getArgs
-- Convert command line arguments to Int array
let args = map read a :: [Int]
-- Get left side of the array and sort it
let frstArray = sort $getLeftSide args -- Get right side of the array and sort it mirrored let scndArray = reverse$ sort $getRightSide args -- Concat the two sides and put a delimiter in between them let finalArray = (addSpacing frstArray (frstArray !! 0)) ++ [-99] ++ (addSpacing scndArray (scndArray !! 0)) -- Create the matrix by -- 1. Duplicating the final array 6 times (one for each level) -- 2. Pair each of those 6 arrays with its level (= index) -- 3. Create a matrix like below: -- -- 1 1 2 2 3 4 4 5 - 1 1 2 2 2 4 -- 6 6 7 7 8 9 9 10 - 6 6 7 7 7 9 -- 11 11 12 12 13 14 14 15 - 11 11 12 12 12 14 -- 16 16 17 17 18 19 19 20 - 16 16 17 17 17 19 -- 21 21 22 22 23 24 24 25 - 21 21 22 22 22 24 -- 26 26 27 27 28 29 29 20 - 26 26 27 27 27 29 -- -- 4. Convert the newly calculated indices to their respective strings let matrix = map (\(list,i) -> map (\item -> getLayerStr item i) list) (zip (take 6$ cycle [finalArray]) [0..5])
-- Finaly output the matrix by concating the elements ...
mapM (\x -> putStrLn (concat x)) matrix
-- ... and print the ground level.
putStrLn (replicate (length $concat$ matrix !! 0) '¯')
-- Exit with a new line
putStrLn ""

• Spaces around parentheses is not necessary. That seems to save you a lot.
– Ray
Aug 9 '14 at 21:35
• ah okay, saved me 3 bytes, thx :) Aug 10 '14 at 1:19
• No, a lot more.
– Ray
Aug 10 '14 at 3:50
• you are right, I got a lot more just now. Aug 10 '14 at 4:08

05AB1E, 120 bytes

εU•1ĆÊLî˜₅ÉÈ«-—gí"Mª§ÚÇGäÒ²ĀÛNYE™Eæ]Ç€Š–ôTú™<C₄+i*∍.[½P•"
|/\.O*'0A"ÅвJ0¡ε.B€S¸XNèиJøðý€S}õζJð3×ýNiεº2äθðÜ]øð8×ý¤'-s∍ª»


Input is similar as in the example, except it's paired together (i.e. [[1,1,2,3,1],[0,0,1,1,1]]).

Try it online.

Explanation:

ε                 # Map both inner lists of the (implicit) input to:
U                #  Pop and store the list in variable X
•1ĆÊLî˜₅ÉÈ«-—gí"Mª§ÚÇGäÒ²ĀÛNYE™Eæ]Ç€Š–ôTú™<C₄+i*∍.[½P•
"#  Push compressed integer 842496640498468305486897242730433696271358810529289612091214532817389449608887173562606281130145674459118763657187307135640
"
|/\.O*'0A"        #  Push string " \n|/\.O*'0A"
Åв      #  Convert the integer to this custom base-" \n|/\.O*'0A",
#  (short for converting it to base-length and indexing each into the string)
J     #  Join this list of characters together to a single string
0¡   #  And split it on "0"s


We now have a list of stick figures. I've generated the stick figures string with this program, which is a slightly modified version of this 05AB1E tip.

 ε                #  Map each stick figure to:
.B              #   Box it (split on newlines, and append spaces to make all lines of equal length)
€S            #   Convert each line to a list of characters
¸           #   Wrap the entire thing into a list
X          #   Push input-sublist X
Nè        #   Index the map-index into it
и       #   Repeat the stick figure that many times as list
J      #   Join each innermost list of characters together to a string
ø     #   Zip/transpose; swapping rows/columns
ðý   #   Join each line with a single space delimiter
€S #   And convert each line back to a character list again
}                #  After the inner map:
ζ              #  Zip/transpose the list of stick figures,
õ               #  with an empty string as filler (in case the input contained a 0)
J             #  Join each inner list together to a string
ð3×ý         #  Join each line with 3 spaces as delimiter
Ni               #  If the map-index is 1 (thus the left army):
ε              #   Map each line to:
º             #    Mirror-reflect the line
2ä           #    Split it into 2 equal-sized parts
θ          #    Pop and only leave the last (mirrored) part
ðÜ        #    Remove any trailing spaces
#    (necessary if the amount of infants in the left army is 0)
]                 # Close all maps and if-statements
ø                # Zip/transpose; swapping rows/columns
ð8×ý            # Join each line together with 8 spaces as delimiter
¤           # Push the last line (without popping the list itself)
'-        '# Push string "-"
s        # Swap so the last line is at the top of the stack
∍       # Extend the "-" to a length equal to that line
ª      # Append it to the list
»     # And join the lines by newlines
# (after which the result is output implicitly)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why •1ĆÊLî˜₅ÉÈ«-—gí"Mª§ÚÇGäÒ²ĀÛNYE™Eæ]Ç€Š–ôTú™<C₄+i*∍.[½P• is 842496640498468305486897242730433696271358810529289612091214532817389449608887173562606281130145674459118763657187307135640.

import Data.List
s=["      -"]
c=["    //-":"   O| -":"    \\\\-":s,"   / /-":"  O|| -":"   \\ \\-":s,"   '.'-":" .'  .-":" ' \\ /-":". O|| -":" * / \\-":" .*  *-":"   .*.-":s,"   || -":"   / /-":"  O|| -":"   \\ \\-":"   /  -":"  /   -":s,"   / /-":"  O|| -":"   \\ \\-":"  A|||-":s]
m '\\'='/'
m '/'='\\'
m x=x
u[]=[]
u x=x++[s,s]
f x=zipWith replicate x c>>=concat.u
k(a,b)=unlines.transpose$f a++s++s++map(map$m)(reverse$f b) main=interact$k.read


Cool challenge! I might be able to golf that down a bit more. Basically I'm storing the figures column wise so I can append them to each other easily, and then flip the whole array of Strings arround using Haskell's transpose.

The input format is ([Infants,Villagers,Mages,Swordsmen,Spearmen],[Infants,Villagers,Mages,Swordsmen,Spearmen])

Here is the example from the OP:

>>>echo ([1,1,2,3,1],[0,0,1,1,1]) | cg2
.       .                                                            .
.' *.   .' *.                                                        .* '.
O     ' O *   ' O *      O  /   O  /   O  /    O A        A O    \  O      * O '
O    /|\   ' \|/ . ' \|/ .   |/|\/  |/|\/  |/|\/    /|\|        |/|\    \/|\|   . \|/ '
/|\    |    .  |  * .  |  *   | |    | |    | |       | |        | |       | |   *  |  .
/ \   / \   './ \*. './ \*.    / \    / \    / \     / \|        |/ \     / \    .*/ \.'
----------------------------------------------------------------------------------------


And here is my favourite depiction of the infamous ritual infanticide during the second era!

>>>echo ([0,0,0,1,0],[5,0,0,0,0]) | cg2

O  /
|/|\/          O   O   O   O   O
| |           /|\ /|\ /|\ /|\ /|\
/ \          / \ / \ / \ / \ / \
---------------------------------


Python (612,522,460,440)

• Rev1: Rudimentary compression and base64-encoding
• Rev2: Removed compression/encoding; got smaller
• Rev3: More byte count reduction by inlining
• Rev4: Removed unneeded input reversal on 2nd army; swapped swordsman and spearman to match spec

Each "line" is trimmed of right-padding, and this is added back in when reconstructing.

I pre-reversed the stickmen in my internal encoding because it saved me having to reverse them individually when rendering them in the code.

Sample run:

$echo "[1,1,2,3,1],[0,0,1,1,1]"|python /tmp/g2.py . . . .' *. .' *. .* '. O ' O * ' O * O / O / O / O A A O \ O * O ' O /|\ ' \|/ . ' \|/ . |/|\/ |/|\/ |/|\/ /|\| |/|\ \/|\| . \|/ ' /|\ | . | * . | * | | | | | | | | | | | | * | . / \ / \ './ \*. './ \*. / \ / \ / \ / \| |/ \ / \ .*/ \.' ----------------------------------------------------------------------------------------  Code: c=",,A O,|/|\\,| |,|/ \\,,,\\ O, \\/|\\|, | |, / \\, . , .* '., * O ',. \\|/ ',* | .,.*/ \\.',,, O,/|\\, |,/ \\,,,, O,/|\\,/ \\".split(',') r=['']*6 for b in input(): for e,f in '/$ \\/ $\\'.split():r=[x.replace(e,f)[::-1] for x in r] if r[0]:r=[x+' ' for x in r] for n,a in enumerate(b[::-1]): m=c[n*6:n*6+6] if a:r=[x+' '+(' '.join([y.ljust(max(map(len,m)))]*a)) for x,y in zip(r,m)] print '\n'.join(r+['-'*len(r[0])])  Python (476) A different solver from my previous one; longer, but more functional. $ echo "[1,1,2,3,1],[0,0,1,1,1]"|python g3.py
.       .                                                            .
.' *.   .' *.                                                        .* '.
O     ' O *   ' O *      O  /   O  /   O  /    O A        A O    \  O      * O '
O    /|\   ' \|/ . ' \|/ .   |/|\/  |/|\/  |/|\/    /|\|        |/|\    \/|\|   . \|/ '
/|\    |    .  |  * .  |  *   | |    | |    | |       | |        | |       | |   *  |  .
/ \   / \   './ \*. './ \*.    / \    / \    / \     / \|        |/ \     / \    .*/ \.'
----------------------------------------------------------------------------------------


Code:

c=",,A O,|L|R,| |,|L R,,,R  O, RL|R|,   | |,  L R,   .  , .* '., * O ',. R|L ',*  |  .,.*L R.',,, O,L|R, |,L R,,,, O,L|R,L R".split(',')+['']*12
s=[sum([[4-n,5]*a+[6] for n,a in enumerate(b) if a]+[[5]],[])[::-1] for b in input()]
t=[[''.join([c[a*6+n].ljust([4,6,7,3,3,1,2][a]) for a in x]) for x in s] for n in range(0,6)]
for d,e,f in 'RL/ LR\\'.split():t=[[x[0].replace(d,f),x[1].replace(e,f)] for x in t]
t=[x[0][::-1]+x[1] for x in t]
print '\n'.join(t+['-'*len(t[0])])