text:
Not Your Routine Bean Machine
Consider this ASCII version of a mechanism similar to a bean machine or plinko/pachinko game:
    O

    ^
   \ ^
  ^ ^ \
 \ ^ / ^
U U U U U
1 2 3 4 5

The O is a ball that falls down.

When it hits a ^, there's a 50-50 chance it will go left or right.
When it hits a /, it always goes left.
When it hits a \, it always goes right.

The ball eventually falls into one of the numbered U troughs at the bottom. The question is, what is the probability it will end up in each trough?
For this particular case, the probabilities are 0.0, 0.1875, 0.5625, 0.125, and 0.125, for troughs 1 through 5 respectively.
Here's another example with 3 troughs instead of 5. The probabilities are 0.5, 0.5, and 0.0:
  O

  /
 ^ ^
U U U
1 2 3

In this challenge we will generalize this problem to a mechanism with any number of layers set up in any fashion.
Challenge
Write a program or function that takes in the ASCII representation of the pyramid structure of the mechanism. (Input via stdin/command line/function arg.)
You may either assume it comes in with spaces that put it in the proper shape, e.g.
   ^
  \ ^
 ^ ^ \
\ ^ / ^

Or you may assume it comes in with no spaces at all, e.g.
^
\^
^^\
\^/^

(If desired, you may assume there is a trailing newline and/or some consistent pattern of trailing spaces.)
The input pyramid structure may have any number of levels (aka lines), including zero. Each level has one more ^, /, or \ than the last, and there are levels + 1 troughs at the bottom (which aren't part of the input).
You program/function must print/return the list of the probabilities that the ball lands in each of the troughs (in the order leftmost trough to rightmost trough). These should be floating point values that, when printed, have at least 3 decimal places (superfluous zeros or decimal points are not required; 1 is fine for 1.000, .5 is fine for 0.500, etc.). If you wrote a function, you may print the values or return a list/array of the floats.
Any reasonable printed list format is fine. e.g. 0.5 0.5 0.0, [0.5 0.5 0.0], [0.5, 0.5, 0.0], {0.5, 0.5, 0.0}, or 0.5\n0.5\n0.0 would all be alright.
Examples
0 Levels: (boils down to one trivial U)
Input: [no input/empty string given]
Output: 1.0
1 Level:
Input: ^
Output: 0.5 0.5
Input: /
Output: 1.0 0.0
Input: \
Output: 0.0 1.0
2 Levels: (second example above)
Input:
 /
^ ^

Output: 0.5 0.5 0.0
3 Levels:
Input:
  ^
 ^ ^
^ ^ ^

Output: 0.125 0.375 0.375 0.125
Input:
  \
 / \
/ / \

Output: 0.0 0.0 0.0 1.0
4 Levels: (first example above)
Input:
   ^
  \ ^
 ^ ^ \
\ ^ / ^

Output: 0.0 0.1875 0.5625 0.125 0.125
7 Levels:
Input:
      ^
     / ^
    ^ ^ /
   / \ / \
  ^ ^ / ^ \
 ^ \ ^ \ / ^
\ ^ ^ ^ \ ^ /

Output: 0.0 0.09375 0.28125 0.4375 0.1875 0.0 0.0 0.0
Scoring
The shortest answer in bytes wins. Tiebreaker is earlier post.

Quincunx had better answer this.

"some consistent pattern of trailing spaces" - may I assume that the trailing spaces on the Nth line encode the probability for the ball to land in the Nth bucket?

@Random832 No. (Do you really think that would fly?)

There's a reason I posted it as a comment instead of an answer. I just thought it was interesting how permissive this puzzle was about input - most that I've seen dictate the format of the input and/or output more strictly.

@Random832: The input and output are very unambiguous. Standard loopholes (like encoding the answer in the input) don't need to be addressed in every challenge.

@Random832 To be clear, I allowed "consistent" trailing spaces because, for example, inputting same sized strings on each line might be easier in some cases. I admit the word "consistent" is a bit vague, but Alex is right that common sense needs to be applied. e.g. I didn't specify that the output be given in Arabic numerals, but somehow everyone knows.

@Calvin'sHobbies: Is there a maximum depth to support?

@MooingDuck The depth should only be limited by computer memory and you languages int maximum. I'd say any depth below 1024 should definitely work.

CJam, 50 48 45 44 42 40 bytes
1]q{iD%"(+0 0+( (\Y/::+ (d2/_a+"S/=~+}/p

This expects the input to be without space and have a trailing newline. For example:
^
\^
^^\
\^/^

[0 0.1875 0.5625 0.125 0.125]

Algorithm
The basic idea is that you keep on parsing each character (there are only 4 different characters) and perform different operations on the probability distribution (initially an array containing 1 element of value 1). For each row of input characters (starting with the first character on first row), we maintain a probability array of that same size. Each character acts upon the first probability from the list and pushes the resultant pair to the end of the list. After each line, we sum up pairs from the list to get exact number of items as the items on the next line.
Here are the four characters and the required actions corresponding to each:

^ : When this character occurs, you split the current probability to two parts. For example, if we have this on the first line, we have to convert the [1] to [0.5 0.5]
/ : When this characters occurs, we have to put <current probability> 0 in place of the current probability in the array.
\ : When this characters occurs, we have to put 0 <current probability> in place of the current probability in the array.
\n : When this character occurs, we have a new line. Thus we group together all pairs from above 3 characters and sum them up to get probability of each item for the next line. For ex. [0 0.5 0.25 0.25] gets converted to [0 0.75 0.25]. Note that the first and last items have an implicit pair (valued 0) before and after them.

Now we only have to identify the right character and perform the right action. Lets use the usual maths here to do that. The ASCII codes for ^, \, / and \n are 94, 92, 47, and 10. After a few trials, we get this simple equation to convert these numbers into 0, 1, 2 and 3:
"^\/
":ied13f%ed4f%ed

gives:
Stack: [[94 92 47 10]]
Stack: [[3 1 8 10]]
Stack: [[3 1 0 2]]
3102

In an array of length 4, the last 4f% would be implicit. So we simply do %13 to the ASCII code of the character and choose the right action from an array of actions.
Code explanation:
1]                                 e# Initial probability array with 1 probability
  q{                          }/   e# Read the whole input and iterate char by char
    iD%                            e# mod the ASCII code of the character with 13
"(+0 0+( (\Y/::+ (d2/_a+"S/        e# This is our actions array in order of [\ / \n ^]
                           =~      e# We pick the correct action and eval it
                             +     e# Evaling each action will leave one number out of the
                                   e# pairs out of the array. So we put it back in
                                p  e# Print the final probability array

Try it online here

How do you test it with 0 rows?

@trichoplax should work now.

It works now with empty input :)

Ruby 140
->s{r=[1.0]
s.lines.map{|l|n=[i=0.0]*(r.size+1)
l.scan(/\S/).map{|e|a,b=e>?/?e>?]?[0.5]*2:[0,1]:[1,0]
z=r[i]
n[i]+=z*a
n[i+=1]+=z*b}
r=n}
r}

Function that takes as input the string (can be nicely formatted as a pyramid) and returns an array of floats.
Test it online: http://ideone.com/kmsZMe
Pretty straightforward implementation. Here it is ungolfed:
F = -> input {
  probabilities = [1.0]

  input.lines.each { |line|

    new_probabilities = [0.0] * (probabilities.size+1)
    elements = line.scan /\S/
    elements.map.with_index{|el, i|
      deltas = el > '/' ? (el > ']' ? [0.5,0.5] : [0,1]) : [1,0]

      d1, d2 = deltas

      new_probabilities[i] += probabilities[i] * d1
      new_probabilities[i + 1] += probabilities[i] * d2
    }
    probabilities = new_probabilities
  }
  return probabilities
}

Ruby, 140 158 bytes
Don't keep upvoting this when there's a better ruby version. Here are more tricks for you.
Unnamed function with one argument. Must not contain any spaces. May or may not contain a trailing newline.
->s{Z=(s.split'
')<<[]
K=[]
F=->i,j,f{k=Z[i][j]
K[i]||=0
k==?^?2.times{|m|F[i+1,j+m,f/2]}:!k ?K[j]+=f :F[i+1,j+(k==?/?0:1),f]}
F[0,0,1.0]
K}

Wastes 9 bytes on having to handle 0 levels (empty string). All test cases work out correctly, see here at ideone.

Just because there's a "better" Ruby answer doesn't mean yours (or any other Ruby answer for that matter) isn't worth votes. :)

I upvoted this myself because it contains some nice tricks. I like your multiline split, for example.

Pyth, 43 42 41 bytes
umsdc+0sm@c[ZJhkJZKcJ2K)2x"\/"ekC,GH2.z]1

This expects the input to be without spaces. Try it online: Pyth Compiler/Executor
Pyth, 40 bytes (questionable)
umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1

Thanks to @isaacg, for saving one byte. Notice that this version didn't actually work in the version of Pyth, when the question was asked. There was a tiny bug in the compiler. Despite this code uses no new features of Pyth (only stuff that was in the Pyth docs for a long time and should have worked), this might not be a valid answer. Decide for yourself.
Try it online: Pyth Compiler/Executor
Explanation:
umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1
u                                   .z]1  reduce G, starting with G = [1], for H in all_input():
                               C,GH         zip(G,H)
        m                                   map each pair k to:
            [ZJhkcJ2)                         create a list [0, k[0], k[0]/2]
                     x"\/"ek                  index of k[1] in "\/" (-1 for "^")
          K@                                  take the correspondent element of the list and store in K
         ,                  -JK               create a pair (K, k[0]-K)
     +0s                                    sum and insert 0 at the begin
    c                              2        chop into pairs
 msd                                        sum up each pair
                                            G gets updated with this new list

For instance if I currently have the input probabilities G = [0.5, 0.5, 0.0] and the row H = "^/^" the following happens:

zip       ... [(0.5,"^"), (0.5,"/"), (0.0,"^")]
create output probabilities ... [[0.25,0.25], [0.5,0.0], [0.0, 0.0]]
0+sum ... [0, 0.25, 0.25, 0.5, 0.0, 0.0, 0.0]
chop      ... [0,0.25], [0.25,0.5], [0.0,0.0], [0.0]]
sum       ... [0.25, 0.75, 0.0, 0.0]

I was trying to golf this, and it led me to a bug in the compiler. The golf works, now that I've fixed the bug. The golf is to replace the list of 2-value lists with one list, and then generate the other value by subtracting the first value from hk.  ,K@[ZJhkcJ2)x"\/"ek-JK

This is really a fine line when you fixing a bug is not being counted as a newer version of the language (and thus is still valid for questions asked before the fix)

@Optimizer Your right. Added some notes to the answer, that explains the circumstances.

@Optimizer In this case, it seems like a good rule of thumb is whether it's really a newer version of the language or a newer version of the language implementation that fixes a bug, bringing the implementation closer into line with the spec.

@Desty That is why I mentioned that its a fine line ;)

C#, 274 247 bytes
Nothing fancy, complete program that reads lines (with or without spaces, it just strips them) in from STDIN, and prints space separated results to STDOUT.
using Q=System.Console;class P{static void Main(){decimal[]k={1},t;string L;for(int l=0,i;(L=Q.ReadLine())!=null;k=t)for(L=L.Replace(" ",""),t=new decimal[++l+1],i=0;i<l;)t[i]+=k[i]-(t[i+1]=(8-L[i]%8)/2*k[i++]/2);Q.WriteLine(string.Join(" ",k));}}

Tidier code with comments:
using Q=System.Console;

class P
{
    // / 47
    // \ 92
    // ^ 94

    static void Main()
    {
        decimal[]k={1},t; // k is old array, t is new array

        string L; // L is the current line, R is the current result (1 if no rows)
        for(int l=0,i; // l is length of old array, i is index in old array
            (L=Q.ReadLine())!=null; // for each line of input
            k=t) // swap array over
            for(L=L.Replace(" ",""), // remove spaces
                t=new decimal[++l+1], // create a new array
                i=0;

                i<l;) // for each position

                t[i]+=k[i]-( // add to left position (for last time)
                        t[i+1]=(8-L[i]%8)/2*k[i++]/2 // assign right position (k is decimal)
                    );

        Q.WriteLine(string.Join(" ",k)); // print result
    }
}

Python 3, 113
P=[1]
for C in input().split():
 l,*Q=0,
 for p,c in zip(P,C):r=p*"\^/".find(c)/2;Q+=l+r,;l=p-r
 P=Q+[l]
print(P)

Repeatedly updates the probability vector P in response to each line. This new probability vector Q is created one entry at a time. Iterates through the new slots, and computes the contribution from the peg to its right as r, while also computing the remaining contribution to the upcoming slot as p-r.
Expects each line to end in at least one space to avoid an issue where lines end in a backslash.

The input will have multiple lines so I don't think a single input() can handle that.

a trailing newline is not required for each line of the input.

@randomra I wrote this in Idle and it worked fine putting in multi-line inputs to the shell prompt.

Python 3, 138 bytes
def f(s):
 r=[1];p=t=0
 for e in s:
  if'!'<e:b=p==t*-~t/2;r+=[0]*b;t+=b;v=ord(e)%7+1;a=r[p]/2;r[-1]+=v//3*a;r+=v%3*a,;p+=1
 return r[~t:]

Works with any whitespaces as they are all filtered out (by if'!'<e).
Method:

We keep an ever expanding list r of the probabilities of reaching any obstacles and the implicit troughs below them. We start from the list [1].
If we are at the first obstacle in a row we need to add an extra 0 to the list for the leading trough. We decide if it is the first obstacle by comparing its index p to the next triangular number t*-~t/2.
For every obstacle we add its list-value partially to the last element and partially to a new trailing element. We divide the list-value based on the obstacle character (^:0.5 0.5; /:1 0; \:0 1). We use the following method:

Take v = ord(char) mod 7 + 1 yielding ^:4 /:6 \:2
v div 3 / 2 yields the first fraction (^:0.5 /:1 \:0)
v mod 3 / 2 yields the second fraction (^:0.5 /:0 \:1)

The result is the last t + 1 elements of the final list r.

2 bytes thanks to @Sp3000's chat advice.

Perl, 78
#!perl -p0a
@r=($/=1);$^=.5;@r=map$r-$l+($l=$$_*($r=shift@r)),/./g,$r=$l=0for@F;$_="@r"

Takes input without spaces.
Try me.

TI-BASIC, 73 76
Takes input one line at a time, and ends when a space is entered on its own, because neither line breaks in strings nor empty strings are legal in TI-BASIC.
{1→X
Input Str1
While Str1≠"  //one space
.5seq(inString("^/",sub(Str1,I,1)),I,1,dim(Ans
augment(Ans∟X,{0})+augment({0},∟X-∟XAns→X
Input Str1
End
∟X

I'm pretty sure I got the size right (TI-BASIC is tokenized, so each command takes either one or two bytes—seq() takes one, inString() takes two, dim() takes one, and so on. I counted the size manually.)
Although the backslash character is valid in a string, note that there is no way to input one from inside the program unless you have modified your calculator.

Javascript - 117
Tried using recursion, but that was too long...
Hat tip to xnor for the subtraction idea, which shaved off a dozen or more characters.
w=s=>{a=[1];s.split('\n').map(m=>{for(b=[i=0];z=a[i],f=m[i];b[i++]+=z-b[i])b[i+1]=f>']'?z/2:f<':'?0:z;a=b})
return a}

Ungolfed:
// s must not have spaces
w=s=>{
  // a is the current probability array
  a=[1];
  s.split('\n').map(
    // for each row of input...
    m=>{
      b=[0];  // b is the next row's probability array
      for(i=0; i<m.length;){
        z=a[i]; // z = probability
        f=m[i]; // f = letter
                                  // let's assume i == 0
        b[i+1] = (f>']') ? z/2 :  // if f == '^', b[1] = z/2
          (f<':' ? 0 :            // else if f == '/', b[1] = 0
            z);                   // else b[1] = z
        b[i++]+=z-b[i];           // then add (z-b[1]) to b[0]
      }
      a=z-b    // increment current probability array
    }
  )
  return a;
}


text:
You call it Centering, I call it Code Golf
"Let's face it, aligned images are like little gifts from Heaven. Welcome, but unexpected." - Geobits
+10000 reputation to whoever wins this challenge.
Rules:
1) You are to generate a program.
2) Input will be an image, however whether it is passed as a file or a list of numbers is up to you.
3) Output will be a file which when opened in paint (or similar) will show the image aligned.
4) The canvas size will always be between 100 x 100 and 2000 x 2000 pixels. It will always be a rectangle, but not always a square.
5) No hard coding of images or funky URL magic.
6) No external libraries to be used.
Guide to Centralisation (Joshpbarron Variant)
An image will be defined as centered if the 1st white(255,255,255,>0 rgba) or transparent(x,y,z,0 rgba) on an axis is equal distance (plus or minus 1 pixel) from the edge of the canvas.
This can be achieved (and will be verified by) the following method.
1) Imagine a bounding box around the object. (Black lines added for help)

2) Move the object around until the edge of the object is equal distance from the appropriate edge of the canvas.

3) Now forget the black lines.

Input:

Output:

More inputs here.
And respective outputs here.
The +10000 rep is a lie.

should the program handle completely white/transparent images?

As there is nothing to center, the same image should be returned. Same for images with no empty space.

You should add some specifics on the images that this should work for. For example should it work for an image that contains a mostly white background but has holes of transparency? Or does having transparency mean there will be no white, and vice versa.

Sorry, but the explanation is obvious. RBGA codes are given.

In the description, you talk about the distance of the 1st white/transparent pixel from an edge. Don't you mean the first non-white? Otherwise all the sample inputs are already solutions, because the distance of the first white pixel from each edge is 0, so those distanced are all equal.

Python 3, 120 205 bytes
EDIT : As the output image must have the same size as the input, the script gets longer ...
EDIT2 : It seems that the rule 6 (no external library) has been added after I answered, so this answer is to be considered invalid anyway :(
from PIL.Image import*;from PIL.ImageOps import*
c='RGB';i=open(input()).convert(c);w,h=i.size
o,a=new(c,(w,h),'white'),i.crop(invert(i).getbbox())
e,f=a.size;o.paste(a,((w-e)//2,(h-f)//2));o.save('o.png')

The former version just cropped the input image:
from PIL.Image import*;from PIL.ImageOps import*
i=open(input()).convert('RGB')
i.crop(invert(i).getbbox()).save('o.png')

both scripts read the image file name from stdin, and saves the output image as 'o.png'. for example :
python3 script.py <<< s2rMqYo.png

It accepts at least PNG images (potentially with an alpha channel) -- Tested 'ok' on the set provided by the asker.
...waiting for my reward ):

I can't test this at the minute, but does the output canvas size match the input canvas size?

pro tip for your future shell endeavors: python3 script.py <<< s2rMqYo.png is cleaner

@undergroundmonorail thx !

@Joshpbarron : no it doesn't .. but it wasn't asked to be so, was it ?

All the output images are.

Would you state that keeping the same size is mandatory ?

If you must not keep the same size, then just cut all the white space, what remains is centered.

sure, that's what my answer actually does

The output must be the same size as the input, yes.

You're using a library (PIL), which is not allowed. (PIL cannot be called part of the standard libraries, because it is not included with Python by default.)

@marinus I think that this is a bit harsh.. That alienates a huge number of programming languages.

HTML5 + JavaScript (ES5), 515 bytes
That count includes the HTML tags as they are part of the program. If you only count the image processing code, it is 376 bytes including the function wrapper.
<canvas id=o></canvas><script>f=function(p){o=new Image();o.crossOrigin='Anonymous';o.src=p;o.onload=function(){v=document.getElementById('o'),c=v.getContext('2d');v.width=l=w=o.width;v.height=t=h=o.height;c.drawImage(o,0,0);for(k=255,d=c[g='getImageData'](0,0,w,h).data,r=b=i=0;i<d.length;)if((d[i++]<k||d[i++]<k||d[i++]<k)&&d[i++]){x=i/4%w;y=~~(i/4/w);l=l<x?l:x;t=t<y?t:y;b=b>y?b:y;r=r>x?r:x}n=c[g](l,t,r-l+1,b-t+1);c.clearRect(0,0,w,h);c.putImageData(n,(w-r+l)/2,(h-b+t)/2)}}</script><input onblur=f(this.value)>

Input
A URL to an image.
Security restrictions
Because this program is running in a browser environment, only URLs to CORS-enabled images will work. Imgur is CORS enabled.
IE 10 does not support CORS. I haven't tested in IE 11 yet but it does work in Chrome and Firefox.
How to run

Type/paste in a URL into the input field.
De-focus (tab/click out of) from the input field.

Output
It outputs on the canvas on the page.
As this is a browser-based application, security restrictions prevent automatic download of a file but you can right click and save image in Chrome and Firefox. I haven't tested on IE 11 yet.
Demo
JavaScript code has been removed from the script element and put into the appropriate area to accommodate Stack Snippets:

f = function(p) {
  o = new Image();
  o.crossOrigin = 'Anonymous';
  o.src = p;
  o.onload = function() {
    v = document.getElementById('o'), c = v.getContext('2d');
    v.width = l = w = o.width;
    v.height = t = h = o.height;
    c.drawImage(o, 0, 0);
    for (k = 255, d = c[g = 'getImageData'](0, 0, w, h).data, r = b = i = 0; i < d.length;)
      if ((d[i++] < k || d[i++] < k || d[i++] < k) && d[i++]) {
        x = i / 4 % w;
        y = ~~(i / 4 / w);
        l = l < x ? l : x;
        t = t < y ? t : y;
        b = b > y ? b : y;
        r = r > x ? r : x
      }
    n = c[g](l, t, r - l + 1, b - t + 1);
    c.clearRect(0, 0, w, h);
    c.putImageData(n, (w - r + l) / 2, (h - b + t) / 2)
  }
}
<canvas id=o></canvas>
<input onblur=f(this.value)>

Confirmed working in Edge. I imagine it'd work in IE11 as well.

Processing 2 - 323 450
Image is read from the file f.png in the data folder of the sketch.  Places the image and determines it's bounds.  Calculates the correct position and replaces the image shifted correctly.
PImage p=loadImage("h.png");int a,b,c,d,x,y,w,i,n,m,t;a=w=p.width;c=i=p.height;clear();size(w,i,P2D);x=y=b=d=t=0;image(p,0,0);loadPixels();while(x<w*i){if(pixels[x]==color(255))t=1;x++;}x=0;background(255);image(p,0,0);loadPixels();while(y*w+x<w*i){if(pixels[y*w+x]!=color(255)){if(x<a)a=x;if(x>b)b=x;if(y<c)c=y;if(y>d)d=y;}x++;if(x==w){x=0;y++;}}n=(w-(b-a))/2;m=(i-(d-c))/2;clear();if(t>0)background(255);image(p,n-a,m-c);loadPixels();save("g.png");

readable version:
PImage p=loadImage("h.png");
int a,b,c,d,x,y,w,i,n,m,t;
a=w=p.width;
c=i=p.height;
clear();
size(w,i,P2D);
x=y=b=d=t=0;
image(p,0,0);
loadPixels();
while(x<w*i)
{
 if(pixels[x]==color(255))t=1;
 x++;
}
x=0;
background(255);
image(p,0,0);
loadPixels();
while(y*w+x<w*i)
{
 if(pixels[y*w+x]!=color(255))
 {
   if(x<a)a=x;
   if(x>b)b=x;
   if(y<c)c=y;
   if(y>d)d=y;
 }
 x++;
 if(x==w){x=0;y++;}
}
n=(w-(b-a))/2;
m=(i-(d-c))/2;
clear();
if(t>0)background(255);
image(p,n-a,m-c);
loadPixels();
save("g.png");

Example output:

You can get processing here

Could you please provide a sample output file for me to compare.

It's nice...but not quite. The input images have a transparent background.

"Image is read from the file f.png". Really? In your code, I see this line: PImage p=loadImage("h.png"); at the very top.

color(-1) and background(-1) are each 1 byte shorter than color(255) and background(255) respectively. And I think you can remove the P2D in the size call

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Digits Digging a Dungeon

Edit: I will award a 100-reputation bounty for the first solver of the bonus puzzle at the end of the question!
I will add the bounty to the question only when the answer appears as this bounty has no deadline.

Given a non-decreasing list of one-digit positive integers, you should determine how deep dungeon the digits will dig.
███  ███  A dungeon with 5 blocks removed and a depth of 3.
███  ███
███ ████
████████

Before the start of the digging the ground is level.
Every digit can remove exactly one block of soil from below itself but it has to reach that position from outside the dungeon and after it removed the block has to leave the dungeon. While doing so a digit can't descend or ascend more than its numerical value at any horizontal step.
The digits use the following strategy for digging:

The digit with the smallest value digs firsts and after that the next digger is always the next smallest value from the rest of the digits.
The first digit can dig at any position. (All ground is the same.)
The following digits always dig at the leftmost already started column where they can go and come out. If no such column exists they start to dig a new column on the right side of the rightmost one.

For example the digits 1 1 1 2 3 3 would dig the following dungeon (step-by-step visualization with numbers marking which kind of digit dig out that position):
███1████    ███11███    ███11███    ███11███    ███11███    ███11███
████████    ████████    ███1████    ███1████    ███1████    ███13███
████████    ████████    ████████    ███2████    ███2████    ███2████
████████    ████████    ████████    ████████    ███3████    ███3████
████████    ████████    ████████    ████████    ████████    ████████

Explanation for the example:

The second 1 couldn't climb out of the only available column if it would deepen it to 2-deep so it digs right to it.
The third 1 can dig in the leftmost column creating a 2-deep column as it can move out into the 1-deep column and then to the ground level.
The next 2 and 3 both can dig in the leftmost column.
The last 3 can't dig in the leftmost column but can in the next one.

Input

A non-decreasing list of positive one-digit integers with at least one element.

Output

A single positive integer, the depth of the constructed dungeon.

Examples
Input => Output (with the depths of the columns of the dungeon from left to right as explanation which is not part of the output)
[3]  =>  1
(column depths are [1])

[1, 1, 1, 2, 3, 3]  =>  4
(column depths are [4, 2])

[1, 1, 1, 1, 1, 1, 1, 1]  =>  3
(column depths are [3, 2, 2, 1])

[1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5]  =>  11
(column depths are [11, 6, 2])

[1, 1, 1, 1, 1, 2, 2, 9, 9, 9]  =>  7
(column depths are [7, 2, 1])

[2, 2, 2, 2, 2, 5, 5, 5, 7, 7, 9]  =>  9
(column depths are [9, 2])

[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5]  =>  10
(column depths are [10, 5])

[1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7, 7, 9]  =>  13
(column depths are [13, 5])

[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]  =>  13
(column depths are [13, 5])

[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9]  =>  21
(column depths are [21, 12, 3])

This is code-golf so the shortest entry wins.
Bonus puzzle
Can you prove (or disprove) that the strategy described in the "The digits use the following strategy for digging" section always gives the deepest possible dungeon for the given digits?

Pyth, 21 bytes
huXf>+H@GhT@GT0G1Qm0Q

Try it online: Single Demonstration or Test Suite
Explanation:
                  m0Q   generate a list of zeros of length len(input)
                        This will simulate the current depths
 u               Qm0Q   reduce G, starting with G=[0,...,0], for H in input():
   f          0             find the first number T >= 0, which satisfies:
    >+H@GhT@GT                  H + G[T+1] > G[T]
  X            G1           increase the depth at this position by one
                            update G with this result
h                       print the first element in this list

Java, 199
import java.util.*;a->{List<Integer>l=new ArrayList();l.add(0);int x,y,z=0;s:for(int i:a){for(x=0;x<z;x++)if((y=l.get(x))-l.get(x+1)<i){l.set(x,l.get(x)+1);continue s;}l.add(z++,1);}return l.get(0);}

Expanded, runnable version
import java.util.*;
class DIGits {
    public static void main(String[] args) {
        java.util.function.Function<int[], Integer> f =
                a->{
                    List<Integer> l = new ArrayList();
                    l.add(0);
                    int x, y, z = 0;
                    s:
                    for (int i : a) {
                        for (x = 0; x < z; x++) {
                            if ((y = l.get(x)) - l.get(x + 1) < i) {
                                l.set(x, l.get(x) + 1);
                                continue s;
                            }
                        }
                        l.add(z++, 1);
                    }
                    return l.get(0);
                };
        System.out.println(f.apply(new int[]{1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7, 7, 9}));
    }
}

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Can you fold a hexomino into a cube?
One of my kid's favorite toys is a set like this.  Actually its one of my favorite toys - I've been playing with it and its been giving me some PPCG challenge ideas.  Here's one:
Write a program or function that takes an ASCII line drawing as input and decides whether or not it folds into a cube.
Input
Input will consist of exactly one hexomino built from squares like this:
+-+
| |
+-+

For example a valid input heximino is:
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
  | |
  +-+

Output

A truthy value if the hexomino can be folded into a cube, or
A falsey value otherwise.

To save us a bit of work, wikipedia has nice graphics of:

All 35 hexominoes:

All 11 hexominoes that fold into cubes:

Notes

Input hexominoes may have any rotation or reflection, not just those shown in the images above
Input hexominoes may have leading spaces, but will be correctly aligned with respect to themselves
Input hexominoes may have trailing space at the end of lines and trailing newlines at the end of input

Can you explain why there is an image-processing tag here ? Neither the question, nor the answer will have to do any kind of image processing to solve the challenge.

Clarification about leading/trailing space: are unnecessary leading/trailing spaces on each row and unnecessary newlines allowed in input ? Should I be able to manage a 1000+ chars input?

@edc65 yes you should expect the unnecessary white space you describe. 1000 chars max input size seems reasonable - I'll edit that in

Hmm. I wonder how many cube hexominoes can be squeezed, juxtaposed, on a printed page?

PMA/Snails, 130
.!(z\ |o{c..!(z\ }3){w=(..!(z\ )|b..!(z\ )o{..!(z\ }2|c{..!(z\ }1,2w..!(z\ )|w{..!(z\ }1,2c..!(z\ }4o..!(z\ )(..!(z\ )|n..!(z\ )`2

or more "readably",
?
.!(z\  | o{c..!(z\ }3  )
{w =( ..!(z\ ) | b ..!(z\ ) o {..!(z\ }2  | c {..!(z\ }1,2w..!(z\ ) | w {..!(z\ }1,2c..!(z\  }4
o  ..!(z\ ) ( ..!(z\ ) | n ..!(z\ ) `2

Unusually, a problem came along that can be handled by the limited amount of features implemented so far. The !(z\ ) pattern determines that the current position is at the space in the middle of a square using a negative assertion that there is a space in some "octilinear" direction. The general idea is to check for a pattern that places a square at each of the 5 necessary locations relative to the square that the match starts on. Also, it needs to check that it is not in a 2x2 block of squares. Before the program would work, I had to fix a bug with the parsing of parentheses.
If the hexomino does not map a cube, 0 is printed. If it does, some positive integer is printed (number of matches).
I adapted this polyomino generator to create all possible test cases:
n=input()
r=range
T=lambda P:set(p-min(p.real for p in P)-min(p.imag for p in P)*1j for p in P)
A=[]
for i in r(1<<18):
 P=[k%3+k/3*1j for k in r(18)if i>>k&1]
 C=set(P[:1])
 for x in P:[any(p+1j**k in C for k in r(4))and C.add(p)for p in P]
 P=T(P)
 if not(C^P or P in A or len(P)-n):
  #for y in r(4):print''.join(' *'[y+x*1j in P] for x in r(6))
  o = [ [' ']*13 for _ in r(9)]
  for y in r(4):
   for x in r(6):
    if y+x*1j in P: X=2*x;Y=2*y; o[Y][X]=o[Y+2][X]=o[Y][X+2]=o[Y+2][X+2]='+'; o[Y][X+1]=o[Y+2][X+1]='-';o[Y+1][X+2]=o[Y+1][X]='|'
  print '\n'.join(map(''.join,o))
  A+=[T([p*1j**k for p in P])for k in r(4)]

hahahahahahahah more "readably"

Ruby, 173 148 145 143 bytes
h=->b,c{[c.count(c.max),c.count(c.min),3].max*2s{x=[];y=[];i=j=0
s.bytes{|e|e==43&&x<<i|y<<j;i=e<32?0*j+=1:i+1}
h[x,y]||h[y,x]}

Latest change: /2 on right side of < replaced by *2on left side. Allows elimination of one set of()
Explanation
The code is in two parts: a main unnamed function that does the parsing, and an auxiliary unnamed function assigned to the variable h that does the checking.
The main function scans bytewise through the string, adding the x and y coordinates i,j of all + symbols found to x[] and y[]. It then calls h twice. The first time it assumes the hexomino is horizontal (x[] contains the lengths and y[] the widths) and the second time it assumes it is vertical.
The function h takes the lengthwise coordinates in array b then the widthwise coordinates in array c. It calculates the length (in squares) by the expression  (b.max.b.min)/2. If this is less than or equal to 3, the hexomino should be evaluated in the other direction so h returns false.
Inspection of the hexominos will show that if the length is 4, those hexominos that will fold into a cube have no more than 2 squares (3 + symbols) in the first and last row. Most of the squares are concentrated on the middle row, which will become the equator of the cube. This condition turns out to be necessary and sufficient for a hexomino of length 4 that will fold into a cube.
There is only one hexomino of length 5 that will fold into a cube. It has 3 squares (4 + symbols) in its first and last rows. All other hexominos of length 5 have 5 or more + symbols in either the first or last row.
There is only one hexomino of length 6. It has 7 + symbols on each row.
Putting all this together, it is sufficient to check that the length of the hexomino is greater than 3, and the number of + symbols on the first and last rows (whichever is higher) is less than the length.
Ungolfed in test program
#checking function as explained in text
h=->b,c{[c.count(c.max),c.count(c.min),3].max<(b.max-b.min)/2}

#main function for parsing
f=->s{
  x=[]                 #separate assignments required,
  y=[]                 #otherwise we get 2 pointers to the same array
  i=j=0                #start coordinates 0,0
  s.bytes{|e|          #scan string bytewise
    e==43&&x<<i|y<<j     #if byte is a + symbol (ascii 43) add the coordinates to arrays x and y
    i=e<32?0*j+=1:i+1    #if byte is before ascii 32 assume newline, increment j and zero i. Otherwise increment i
  }
  h[x,y]||h[y,x]       #call h twice, with x and y in each possible order
}

#VALID INPUTS
puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
| |
+-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
  | |
  +-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
+-+
| |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]

puts f["
+-+
| |
+-+-+-+-+
| | | | |
+-+-+-+-+
      | |
      +-+"]

puts f["
    +-+
    | |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
    +-+
    | |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]

puts f["
  +-+
  | |
+-+-+-+-+
| | | | |
+-+-+-+-+
    | |
    +-+"]
puts f["
  +-+
  | |
+-+-+-+
| | | |
+-+-+-+-+
    | | |
    +-+-+"]
puts f["
+-+-+
| | |
+-+-+-+
  | | |
  +-+-+-+
    | | |
    +-+-+"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+-+
      | | | |
      +-+-+-+
"]

#INVALID INPUTS

puts f["
  +-+-+-+
  | | | |
  +-+-+-+
  | | | |
  +-+-+-+
"]

puts f["
  +-+-+-+-+-+-+
  | | | | | | |
  +-+-+-+-+-+-+

"]

puts f["
  +-+-+
  | | |
  +-+-+
  | |
  +-+
  | |
  +-+
  | |
  +-+
  | |
  +-+
"]

puts f["
  +-+-+-+-+-+
  | | | | | |
  +-+-+-+-+-+
    | |
    +-+
"]

puts f["
      +-+
      | |
  +-+-+-+-+-+
  | | | | | |
  +-+-+-+-+-+
"]

puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+-+
        | | |
        +-+-+"]

puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
      | | |
      +-+-+
"]

puts f["
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
  | | | |
  +-+ +-+
"]

puts f["
 +-+   +-+
 | |   | |
 +-+-+-+-+
 | | | | |
 +-+-+-+-+
"]

puts f["
   +-+-+
   | | |
 +-+-+-+-+
 | | | | |
 +-+-+-+-+
"]

puts f["
  +-+
  | |
  +-+
  | |
  +-+-+-+-+
  | | | | |
  +-+-+-+-+
"]

puts f["
  +-+
  | |
  +-+-+-+
  | | | |
  +-+-+-+
  | |
  +-+
  | |
  +-+
"]

puts f["
  +-+
  | |
+-+-+-+
| | | |
+-+-+-+
| |
+-+
| |
+-+"]

puts f["
  +-+-+
  | | |
  +-+-+
  | |
  +-+-+
  | | |
  +-+-+
    | |
    +-+
"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+
    | | | |
    +-+-+-+
"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+
      | |
      +-+-+
      | | |
      +-+-+
"]

puts f["
  +-+-+-+
  | | | |
  +-+-+-+-+
      | | |
      +-+-+
        | |
        +-+
"]

pentonimo → hexonimo in your text?

JavaScript (ES6), 443 431
Edit bug fix, problem during input parse, removing blank columns

F=t=>(a=b=c=d=e=f=g=h=0,M=Math.min,
t=t.split('\n').filter(r=>r.trim()>''),
t=t.map(r=>r.slice(M(...t.map(r=>r.search(/\S/))))),
t.map((r,i)=>i&1&&[...r].map((_,j)=>j&1&&r[j-1]==r[j+1]&t[i-1][j]==t[i+1][j]&r[j-1]=='|'
&&(y=i>>1,x=j>>1,z=y*5,w=x*5,a|=1<<(z+x),e|=1<<(w+y),b|=1<<(4+z-x),f|=1<<(4+w-y),c|=1<<(20-z+x),g|=1<<(20-w+y),d|=1<<(24-z-x),h|=1<<(24-w-y)
))),~[1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056].indexOf(M(a,b,c,d,e,f,g,h)))

That's very long, and even longer as parsing input is a big part of the task.
What I do is verifyng if the given input is one of the 11 foldable hexominoes.
Each foldable hexomino can be mapped to some 5x5 bitmap (up to 8 different, with simmetry and rotations). Taken the bitmaps as 25bit number, I have found the min values for the 11 noted hexominoes, using the following code (with very simple input format)
h=[ // Foldable hexominoes
'o\noooo\no', ' o\noooo\n o', // pink
'o\noooo\n   o', ' o\noooo\n  o', 'ooo\n  ooo', 'oo\n oo\n  oo', //blue
'o\noooo\n o', 'o\noooo\n  o', 'oo\n ooo\n o', 'oo\n ooo\n  o', 'o\nooo\n  oo' // gray
]
n=[]
h.forEach(t=>(
  a=[],
  t.split('\n')
    .map((r,y)=>[...r]
      .map((s,x)=>s>' '&&(
         a[0]|=1<<(y*5+x),a[1]|=1<<(x*5+y),
         a[2]|=1<<(y*5+4-x),a[3]|=1<<(x*5+4-y),
         a[4]|=1<<(20-y*5+x),a[5]|=1<<(20-x*5+y),
         a[6]|=1<<(24-y*5-x),a[7]|=1<<(24-x*5-y))
     )
  ),
n.push(Math.min(...a))
))

That gives [1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056]
So, given the input string, I have to do the same to find the min bitmap, then return true if this number is present in my precalc list.
// Not so golfed

F=t=>(
  a=b=c=d=e=f=g=h=0,M=Math.min,
  t=t.split('\n').filter(r=>r.trim()>''), // remove blank lines
  t=t.map(r=>r.slice(M(...t.map(r=>r.search(/\S/))))), // remove blank colums to the left
  t.map((r,i)=>i&1&&[...r] // only odd rows
   .map((_,j)=>j&1&& // only odd columns
      r[j-1]==r[j+1]&t[i-1][j]==t[i+1][j]&r[j-1]=='|' // found a cell
         &&(y=i>>1,x=j>>1,z=y*5,w=x*5, // find bitmaps for 8 rotations/simmetries
            a|=1<<(z+x),e|=1<<(w+y),
            b|=1<<(4+z-x),f|=1<<(4+w-y),
            c|=1<<(20-z+x),g|=1<<(20-w+y),
            d|=1<<(24-z-x),h|=1<<(24-w-y)
    ))),
   ~[1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056].indexOf(Math.min(a,b,c,d,e,f,g,h)) // look for min
)

Run snippet to test in Firefox

F=t=>(a=b=c=d=e=f=g=h=0,M=Math.min,
t=t.split('\n').filter(r=>r.trim()>''),
t=t.map(r=>r.slice(M(...t.map(r=>r.search(/\S/))))),
t.map((r,i)=>i&1&&[...r]
.map((_,j)=>j&1&&r[j-1]==r[j+1]&t[i-1][j]==t[i+1][j]&r[j-1]=='|'
&&(y=i>>1,x=j>>1,z=y*5,w=x*5,
a|=1<<(z+x),e|=1<<(w+y),b|=1<<(4+z-x),f|=1<<(4+w-y),c|=1<<(20-z+x),g|=1<<(20-w+y),d|=1<<(24-z-x),h|=1<<(24-w-y)
))),~[1505,2530,3024,4578,252,6552,2529,4577,2499,4547,7056].indexOf(M(a,b,c,d,e,f,g,h)))

s=[...'      \n      \n      \n  2   \n      \n      '],o=7,l=5,k={},t=0

out=[[],[]]

Test=s=>k[s]?0 // filter duplicates, but allow same shape in different position
  :k[s]=(
  p=Array(13).fill(0).map(x=>Array(13).fill(' ')), // build string to test in long format
  s.map((v,i)=>(x=2*(i%7),y=2*(i/7|0),-v&&(
    p[y][x]=p[y][x+2]=p[y+2][x]=p[y+2][x+2]='+',
    p[y][x+1]=p[y+2][x+1]='-',
    p[y+1][x]=p[y+1][x+2]='|'
  ))),
  s=p.map(r=>r.join('')).join('\n'),
  ok=F(s), // test

  out[!ok|0].push('\n'+s+-ok),
  1
)

Fill=(z,p)=>(
  s[p]=2,
  z>l?Test(s):s.forEach((v,i)=>v==' '&(s[i+o]==2|s[i-o]==2|s[i-1]==2|s[i+1]==2)?Fill(z+1,i):0),
  s[p]=' '
)

Fill(1,s.indexOf('2'))

OV.innerHTML=out[0].join('\n')
OI.innerHTML=out[1].join('\n')
pre {
  overflow: auto;
  font-size: 9px;
  height: 500px;
  display: block;
  border: 1px solid #888;
  padding: 6px 20px;
  line-height: 6px;
}
Verify all hexominoes possible in a 6x6 grid (Better full page)

  VALID	INVALID

Forgive me if I am missing something, but couldn't you the ,\nt=t from the end of the second line/the beginning of the third line?

@CᴏɴᴏʀO'Bʀɪᴇɴ reviewing six months later, the parsing code could be made 10...15 bytes shorter. As is, I need the assignment to t in line 2 and the again in line 3 because in line 3 it's used to find the number of blank chars to cut at left side.


text:
Concatenate lists of strings item-wise in Python
This is a tips question for golfing in python.
Suppose you have two lists of strings, and you want to concatenate the corresponding entries from each list. E.g. with a=list("abcd") and b=list("1234"), calculate ["a1","b2","c3","d4"].
This is trivial in array-based programming languages, where operations generally apply memberwise to lists. For example, in my golfing language Pip, the code is simply a.b. But in Python, it's not so easy.
The Pythonic way is probably to use zip and a list comprehension (25 chars):
[x+y for x,y in zip(a,b)]

Another method is map with a lambda function (23):
map(lambda x,y:x+y,a,b)

The following is the shortest I've come up with (21):
map("".join,zip(a,b))

Is there any shorter method?
Assume that the lists are the same length and that some kind of iterable is all that's needed (so a map object is fine in Python 3).

possible duplicate of Tips for golfing in Python

@Mast Does the tips list contain an answer which addresses this specific question?

@MartinBüttner If it isn't, it should. Prevents cluttering and keeps all the tricks togeter, etc.

20 chars
map(str.__add__,a,b)

Uses the build-in method string addition method __add__ that is invoked by + on strings in place of your anonymous function lambda x,y:x+y.

You know, I thought of str.__add__ but for some reason didn't check to see if it was shorter.

@DLosc the real advantage of this answer is using map with multiple iterables, which dis the zipping automatically. Without that it wouldn't be shorter. Note that if in your code you have to access some of the __*__ methods it may be shorter to do from operator import * and then use map(add,a,b).


text:
Do you want to code a snowman?
Here is a simple ASCII art snowman:
_===_
(.,.)
( : )
( : )

Let's make him some friends. This will be the general pattern for our ASCII art snowpeople:
 HHHHH
 HHHHH
X(LNR)Y
X(TTT)Y
 (BBB)

The leading spaces and the parentheses are always the same for all snowpeople. The different letters represent sections of the pattern that can individually change. Each section has exactly four presets for what ASCII characters can fill it.
By mixing and matching these presets for all eight sections, we can make a variety of snowpeople.
All Presets
(Notice that spaces are put on otherwise empty lines so the section shape is always correct.)
H is for Hat

Straw Hat

_===_
Mexican Hat
 ___
.....

Fez
  _
 /_\

Russian Hat
 ___
(_*_)

N is for Nose/Mouth

Normal ,
Dot .
Line _
None

L is for Left Eye

Dot .
Bigger Dot o
Biggest Dot O
Closed -

R is for Right Eye
(Same list as left eye.)
X is for Left Arm

Normal Arm

<
Upwards Arm
\

Downwards Arm

/
None

Y is for Right Arm

Normal Arm

>
Upwards Arm
/

Downwards Arm

\
None

T is for Torso

Buttons  :
Vest ] [
Inward Arms > <
None

B is for Base

Buttons  :
Feet " "
Flat ___
None

Challenge
Write a program that takes in an eight character string (via stdin or command line) in the format HNLRXYTB, where each letter is a digit from 1 to 4 that denotes which preset to use for the corresponding section of the snowperson. Print the full snowperson to stdout.
For example, the input 11114411 is the snowman at the top of the page. (First 1: he has a straw hat, second 1: he has a normal nose, etc.)
Another example, the snowperson for input 33232124:
   _
  /_\
\(o_O)
 (] [)>
 (   )

Details

Any amounts and combinations of leading/trailing spaces and leading/trailing newlines are allowed as long as...

the snowperson has all their sections arranged correctly with respect to one another, and
there are never more than 64 total whitespace characters (the general pattern is only 7×5, so you probably won't hit this limit).

You don't need to print rows/columns of the pattern if they only contain whitespace. e.g. the empty line of the straw hat is not required.
You must use the ordering of the parts as they are given above.
Instead of a program, you may write a function that takes the digit string as an argument. The output should be printed normally or returned as a string.
You may treat the input as an integer instead of a string if preferred.

Scoring
The shortest code in bytes wins.
Bonus question: Which of the 65536 distinct snowpeople is your favorite?

I like the angel 14441133. Alternatively the small-eyed four-armed monster. Your pick.

Does it have to be a snowman?

It doesn't have to be a snowman. (Disclaimer: It may have to be a snowman)

The occasional witty comment is nice, but for extended discussion please use chat instead of comments. I've cleaned this up a bit.

Question to do next: "The code never bothered me anyway"

Is PETSCII art equivalent acceptable? -> http://sta.c64.org/cbm64pet.html

@Joshpharron: OK, bye.

My favourite is 14444444 (as it has the digis of my rep, 4 and 1).

CJam, 135 134 132 130 126 125 bytes
0000000: 4e22285b200a5c225f2a295c2d2e2f6f2c3e4f3a3c3d5d225f  N"([ .\"_*)\-./o,>O:<=]"_
0000019: 2422dd7382d6bfab28707190992f240c362ee510262bd07a77  $".s....(pq../$.6...&+.zw
0000032: 08556de9dcdb566c676817c2b87f5ecb8bab145dc2f2f76e07  .Um...Vlgh....^....]...n.
000004b: 22323536624b623224663d4e2f7b5f2c342f2f7d25723a7e2e  "256bKb2$f=N/{_,4//}%r:~.
0000064: 3d2828342423346222205f0a20222e2a6f6f736572372f4e2a  =((4$#4b" _. ".*ooser7/N*

To create the file on your machine, execute xxd -r > snowman.cjam, paste the reversible hexdump from above, press Enter and finally Ctrl + D.
Alternatively, you can try the code online using the CJam interpreter.
Bonus
My favorite snowman is Olaf:
$ LANG=en_US cjam snowman.cjam <<< 12222212

 _===_
\(o.o)/
 ( : )
 (" ")

Winter's a good time to stay in and cuddle, but put me in summer and I'll be a… happy snowman!
Idea
The hex string
dd7382d6bfab28707190992f240c362ee510262bd07a7708
556de9dcdb566c676817c2b87f5ecb8bab145dc2f2f76e07

encodes the possible choices for all parts of the snowman, including the fixed ones. Let's call this string P.
To decode it, we convert P (here treated as an array of integers) from base 256 to base 20 and replace each of the resulting integers by the corresponding character of the string M:
([
"_*)\-./o,>O:<=]

This results in the string T:
/(_*_)"_===_/....., /_\
 ,._
-.oO
-.oO
   <\  /
   >/  \
    : ] [> <
    : " "___
 ((()

The first line encodes all hat choices, the last all fixed body parts. The other lines contain the 28 variable body parts.
We split T at linefeeds and divide the strings of the resulting array into four parts of equal length. Then, we read the input from STDIN, push the array of its digits in base 10 and select the corresponding elements of the split strings. We take advantage of the fact that arrays wrap around in CJam, so the element at index 4 of an array of length 4 is actually the first element. The last divided string does not correspond to any input, so it will get selected entirely.
We handle the hat by shifting the first element out of the resulting array. The index in M of first character, read as a base 4 number, reveals the number of spaces and underscores in the first line of the hat. We print those characters, a linefeed, a space and the remainder of the shifted string. Then, we push an additional linefeed on the bottom of the stack.
For the body parts, we concatenate the string corresponding to all of them. Let's call this string S. To assemble the body parts, we perform transliteration: we take each character of the string M, compute its index in sort(M) and replace it by the corresponding character of S. We take advantage of the fact that the transliteration operator automatically pads S to match the length of sort(M) by repeating the last character of S as many times as necessary.
Finally, we divide the resulting string into substrings of length 7 and place a linefeed between each pair of substrings.
Code
Suppose that the variables M and P contain the strings M and P.
N        e# Push a linefeed.
M_$      e# Push M and a sorted copy.
P256bKb  e# Push P and convert it from base 256 to base 20.
2$       e# Push a copy of M.
f=       e# Compute T by retrieving the proper chars from M.
N/       e# Split T at linefeeds.
{_,4//}% e# Divide each string into four substrings of equal length.
r:~      e# Read a number from STDIN and push the array of its digits in base 10.
.=       e# Get the corresponding chunks from T.
((       e# Shift out the first string and that string's first character.
4$#      e# Find its index in M.
4b       e# Compute its digits in base 4.
" _
 ".*     e# Repeat the space and underscore that many times in place.
oo       e# Print the result and the shifted string.
s        e# Flatten the remainder of the array. This pushes S.
er       e# Perform transliteration.
7/       e# Split into chunks of length 7.
N*       e# Join using linefeeds.

JavaScript ES6, 210 208 202 bytes
s=>` 0
8(213)9
4(6)5
 (7)`.replace(/\d/g,p=>`_===_1 ___
 .....1  _
  /_\\1 ___
 (_*_)1,1.1_11.1o101-1.1o101-1<11/11>11\\11 : 1] [1> <1   1 : 1" "1___1   11\\11 11/11 `.split(1)[s[p>7?p-4:p]-1+p*4]||' ')

This is an anonymous function; you use it by executing ([function code])('42232124'). The most aggravating part of this was the arms, which take up 2 lines, so I had to include code for both top and bottom.
The Stack Snippet below has ungolfed, un-ES6-ified, commented code. And you can use it to easily test the code and try out different combinations. Edit: I'm having way too much fun with this. I've added several new features, including a way to generate a random snowman.
Thanks to Yair Rand for saving six bytes.

var f=function(s){
  return' 0\n8(213)9\n4(6)5\n (7)' // Start with a placeholder string with all the static components
    .replace(/\d/g,function(p){ // Go through each placeholder number to replace it with its value
    // The massive string below holds all the possible body parts, separated by 1 for easy splitting.
    // The two at the end are for the top of the arms
    return'_===_1 ___\n .....1  _\n  /_\\1 ___\n (_*_)1,1.1_11.1o101-1.1o101\
-1<11/11>11\\11 : 1] [1> <1   1 : 1" "1___1   11\\11 11/11 '.split(1)
    [s[p>7?p-4:p]-1 // Get the value from the input string. If the current body part
                    // is the top of the two-line arms (8 or 9), drop it down to 4 or 5
                    // Subtract 1 to account for the 0-indexed array.
     +p*4] // multiply by 4 to skip to the relevant code
     ||' ' // To save bytes in the above string, spaces are empty strings, so replace them here
  })
}

// Code for the interactive version follows
// http://codepen.io/hsl/pen/bdEgej
function updateRadios(){$('input[type="radio"]').each(function(){if($(this).is(":checked")){var t=$(this).data("p"),i=$(this).data("v");input[t]=i}}),inputS=input.join(""),update()}var input=[],inputS=$("#code").val(),update=function(){$("#p").text(f(inputS)),$("#code").val(inputS)};$('input[type="radio"]').change(updateRadios),$("#code").keyup(function(){inputS=$(this).val(),update()}),updateRadios(),$("#random").click(function(){for(var t=0;8>t;t++)$("div:eq("+t+") input:eq("+Math.floor(4*Math.random())+")").prop("checked",!0);updateRadios()});
body{font-family:sans-serif}h2{font-size:18px;font-weight:400}label{display:block}div{display:inline-block;margin:0 10px}#code{width:70px}

Hat
<input type="radio" name="p1" data-p="1" data-v="1"> Straw hat<input type="radio" name="p1" data-p="1" data-v="2"> Mexican hat<input type="radio" name="p1" data-p="1" data-v="3"> Fez<input type="radio" name="p1" data-p="1" data-v="4" checked> Russian hat

Nose/mouth
<input type="radio" name="p2" data-p="2" data-v="1"> Normal<input type="radio" name="p2" data-p="2" data-v="2" checked> Dot<input type="radio" name="p2" data-p="2" data-v="3"> Line<input type="radio" name="p2" data-p="2" data-v="4"> None

Left eye
<input type="radio" name="p3" data-p="3" data-v="1"> Dot<input type="radio" name="p3" data-p="3" data-v="2" checked> Bigger dot<input type="radio" name="p3" data-p="3" data-v="3"> Biggest dot<input type="radio" name="p3" data-p="3" data-v="4"> Closed

Right eye
<input type="radio" name="p4" data-p="4" data-v="1"> Dot<input type="radio" name="p4" data-p="4" data-v="2"> Bigger dot<input type="radio" name="p4" data-p="4" data-v="3" checked> Biggest dot<input type="radio" name="p4" data-p="4" data-v="4"> Closed

Left arm
<input type="radio" name="p5" data-p="5" data-v="1"> Normal<input type="radio" name="p5" data-p="5" data-v="2" checked> Upwards<input type="radio" name="p5" data-p="5" data-v="3"> Downwards<input type="radio" name="p5" data-p="5" data-v="4"> None

Right arm
<input type="radio" name="p6" data-p="6" data-v="1" checked> Normal<input type="radio" name="p6" data-p="6" data-v="2"> Upwards<input type="radio" name="p6" data-p="6" data-v="3"> Downwards<input type="radio" name="p6" data-p="6" data-v="4"> None

Torso
<input type="radio" name="p7" data-p="7" data-v="1"> Buttons<input type="radio" name="p7" data-p="7" data-v="2" checked> Vest<input type="radio" name="p7" data-p="7" data-v="3"> Inward arms<input type="radio" name="p7" data-p="7" data-v="4"> None

Base
<input type="radio" name="p8" data-p="8" data-v="1"> Buttons<input type="radio" name="p8" data-p="8" data-v="2"> Feet<input type="radio" name="p8" data-p="8" data-v="3"> Flat<input type="radio" name="p8" data-p="8" data-v="4" checked> None

<button id="random">Randomize</button>

<input type="text" id="code">

+1 Very clever, so much better than mine

The 'GUI' is pretty darn cool.

You can save 2 bytes by using your "un-ES6-fied" code instead of p*4+(s[p>7?p-4:p]-1) and another 2 bytes by making the function anonymous (which is allowed by default).

@Dennis Thanks! I had actually subtracted the first one from my byte count but forgot to change the code.

Sweet, check out the 8-eyed spider snowman: 22112333

I like the sleeping Russian owl: 41444442

... 22111131 ...

You can save six bytes by removing each single space in a slot (1 1 -> 11) and adding ||' ' at the end.

CJam, 164 bytes
Generates the snowman left-to-right, top-to-bottom. This eliminates the need for any kind of string joining or repositioning operations, as I just leave every piece of the snowman on the stack. And then, due to the automatic stack dump at the end of programs:
♫ CJam wants to build a snowman! ♫
q:Q;SS"
 _===_,___
 ....., _
  /_\,___
 (_*_)"',/0{Q=~(=}:G~N" \ "4G'(".oO-"_2G",._ "1G@3G')" / "5GN"< / "4G'(" : ] [> <   "3/6G')"> \ "5GNS'(" : \" \"___   "3/7G')

Try it online.
Bonus
Thinking outside the box! 32443333 gives a snow(wo)man bride. You've gotta try a bit to see it, but there are the inward arms, fez + downwards arms = veil, and the head is actually in the fez/veil. The generally large form is the billowy dress, and the "eyes" and "nose" are folds in the dress.
   _
  /_\
 (-.-)
/(> <)\
 (___)

Other "eye" choices are a bit risqué...

To me, your bonus looks more like a KKK member than a bride.

Python, 276 289 bytes
V='.oO-'
def F(d):
 D=lambda i:int(d[i])-1
 print"  "+("","___"," _ ","___")[D(0)]+"\n "+\
"_. (=./_=._*=.\\__. )"[D(0)::4]+"\n"+\
" \\  "[D(4)]+"("+V[D(2)]+',._ '[D(1)]+V[D(3)]+")"+" /  "[D(5)]+'\n'+\
"< / "[D(4)]+"("+" ]> :    [< "[D(6)::4]+")"+"> \\ "[D(5)]+"\n ("+\
' "_ : _  "_ '[D(7)::4]+")"

This code has 8 extra bytes(\*4) for readability.
Builds the snowman up bit by bit.
Bonus
F("44444432") gives "sleepy russian bear":
  ___
 (_*_)
 (- -)
 (> <)
 (" ")

Sleepy russian bear is now my favorite too.

The top row underscores don't seem to be correct on the fez and russian hats. e.g. It's giving a propellor hat..

@Calvin'sHobbies: The russian hat was okay, but the fez hat was messed up. I fixed it now and checked all the other cases too. I must be more careful in the future!

super late to the party, but this TIO says this is 297 for me. Intellij says 299. Am I missing something?

Python 2, 354 280 241 261 bytes
def s(g):H,N,L,R,X,Y,T,B=[int(c)-1for c in g];e='.oO-';print(' '*9+'_ _ ___ _ _\n\n\n\n    _. (=./_=._*=.\\__. )')[H::4]+'\n'+' \\  '[X]+'('+e[L]+',._ '[N]+e[R]+')'+' /  '[Y]+'\n'+'< / '[X]+"("+' ]> :    [< '[T::4]+')'+'> \\ '[Y]+'\n ('+' "_ : _  "_ '[B::4]+")"

Calling s('33232124') gives:
   _
  /_\
\(o_O)
 (] [)>
 (   )

But my favorites are 44242123 and 41341144:
  ___      ___
 (_*_)    (_*_)
\(o -)    (O,-)
 (] [)>  <(   )>
 (___)    (   )

When I do s('33232124') the fez slashes aren't drawn. In fact the bottom half of the hat is missing in a lot of cases. Also, 0 is not one of the options.

@Calvin'sHobbies Thanks, I fixed it.

TI-BASIC, 397 bytes
Important: If you want to test this out, download it from here and send that file to your calculator. Do not try to copy the code below into TI-Connect CE's program editor or SourceCoder 3 or something to build and send it to your calculator; in TI-Connect's case, it'll say it has an invalid token. SC3 uses the backslash as a comment delimiter (// starts a comment in SC3; /\/, though, will export as //) and so it won't export the arms and hat and such correctly, causing the program to both display the incorrect body parts and throw an ERROR:DOMAIN every now and then. Fun stuff!
Important #2: I'm too lazy to fix the download at the moment, so when you transfer it to your calc, change the 7 on the third line from the bottom to X+6. The code below is fixed if you need to compare.
Input Str9
seq(inString("1234",sub(Str9,I,1)),I,1,length(Ans→L1
"      ___   _   ___ →Str1
"_===_..... /_\ (_*_)→Str2
",._ →Str3
"•oO-→Str4
"<\/ →Str5
">/\ →Str6
" : ] [> <   →Str7
" : ¨ ¨___   →Str8
"Str1Str2Str3Str4Str5Str6Str7Str8→Str0
For(X,3,5
Output(X,2,"(   )
End
L1
Output(3,3,sub(Str4,Ans(3),1)+sub(Str3,Ans(2),1)+sub(Str4,Ans(4),1
Ans(5
Output(4-(Ans=2),1,sub(Str5,Ans,1
L1(6
Output(4-(Ans=2),7,sub(Str6,Ans,1
L1-1
For(X,1,2
Output(X+3,3,sub(expr(sub(Str0,X+6,1)),1+3Ans(X+6),3
Output(X,2,sub(expr(sub(Str0,X,1)),1+5Ans(1),5
End

Bonus: I'm particularly fond of 12341214.
 _===_
 (O.-)/
<( : )
 (   )

Some notes:

It can definitely be golfed more, no question about that. I'm nearly positive that I can combine a majority, if not all, of the outputting into a single For( loop. Also, I'm pretty sure that I can merge some strings together.
In Str4 (the eyes) I use the "plot dot" ([2ND] → [0]CATALOG → [3]θ → scroll down, it's between ﹢ (small plus) and · (interpunct)) as opposed to a period so that the eyes don't line up with the comma, because that looks weird as hell.
In Str8 (base) I had to use a diaeresis (¨) instead of double quotes because there's no way to escape characters in TI-BASIC, and double quotes are used to start/end strings.
In TI-BASIC, there's no need to close parentheses and brackets if they're followed by a colon, newline or → (used for var assignment), and double quotes (strings) can stay unclosed when followed by a newline or →.

First, in the second line, length(Ans should be length(Str9; second, have you tried combining Str3 through Str6 into a single string?

Oh, whoops! I think that's fixed in the download, though. Besides that, I haven't looked at this much since I made it, but I did mention that I could probably merge some strings together; I'll look into that sometime today/this week.

I thought I was good at TI-Basic, but this answer includes some black magic… Fi22111131rstly, really clever usage of seq( in line 2, it took me a while to understand that. Also, how in the world have I never played around with expr(?!? That is amazing! 4-(Ans=2) is also nice, I've only used adding "booleans" once before, in a TicTacToe AI.

Hm, that was apparently a middle-click at the wrong place and now I can't edit it out anymore.

CJam, 150 145 bytes
Base convert all the things!
"b8li'
U9gN;|"125:Kb8bl:~f="r  pL|P3{cR`@L1iT"Kb21b"G.HMtNY7VM=BM@$^$dX8a665V"KbFb"=_./ <[(*-oO,\":"f=_"/<[(""\>])"er+4/f=.=7/N*

SE mangles unprintables, so here is a copy on Pastebin. Make sure you copy the "RAW Paste Data" part, not the part next to line numbers. You can try it online, but the permalink may not work in some browsers.
Explanation
The "b8li'U9gN;|"125:Kb8bp part generates the array
[1 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 2 1 3 0 5 4 0 6 6 6 0 5 0 0 7 7 7 0]

which maps each digit of the input to where the digit is used. Anything which is common to all inputs (e.g. leading spaces and ()) is arbitrarily assigned a 0, except the first which is assigned 1 so that base convert can work.
l:~f= then converts each digit to an int and maps accordingly, e.g. for 14441133 we get
[2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 2 4 1 2 1 1 3 3 3 1 2 1 1 4 4 4 1]

"G.HMtNY7VM=BM@$^$dX8a665V"KbFb"=_./ <[(*-oO,\":"f= gives the string
"_=./  /  < /  [<(((((_. _ _     _ __*=._-.oO ,._  \"_ :   : _"

after which we duplicate, replace /<[( with \>]) and append to give a long string. Then we split the string into groups of 4 and map according to another array "r   pL|P3{cR`@L1iT"Kb21b, thus getting an array of length-4 strings describing all possible options at each cell (e.g. _=./ is all possible options for the second character on the second line, starting from the Russian hat).
Finally we map the options to the inputs accordingly .=, split into rows of length 7 7/ and riffle in some newlines N*.
Test runs
11111111

 _===_
 (.,.)
<( : )>
 ( : )

22222222
  ___
 .....
\(o.o)/
 (] [)
 (" ")

33333333
   _
  /_\
 (O_O)
/(> <)\
 (___)

44444444
  ___
 (_*_)
 (- -)
 (   )
 (   )

C, 280 272 264 bytes
Only partially golfed at this point, but this is a fun challenge.
#define P(n)[s[n]&3],
f(char*s){printf("  %.3s\n %.5s\n%c(%c%c%c)%c\n%c(%.3s)%c\n (%.3s)",
"___   ___ _"+*s%4*3,"(_*_)_===_..... /_\\"+*s%4*5,"  \\ "P(4)"-.o0"P(2)
" ,._"P(1)"-.o0"P(3)"  /"P(5)" < /"P(4)"    : ] [> <"+s[6]%4*3," > \\"P(5)
"    : \" \"___"+s[7]%4*3);}

(With some extra \n for readability.) I expect the define should go away with further golfing.
A more readable version is
#define P(n)[s[n]&3],
f(char *s) {
  printf("  %.3s\n"
         " %.5s\n"
         "%c(%c%c%c)%c\n"
         "%c(%.3s)%c\n"
         " (%.3s)",
         "___   ___ _"+*s%4*3,                  /* Top of hat. */
         "(_*_)_===_..... /_\\"+*s%4*5,         /* Lower hat. */
         "  \\ "P(4)                            /* Upper left arm. */
         "-.o0"P(2)                             /* Left eye. */
         " ,._"P(1)                             /* Nose. */
         "-.o0"P(3)                             /* Right eye. */
         "  /"P(5)                              /* Upper right arm. */
         " < /"P(4)                             /* Lower left arm. */
         "    : ] [> <"+s[6]%4*3,               /* Torso. */
         " > \\"P(5)                            /* Lower right arm. */
         "    : \" \"___"+s[7]%4*3              /* Base. */
         );
}

C, 212 bytes
d;main(){char*t="##3#b#b3#bbb3#b#b##\r#3b1#+3@12b3@1b-3@1_b3b1#,#\r7#_##+51rR04/1b#61rR0,8#2##\r7?#2#+9#`A#9=###9#^?#,8A#_#\r#+:#%b#:=#b#:#%b#,#",p[9];for(gets(p);d=*t++;putchar(d-3))d=d<51?d:(p[d-51]-53)[t+=4];}

A readable version:
d;
main()
{
    char *t = "##3#b#b3#bbb3#b#b##\r"
              "#3b1#+3@12b3@1b-3@1_b3b1#,#\r"
              "7#_##+51rR04/1b#61rR0,8#2##\r"
              "7?#2#+9#`A#9=###9#^?#,8A#_#\r"
              "#+:#%b#:=#b#:#%b#,#",
        p[9]; // 9 bytes is just enough for the input string of length 8

    for (gets(p); d = *t++; putchar(d-3))
        d = d < 51 ? d : (p[d - 51] - 53)[t += 4];
}

I took the idea from the answer by Reto Koradi. There were several fun improvements I did, which may warrant posting a separate answer:

Converted from function to program (+10)
Moved newlines into the control string (-7)
Added 3 to all character codes to have fewer escaped chars like \" (-3)
Reading from the string with autoincrement; also replaced t[i++] by *t++ (-4)
Replaced while by for; removed {} (-4)
Simplified loop termination: reading until \0 (-9)
Transformed t[...],t+=4 to (...)[t+=4] to eliminate the comma operator (-1)

Why all that trouble? To share my favorite one, snow ghost:
   _
  /_\
\(. .)/
 (   )
 (___)

Can put d in the parens behind main

JavaScript, 489 (without newlines and tabs)
x=' ';
d="   ";
h=['\n_===_',' ___ \n.....','  _  \n /_\\ ',' ___ \n(_*-)'];
n=[',','.','_',x];
e=['.','o','O','-'];
y=['>',,'\\',x];
u=['<',,'/',x];
t=[' : ','[ ]','> <',d;
b=[' : ','" "',"___",d];

j=process.argv[2].split('').map(function(k){return parseInt(k)-1});
q=j[4]==1;
w=j[5]==1;

console.log([
    h[j[0]].replace(/(.*)\n(.*)/g, " $1\n $2"),
    (q?'\\':x)+'('+e[j[2]]+n[j[1]]+e[j[3]]+')'+(w?'/':x),
    (!q?u[j[4]]:x)+'('+t[j[6]]+')'+(!w?y[j[5]]:x),
    x+'('+b[j[7]]+')'].join('\n'));

run with node snowman.js 33232124

Welcome to Code Golf! A few pointers: You may not need a parseInt call, since subtraction automatically tries to cast string operands to numbers. Also, you can get rid of the function wrapping and just lead with i=process.argv[2], unless you're using it for recursion or variable scoping. Additionally, you can get rid of s entirely and just do console.log([ ... ].join('\n')).

Actually, you could do away with the input string-to-array conversion entirely if you put a leading comma in each of your arrays to increase the index of each item. It adds 7 , characters, but it allows you to remove more than 50. Finally, one very finicky optimization would be using q=j[4]-1 instead of q=j[4]==1 (and then flipping your use of q and !q). This will cause q to be 0 (a falsey value) when j[4] is 1, and otherwise a truthy nonzero value. This is the exact opposite of your current true/false values, so you simply switch q and !q.

Sorry for the mound of feedback on your first answer! I personally find revising my submissions to be one of the most fun parts of golfing; my apologies if you don't share my feeling. :)

@apsillers your feedback is greatly appreciated! I was about to go to sleep last night and then wrote this for fun with the full intention of widding it down to the simplest possible later. I'll be doing some edits tonight!

Pyth, 203 bytes
M@GCHgc"  ___

  ___
   _"bhzgc" (_*_)
 _===_
 .....
  /_\\"bhzs[g"  \ "@z4\(g"-.oO"@z2g" ,._"@z1g"-.oO"@z3\)g"  / "@z5)s[g" < /"@z4\(gc"
 :
] [
> <"b@z6\)g" > \\"@z5)++" ("gc"
 :
\" \"
___"bez\)

Lol. Try it online: Pyth Compiler/Executor
Explanation
First I define a helper function g, which takes a list and a char as input, converts the char into its ASCII-value and takes correspondent element (modular wrapping).
M@GCH  def g(G,H): return G[ord(H)]

The other things is just printing line by line. For instance the first line is:
 c"  ___\n\n  ___\n   _"b     split the string "  ___\n\n  ___\n   _" at "\n"
                         hz   first char in input
g                             apply g and print

Btw. I experimented a little bit with .F"{:^7}", which centers a string. Using it, I could save a few spaces in my code, but it doesn't save any bytes at the end.

R, 436 437 bytes
Here's my first try on code-golf, using R which isn't the shortest but still fun. At least I'm beating JavaScript (for now)...
H=c("_===_"," ___\n .....","  _\n  /_\\"," ___\n (_*_)")
N=c(",",".","_"," ")
L=c(".","o","O","-")
X=c(" ","\\"," "," ")
S=c("<"," ","/"," ")
Y=c(" ","/"," ","")
U=c(">"," ","\\","")
T=c(" : ","] [","> <","   ")
B=c(" : ","\" \"","___","   ")
f=function(x){i=as.integer(strsplit(x,"")[[1]]);cat(" ",H[i[1]],"\n",X[i[5]],"(",L[i[3]],N[i[2]],L[i[4]],")",Y[i[6]],"\n",S[i[5]],"(",T[i[7]],")",U[i[6]],"\n"," (",B[i[8]], ")",sep="")}

Testing:
> f("12344321")
 _===_
 (O.-)
 (] [)\
 ( : )

I actually struggled with X and Y being multilined but with stuff in between, ended up separating each line in (X, S) and (Y, U).
function and conversion from string to integer are also very verbose.
Edit 436 => 437
Had to fix a missing empty space noticed by @OganM
I could reduce to 428 replacing the line breaks between variables with ;, but the "one-lined" code looks so bad and unreadable I won't be that greedy.

you need and extra char for the 4th hat

@OganM Thanks for that extra byte! :( Fixed.

When doing codegolf we generally count each new line as one character (as it is on *nix) as opposed to two (as in Windows). So it shouldn't matter whether you use semicolon or new line.

@ace Thanks for the tip, good to know!

Haskell, 361 306 289 bytes
o l a b=take a$drop((b-1)*a)l
n="\n"
p i=id=<<["  ",o"    \n _===____ \n ..... _  \n  /_\\ ___ \n (_*_)"11a,n,o" \\  "1e,o"(.(o(O(-"2c,o",._ "1 b,o".)o)O)-)"2d,o" /  "1f,n,o"< / "1e,o"( : )(] [)(> <)(   )"5g,o"> \\ "1f,n," (",o" : )\" \")___)   )"4h]where[a,b,c,d,e,f,g,h]=map(read.(:[]))i

Usage:
putStrLn $ p "12333321"

 _===_
 (O.O)
/(] [)\
 ( : )

How it works: index every element of the list of [hat options, left upper arm options, left eye options, ..., base options] with the corresponding input number and concatenate it into a single list. I've split the left and right arm into an upper and lower part, so that I can build the snowman line by line.
My favorite is the classic 11112211.
Edit: switched from list of strings to strings for the parts (hat, eye, ...). Needs a second parameter, the length of the substring to take.
Edit II: extracted common substrings

PowerShell, 199 bytes
Inspired by Reto Koradi and anatolyg.
for($t='  0 _ _0 ___0 _ _
 0_. (0=./_0=._*0=.\_0_. )
4 \  (2.oO-1,._ 3.oO-)5 /
4< / (6 ]> 6:   6 [< )5> \
 (7 "_ 7: _ 7 "_ )';$d=$t[$i++];$r+="$d"){if($d-ge48){$d=$t[$i+"$args"["$d"]-49]
$i+=4}}$r

Try it online!
Note: The line 3 has 2 trail spaces, line 4 has a trail space.
My favorite is 44444444 "sleepy russian guard":
 ___
(_*_)
(- -)
(   )
(   )

Python 3, 349 336 254 251 bytes
So much for doing my thesis.
Here's the content of the file snowman.py:
l='_===_| ___\n .....|  _\n  /_\| ___\n (_*_)| : |] [|> <|   |>| |\| | : |" "|___|   '.split('|')
l[4:4]=' \  .oO-,._ .oO- /  < / '
def s(a):print(' {}\n{}({}{}{}){}\n{}({}){}\n ({})'.format(*[l[4*m+int(a[int('0421354657'[m])])-1]for m in range(10)]))

And this is how I conjure my favourite snowman:
s('11112311')

 _===_
\(.,.)
 ( : )\
 ( : )

Explanation
# Create a list containing the 4 * 10 body parts of the snowman in order of drawing:
#   hats,
#   upper left arms, left eyes, noses, right eyes, upper right arms,
#   lower left arms, torso's, lower right arms,
#   bases
l='_===_| ___\n .....|  _\n  /_\| ___\n (_*_)| : |] [|> <|   |>| |\| | : |" "|___|   '.split('|')
l[4:4]=' \  .oO-,._ .oO- /  < / '
# This is the function that draws the snowman
# All the lines of this function are golfed in a single statement, but seperated here for clearity
def s(a):
    # In this list comprehension I put the elements of l that are chosen according to the parameters
    list_comprehension = []
    # m is the number of the body part to draw
    for m in range(10):
        # Get the index for the choice of the m-th bodypart
        # (example: the 2nd bodypart (m = 1: the upper left arm) is in the 4th place of the arguments list)
        choice_index = int('0421354657'[m])
        # n is the parameter of the current bodypart
        n = int(a[choice_index]) - 1
        # Add the body part from list l to the list comprehenseion
        list_comprehension.append( l[4 * m + n] )
    # Print the list comprehension with the static parts
    print(' {}\n{}({}{}{}){}\n{}({}){}\n ({})'.format(*list_comprehension))

You can remove the space in line 2 between [int(i)] and for. Similarly you can remove the space in line 7 between f(int(i)) and for. Also, in your print() statement you don't need to print the final space - it is not part of the snowman. Finally, change your print() call to a single-line print("{}\n{}({}{}{}){}\n{}({}){}\n ({})".format(*c)). Each of these should save you 1 byte, saving a total of 4 bytes :)

Also, instead of using the global variable n, you can define an attribute of function f. So you can replace lines 5-6 with: def f(m):f.n+=1;return l[4*m+int(b[f.n])-1]  f.n=-1. This reduces 3 more bytes.

@ace Thanks, never heared of the function attribute before, learned something new!

R 414 Bytes
Slightly modified version of Molx's version
W =c("_===_"," ___\n .....","  _\n  /_\\"," ___\n (_*_)",",",".","_"," ",".","o","O","-"," ","\\"," "," ","<"," ","/"," "," ","/"," ","",">"," ","\\",""," : ","] [","> <","   "," : ","\" \"","___","   ")
f=function(x){i=as.integer(strsplit(x,"")[[1]]);cat(" ",W[i[1]],"\n",W[i[5]+12],"(",W[i[3]+8],W[i[2]+4],W[i[4]+8],")",W[i[6]+20],"\n",W[i[5]+16],"(",W[i[7]+28],")",W[i[6]+24],"\n"," (",W[i[8]+32], ")",sep="")}

Just merged the seperate variables into one. Shawing of some space that was used for X=c( routine.

CJam, 200 191 bytes
This can surely be golfed a lot. (Specially if I base encode it). But here goes for starters:
7S*"_===_  ___  .....   _    /_\   ___  (_*_)"+6/2/Nf*",._ "1/".oO-"1/_" <\  /   >/  \  "2/4/~" : ] [> <    : \" \"___   "3/4/~]l~Ab:(]z::=:L0=N4{L=}:K~0='(2K1K3K')5K0=N4K1='(6K')5K1=NS'(7K')

Input goes into STDIN. For example, input 23232223 gives:
  ___
 .....
\(o_O)/
 (] [)
 (___)

Try it online here

C, 233 230 bytes
char*t="  0 _ _0 ___0 _ _   0_. (0=./_0=._*0=.\\_0_. ) 4 \\  (2.oO-1,._ 3.oO-)5 /  4< / (6 ]> 6:   6 [< )5> \\  (7 \"_ 7: _ 7 \"_ ) ";i,r,d;f(char*p){while(r++<35){d=t[i]-48;putchar(t[d<0?i:i+p[d]-48]);i+=d<0?1:5;r%7?0:puts("");}}

With newlines and whitespace for better readability:
char* t = "  0 _ _0 ___0 _ _   0_. (0=./_0=._*0=.\\_0_. ) 4 \\  (2.oO-1,._ 3.oO-)5 /  4< / (6 ]> 6:   6 [< )5> \\  (7 \"_ 7: _ 7 \"_ ) ";
i, r, d;
f(char* p)
{
    while (r++ < 35)
    {
        d = t[i] - 48;
        putchar(t[d < 0 ? i : i + p[d] - 48]);
        i += d < 0 ? 1 : 5;
        r % 7 ? 0 : puts("");
    }
}

The whole thing is fairly brute force. It uses a table that contains one entry for each of the 35 (5 lines with length 7) characters. Each entry in the table is either:

A constant character: , (, ). Length of table entry is 1 character.
Index of body part, followed by the 4 possible characters depending on the part selection in the input. Length of table entry is 5 characters.

The code then loops over the 35 characters, and looks up the value in the table.

Haskell, 333 bytes
My first submission! Builds the snowman from top to bottom, left to right. I split the arms into two functions for each arm, the part next to head and the part next to the body.
The function s takes a list of integers and concatenates the output of the functions which produce the body parts given correct sublists of the input.
a=y["\n _===_\n","  ___ \n .....\n","   _  \n  /_\\ \n","  ___ \n (_*_)\n"]
d=y",._ "
c=y".oO-"
e=y"< / "
j=y" \\  "
f=y"> \\ "
k=y" /  "
y w n=w!!(n-1)
h=y[" : ","] [","> <","   "]
b=y[" ( : ) \n"," (\" \") \n"," (___) \n"," (   ) \n"]
s(m:x:o:p:n:q:t:l:_)=putStr$a m++j x:'(':c o:d n:c p:')':k q:'\n':e x:'(':h t++')':f q:'\n':b l

It relies on the function
y :: [a] -> Int -> a
y w n=w!!(n-1)

which returns the nth element of the list it is given. This allows for the list of hats in a, as well as things like
k=y" /  "

all of these functions use a beta reduction so their argument is passed as the index to the y function.
Output:
λ> s $ repeat 1

 _===_
 (.,.)
<( : )>
 ( : )

λ> s $ repeat 2
  ___
 .....
\(o.o)/
 (] [)
 (" ")

λ> s $ repeat 3
   _
  /_\
 (O_O)
/(> <)\
 (___)

λ> s $ repeat 4
  ___
 (_*_)
 (- -)
 (   )
 (   )

JavaScript (ES6), 247
Not as good ad @NinjaBearMonkey's :(
Test in snippet (with Firefox)

S=p=>([h,n,c,d,l,r,t,b,e,x]=[...p,' .oO-',`1_===_1 ___
 .....1  _
  /_\\1 ___
 (_*_)1 : 1] [1> <1   1 : 1" "1___1   `.split(1)],` ${x[h]}
${'  \\  '[l]}(${e[c]+' ,._ '[n]+e[d]})${'  /  '[r]}
${' < / '[l]}(${x[3-~t]})${' > \\ '[r]}
 (${x[7-~b]})`)

// TEST //

function go()
{
  var n=N.value
  if (/^[1-8]{8}$/.test(n)) {
    s=S(n)
    OUT.innerHTML = s+'\n'+n+'\n\n'+ OUT.innerHTML
  }
  else N.focus()
}

<input id=N maxlength=8><button onclick="go()">Test</button>

05AB1E, 137 135 128 122 121 bytes
…( )7ÝJ»•αγʒδÓ₂©8¥ŽQxΣxêÿ•sÅвJIvN”</[(
._-=:"ÆŸ,*”º•DùÙÂ+;Èγтáì³ÓW©ÎÂ_`ƒ≠îj*ΓçÊ~ÞÒ¸β¦oåb/õ47/vÎΓ”›≠øØZµλÝº•20вè¶¡Nè4äyè.;

-6 bytes thanks to @Grimy.
Try it online or verify a few more test cases.
Explanation:
We first create the template-string:
…( )         # Push string "( )"
7ÝJ          # Push a list in the range [0,7] joined together: "01234567"
»            # Join both by a newline: "( )\n01234567"
•αγʒδÓ₂©2°ćì₂òη₆½•
             # Push compressed integer 80545642885242518310229085147411483894
 s           # Swap to get the earlier created string at the top of the stack
  Åв         # Convert the large integer to base-"( )\n01234567",
             # which basically converts to base-length, and indexes into the string:
             #  [" ","0","0","0","0","0","\n"," ","0","0","0","0","0","\n","4","(","2","1","3",")","5","\n","4","(","6","6","6",")","5","\n"," ","(","7","7","7",")"]
    J        # And join it to a single string: " 00000\n 00000\n4(213)5\n4(666)5\n (777)"

Which looks like this:
 00000
 00000
4(213)5
4(666)5
 (777)

Then I loop over the digits of the input:
I            # Get the input
 v           # Loop `y` over each of its digits:

And do the following:
Push the (0-indexed) index N of the list:
  N          # Push the index of the loop

Push all possible parts as a list of character lists:
  ”</[(
  ._-=:"ÆŸ,*”
            "# Push dictionary string "</[(\n._-=:" Oo,*"
   º         # Mirror each line: "</[()]\>\n._-=:" Oo,**,oO ":=-_."
  •DùÙÂ+;Èγтáì³ÓW©ÎÂ_`ƒ≠îj*ΓçÊ~ÞÒ¸β¦oåb/õ47/vÎΓ”›≠øØZµλÝº•
             # Push compressed integer 492049509496347122906361438631265789982480759119518961177677313610613993948059787418619722816092858096158180892708001681647316210
   20в       # Convert it to Base-20 as list: [15,10,10,10,15,3,10,19,10,4,15,15,15,15,15,10,12,12,12,10,15,10,10,10,15,9,9,9,9,9,15,15,10,15,15,15,1,10,6,15,8,15,18,9,10,8,11,9,17,16,8,11,9,17,16,8,15,15,15,0,6,15,15,1,8,15,15,15,7,1,15,15,6,8,15,15,15,15,13,15,5,15,2,7,15,0,8,15,15,15,15,13,15,14,15,14,10,10,10]
      è      # Index each into the string: [" ","_","_","_"," ","(","_","*","_",")"," "," "," "," "," ","_","=","=","=","_"," ","_","_","_"," ",".",".",".",".","."," "," ","_"," "," "," ","/","_","\"," ","\n"," ",",",".","_","\n","-",".","o","O","\n","-",".","o","O","\n"," "," "," ","<","\"," "," ","/","\n"," "," "," ",">","/"," "," ","\","\n"," "," "," "," ",":"," ","]"," ","[",">"," ","<","\n"," "," "," "," ",":"," ","""," ",""","_","_","_"]
       ¶¡    # Split it by the newline character: [[" ","_","_","_"," ","(","_","*","_",")"," "," "," "," "," ","_","=","=","=","_"," ","_","_","_"," ",".",".",".",".","."," "," ","_"," "," "," ","/","_","\"," "],[" ",",",".","_"],["-",".","o","O"],["-",".","o","O"],[" "," "," ","<","\"," "," ","/"],[" "," "," ",">","/"," "," ","\"],[" "," "," "," ",":"," ","]"," ","[",">"," ","<"],[" "," "," "," ",":"," ","""," ",""","_","_","_"]]

Use the loop index N to get the character-list of the part we are currently working with:
  Nè         # Index the loop index into it
             #  i.e. 6 → [" "," "," "," ",":"," ","]"," ","[",">"," ","<"]

Then split the character list into four equal part, and use the input-digit y (which is 1-indexed) to index into it. (NOTE: Since 05AB1E is 0-indexed, but the input is 1-indexed, it would be logical to decrease the digit by 1 before indexing. However, since 05AB1E has automatic wraparound (i.e. indexing 3 in list [1,3,5] will result in 1), I simply rotated the parts once so parts with nr 4 in the challenge description, are at the front of the lists.)
    4ä       # Split it into 4 equal parts
             #  i.e. [[" "," "," "],[" ",":"," "],["]"," ","["],[">"," ","<"]]
      yè     # Index the input-digit `y` into it (with automatic wraparound)
             #  i.e. 4 → [" "," "," "]

And then replace the 0-indexed index of the loop we pushed at first, one by one with the part-characters:
  .;         # Replace first; every index of the loop `N` in the template-string
             # is replaced one by one with the characters

And in the end the result is output implicitly.
See this 05AB1E tip of mine (section How to compress large integers? and How to compress integer lists?) to understand how the compression parts work.

As for my favorite, it's still the same 'snow rabbit' as 1.5 year ago when I posted my Java solution:
44114432:
   _
 (_*_)
 (. .)
 (> <)
 (" ")

-4, just enough to beat CJam!

Down to 122, and also closer to what you originally had.

@Grimy Your 122 byte version has a 0 between its eyes. :)

Just a base-12 encoding mistake, should be easy enough to fix!

@Grimy You're right. I didn't had a lot of time yesterday, but it's indeed a simple fix in the list. Thanks for the -6! :)

Java 8, 548 545 432 401 399 397 bytes
a->{int q=50,H=a[0]-49,N=a[1],L=a[2],R=a[3],X=a[4],Y=a[5];return"".format(" %s%n %s%n%c(%c%c%c)%c%n%c(%s)%c%n (%s)",H<1?"":H%2<1?" ___":"  _","_===_s.....s /_\\s(_*_)".split("s")[H],X==q?92:32,L<q?46:L<51?111:L<52?79:45,N<q?44:N<51?46:N<52?95:32,R<q?46:R<51?111:R<52?79:45,Y==q?47:32,X<q?60:32+X%2*15,"   s : s] [s> <".split("s")[a[6]%4],92-(Y%3+Y%6/4)*30,"   s : s\" \"s___".split("s")[a[7]%4]);}

-2 bytes thanks to @ceilingcat.
Try it here.
Explanation:
a->{             // Method with character-array parameter and String return-type
  int q=50,      //  Temp integer with value 50 to reduce the byte-count
      H=a[0]-49, //  The hat-character as unicode value minus 49: 1=0; 2=1; 3=2; 4=3
      N=a[1],L=a[2],R=a[3],X=a[4],Y=a[5];
                 //  Most of the other characters as unicode values: 1=49; 2=50; 3=51; 4=52
  return"".format(" %s%n %s%n%c(%c%c%c)%c%n%c(%s)%c%n (%s)",
                                               // Return the snowman with:
    H<1?"":H%2<1?" ___":"  _",                 //  The top of the hat
    "_===_s.....s /_\\s(_*_)".split("s")[H],   //  + the bottom of the hat
    X==q?92:32,                                //  + the top of the left arm
    L<q?46:L<51?111:L<52?79:45,                //  + the left eye
    N<q?44:N<51?46:N<52?95:32,                 //  + the nose
    R<q?46:R<51?111:R<52?79:45,                //  + the right eye
    Y==q?47:32,                                //  + the top of the right arm
    X<q?60:32+X%2*15,                          //  + the bottom of the left arm
    "   s : s] [s> <".split("s")[a[6]%4],      //  + the torso
    92-(Y%3+Y%6/4)*30,                         //  + the bottom of the right arm
    "   s : s\" \"s___".split("s")[a[7]%4]);}  //  + the feet

My favorite:
44114432:
   _
 (_*_)
 (. .)
 (> <)
 (" ")

I don't know why, but it looks kinda cute. Like a bunny with a Russian hat instead of ears.

C# 9.0 (.NET 4.8) - 1813 1803 1821 1815 1812+30=1843 1833 1851 1845 1842 bytes
A Windows Forms application; likely can be improved on in terms of size. Contains a massive one-liner. The extra 30 bytes is from adding <LangVersion>9.0</LangVersion> to the project file.
using System;using System.Windows.Forms;class P:Form{string[]h={$@"
_===_",$@"___
.....",$@"_
/_\",$@"___
(_*_)"},s={" : ","] [","> <","   "},z={" : ","\" \"","___","   "};string n=",._ ",e=".oO-",x="< / ",y="> \\ ";TextBox t;Button b,d;Label l;[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new P());}P(){t=new();b=new();d=new();l=new();SuspendLayout();t.Location=new(0,0);t.MaxLength=8;t.Size=new(269,23);t.TabIndex=0;b.Location=new(-1,22);b.Size=new(200,25);b.TabIndex=1;b.Text="Build the snowman!";b.UseVisualStyleBackColor=true;b.Click+=m;d.Location=new(198,22);d.Size=new(72,25);d.TabIndex=2;d.Text="Random";d.UseVisualStyleBackColor=true;d.Click+=(_,_)=>{int a=0;Random r=new();for(int i=0;i<8;i++)a+=r.Next(1,5)*(int)Math.Pow(10,i);m(a.ToString(),null);};l.AutoSize=false;l.Font=new("Consolas",9);l.Location=new(0,41);l.Size=new(269,73);l.TextAlign=System.Drawing.ContentAlignment.MiddleCenter;Font=new("Segoe UI",9);ClientSize=new(269,114);Controls.Add(l);Controls.Add(t);Controls.Add(b);Controls.Add(d);MaximizeBox=false;FormBorderStyle=FormBorderStyle.FixedSingle;Text="Snowman Maker";l.SendToBack();t.BringToFront();ResumeLayout(true);}void m(object q,EventArgs k){t.Enabled=false;b.Enabled=false;d.Enabled=false;if(q is string j)t.Text=j;if(t.Text.Length!=8||!int.TryParse(t.Text,out _))MessageBox.Show("Invalid input format.");else{int[]a=new int[8];for(int i=0;i<8;i++){a[i]=t.Text[i]-'0'-1;if(a[i]>3){MessageBox.Show("Invalid input format.");t.Enabled=true;b.Enabled=true;d.Enabled=true;return;}}l.Text=$@"{h[a[0]]}
{(a[4]==1?'\\':' ')}({e[a[2]]}{n[a[1]]}{e[a[3]]}){(a[5]==1?'/':' ')}
{x[a[4]]}({s[a[6]]}){y[a[5]]}
({z[a[7]]})";}t.Enabled=true;b.Enabled=true;d.Enabled=true;}}

A more readable version, with comments (though with the same confusing variable naming):
using System;
using System.Windows.Forms;
class Program : Form
{
    string[] h = {$@"
_===_",$@"___
.....",$@"_
/_\",$@"___
(_*_)"}, // Hats
    s = {" : ","] [","> <","   "}, // Torso
    z = {" : ","\" \"","___","   "}; // Base
    string n = ",._ ", e = ".oO-", x = "< / ", y = "> \\ "; // Nose, eyes, left arm, right arm
    //Controls
    TextBox t;
    Button b, d;
    Label l;
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Program()); // I put all the control code in Program; please don't do this in normal code
    }
    Program()
    {
        // Initialize everything
        t = new(); // Taking advantage of the short contructors in C# 9.0
        b = new();
        d = new();
        l = new();
        SuspendLayout();
        // TextBox properties
        t.Location = new(0, 0);
        t.MaxLength = 8;
        t.Size = new(269, 23);
        t.TabIndex = 0;
        // 'Build the snowman' button properties
        b.Location = new(-1, 22);
        b.Size = new(200, 25);
        b.TabIndex = 1;
        b.Text = "Build the snowman!";
        b.UseVisualStyleBackColor = true;
        b.Click += m;
        // 'Random' button properties
        d.Location = new(198,22);
        d.Size = new(72,25);
        d.TabIndex = 2;
        d.Text = "Random";
        d.UseVisualStyleBackColor = true;
        d.Click += (_,_) =>
        {
            int a = 0;
            Random r = new();
            for(int i = 0; i < 8; i++)
                a += r.Next(1,5) * (int)Math.Pow(10,i); // Math.Pow returns a number that satisfies 1 <= n < 5, not 1 <= n <= 5
            m(a.ToString(), null); // Since I don't need the "sender" field, I use it to send the random input. Please don't do this in a normal program.
        };
        // Label properties
        l.AutoSize = false;
        l.Font = new("Consolas", 9);
        l.Location = new(0, 41);
        l.Size = new(269, 73);
        l.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // This lets us omit some spaces, while making the form look nicer as well
        // Form properties
        Font = new("Segoe UI", 9);
        ClientSize = new(269, 114);
        Controls.Add(l);
        Controls.Add(t);
        Controls.Add(b);
        Controls.Add(d);
        MaximizeBox = false;
        FormBorderStyle=FormBorderStyle.FixedSingle;
        Text="Snowman Maker";
        l.SendToBack();
        t.BringToFront();
        ResumeLayout(true);
    }
    // Event handler for the 'Build the snowman' button
    void m(object sender, EventArgs k)
    {
        // Disable all the inputs, in case the user tries to mess with the data while the function is running.
        // This is probably unneeded since modern computers run so quickly, but I kept it anyway.
        t.Enabled = false;
        b.Enabled = false;
        d.Enabled = false;
        if(sender is string j) // Accept input from 'Random' button
            t.Text=j;
        if(t.Text.Length != 8|| !int.TryParse(t.Text, out _)) // Discard the out parameter since we don't need it
            MessageBox.Show("Invalid input format.");
        else
        {
            int[] a = new int[8];
            // Read from the TextBox.
            for (int i = 0; i < 8; i++)
            {
                a[i] = t.Text[i] - '0' - 1;
                if(a[i] > 3)
                {
                    MessageBox.Show("Invalid input format.");
                    // Re-enable the inputs and cancel the operation.
                    t.Enabled = true;
                    b.Enabled = true;
                    d.Enabled = true;
                    return;
                }
            }
            // Set the label text; uses an interpolated multiline string ($ makes it interpolated, @ makes it accept newlines and automatically escape characters (excluding " ))
            l.Text=$@"{h[a[0]]}
{((a[4] == 1) ? '\\' : ' ')}({e[a[2]]}{n[a[1]]}{e[a[3]]}){((a[5] == 1) ? '/' : ' ')}
{x[a[4]]}({s[a[6]]}){y[a[5]]}
({z[a[7]]})";
        }
        t.Enabled = true;
        b.Enabled = true;
        d.Enabled = true;
    }
}

The compact version was so painful to edit (I absolutely hate scrolling left and right) that I split it into a lot of lines and removed the unnecessary newlines after I was done with it:
using System;using System.Windows.Forms;class P:Form{string[]h={$@"
_===_",$@"___
.....",$@"_
/_\",$@"___
(_*_)"},s={" : ","] [","> <","   "},z={" : ","\" \"","___","   "};string n=",._ ",e=".oO-",x="< / ",y="> \\ ";TextBox t;
Button b,d;Label l;[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new P());}P(){t=new();b=new();d=new();l=new();SuspendLayout();t.Location=new(0,0);t.MaxLength=8;t.Size=new(269,23
);t.TabIndex=0;b.Location=new(-1,22);b.Size=new(200,25);b.TabIndex=1;b.Text="Build the snowman!";b.UseVisualStyleBackColor=true;b.Click+=m;d.
Location=new(198,22);d.Size=new(72,25);d.TabIndex=2;d.Text="Random";d.UseVisualStyleBackColor=true;d.Click+=(_,_)=>{int a=0;Random r=new();
for(int i=0;i<8;i++)a+=r.Next(1,5)*(int)Math.Pow(10,i);m(a.ToString(),null);};l.AutoSize=false;l.Font=new("Consolas",9);l.Location=new(0,41);
l.Size=new(269,73);l.TextAlign=System.Drawing.ContentAlignment.MiddleCenter;Font=new("Segoe UI",9);ClientSize=new(269,114);Controls.Add(l);
Controls.Add(t);Controls.Add(b);Controls.Add(d);FormBorderStyle=FormBorderStyle.FixedSingle;MaximizeBox=false;Text="Snowman Maker";l.
SendToBack();t.BringToFront();ResumeLayout(true);}void m(object q,EventArgs k){t.Enabled=false;b.Enabled=false;d.Enabled=false;if(q is string
j)t.Text=j;if(t.Text.Length!=8||!int.TryParse(t.Text,out _))MessageBox.Show("Invalid input format.");else{int[]a=new int[8];for(int i=0;i<8;
i++){a[i]=t.Text[i]-'0'-1;if(a[i]>3){MessageBox.Show("Invalid input format.");t.Enabled=true;b.Enabled=true;d.Enabled=true;return;}}l.Text=$@"{h[a[0]]}
{(a[4]==1?'\\':' ')}({e[a[2]]}{n[a[1]]}{e[a[3]]}){(a[5]==1?'/':' ')}
{x[a[4]]}({s[a[6]]}){y[a[5]]}
({z[a[7]]})";}t.Enabled=true;b.Enabled=true;d.Enabled=true;}}

To run this code, make a Windows Forms Application project in Visual Studio for .NET Framework 4.8 (or whatever editor you use for C#), remove Form1.cs and delete it from the project, save the project, and add <LangVersion>9.0</LangVersion> to the project file. Then, you can copy the code into Program.cs (overwrite everything) and run it.

F#, 369 bytes
let f(g:string)=
 let b=" "
 let p=printfn
 let i x=int(g.[x])-49
 p"  %s  "["";"___";" _ ";"___"].[i 0]
 p" %s "["_===_";".....";" /_\ ";"(_*_)"].[i 0]
 p"%s(%c%c%c)%s"[b;"\\";b;b].[i 4]".oO-".[i 2]",._ ".[i 1]".oO-".[i 3][b;"/";b;b;b].[i 5]
 p"%s(%s)%s"["<";b;"/";b].[i 4][" : ";"] [";"> <";"   "].[i 6][">";b;"\\";b].[i 5]
 p" (%s) "[" : ";"\" \"";"___";"   "].[i 7]

Try it online!
Because g uses an array accessor, I need to explicitly specify the type in the function definition as a string, which is why the function definition has (g:string).
Apart from that, it's usually an array of strings accessed by an index. The hat, left and right arms which would go on separate lines are split into separate top and bottom arrays. The i function changes a number in the argument g into the array index. And the letter b replaces the one-space strings in the arrays.
Great challenge! My favourite snowman is probably 242244113:
  ___
 .....
 (o o)
 ( : )
 ( : )

im watching you

PHP, 378 bytes
<?$f=str_split;$r=$f($argv[1]);$p=[H=>'   _===____..... _  /_\ ___(_*_)',N=>',._ ',L=>'.oO-',R=>'.oO-',X=>' <\  /  ',Y=>' >/  \  ',T=>' : ] [> <   ',B=>' : " "___   '];echo preg_replace_callback("/[A-Z]/",function($m){global$A,$p,$r,$f;$g=$m[0];return$f($f($p[$g],strlen($p[$g])/4)[$r[array_search($g,array_keys($p))]-1])[(int)$A[$g]++];},'  HHH
 HHHHH
X(LNR)Y
X(TTT)Y
 (BBB)');

Try it online!
I like wise Mr. Owl 31333342
   _
  /_\
 (O,O)
/(   )\
 (" ")

Python 2.7, 257 bytes (i think)
H,N,L,R,X,Y,T,B=map(int,i)
l='\n'
s=' '
e=' .o0-'
F='  \  / '
S=' < / \ >'
o,c='()'
print s+'      _ _ ___ _ _\n\n\n\n    _. (=./_=._*=.\__. )'[H::4]+l+F[X]+o+e[L]+' ,._ '[N]+e[R]+c+F[-Y]+l+S[X]+o+'  ]> :    [< '[T::4]+c+S[-Y]+l+s+o+'  "_ : _  "_ '[B::4]+c

where 'i' is the input as an string (e.g "13243213")

Welcome to PPCG! As it happens, it is 256 bytes. Unfortunately, you cannot assume the input is stored in a variable. You can however replace i for input() for a total of 262 bytes

Clojure (407 402 bytes)
(defn a[s](let[[H N L R X Y T B](into[](map #(-(int %)49)(into[]s)))h(["""  ___""   _""  ___"]H)i([" _===_"" .....""  /_\\"" (_*_)"]H)n([","".""_"" "]N)e[".""o""O""-"]l([" ""\\"" "" "]X)m(["<"" ""/"" "]X)r(["""/"""""]Y)u([">""""\\"""]Y)t([" : ""] [""> <""   "]T)b([" : ""   ""___""   "]B)d(["""\" \""""""]B)f(str \newline)](str h f i f l "(" (e L) n (e R) ")" r f m "(" t ")" u f " (" b ")" f "  " d)))

Hopefully that's clear to everyone.
And if not...
Ungolfed version:
(defn build-a-snowman [s]
  (let [ [H N L R X Y T B] (into [] (map #(- (int %) 49) (into [] s)))
         hat1     ([""       "  ___"  "   _"   "  ___" ] H) ; first line of hats
         hat2     ([" _===_" " ....." "  /_\\" " (_*_)"] H) ; second line of hats
         nose     ([","      "."      "_"      " "     ] N)
         eye      ["."      "o"      "O"      "-"     ]
         left1    ([" "      "\\"     " "      " "     ] X) ; left arm, upper position
         left2    (["<"      " "      "/"      " "     ] X) ; left arm, lower position
         right1   ([""       "/"      ""       ""      ] Y) ; right arm, upper position
         right2   ([">"      ""       "\\"     ""      ] Y) ; right arm, lower position
         torso    ([" : "    "] ["    "> <"    "   "   ] T)
         base1    ([" : "    "   "    "___"    "   "   ] B) ; first line of base
         base2    ([""       "\" \""  ""       ""      ] B) ; second line of base
         nl       (str \newline) ]
    (str hat1 nl
         hat2 nl
         left1 "(" (eye L) nose (eye R) ")" right1 nl
         left2 "(" torso ")" right2 nl
         " (" base1 ")" nl
         "  " base2)))

Tests:
(println (a "33232124"))  ; waving guy with fez
(println (a "11114411"))  ; simple ASCII-art snowman
(println (a "34334442"))  ; mouse
(println (a "41214433"))  ; commissar with monocle
(println (a "41212243"))  ; commissar celebrating success of five-year plan
(println (a "41232243"))  ; commissar after too much vodka

My favorite:
34334442 - mouse
Try it online!

Dart, 307 bytes
f(i,{r='.o0-',s=' : '}){i=i.split('').map((j)=>int.parse(j)-1).toList();return' ${['_===_',' ___ \n.....',' /_\\ ',' ___ \n (_*_)'][i[0]]}\n${' \\  '[i[4]]}(${r[i[2]]+',._ '[i[1]]+r[i[3]]})${' /  '[i[5]]}\n${'< /  '[i[4]]}(${[s,'] [','> <','  '][i[6]]})${'> \\ '[i[5]]}\n (${[s,'" "','___','   '][i[7]]})';}

Try it online!

Zsh, 247 bytes
try it online!!
(){H='_===_h ___
 .....h  _
  /_\h ___
 (_*_)'
W=' \  ' L=.oO- N=,._\  Y=' /  '
X='< / ' T=' : ] [> <   ' Z='> \ '
B=' : " "___   '
<<<" ${H[(ws:h:)$1]}
$W[$5]($L[$3]$N[$2]$L[$4])$Y[$6]
$X[$5](${T:3*($7-1):3})$Z[$6]
 (${B:3*($8-1):3})"
} ${(s::)1}

fav snowman:
43232122 Cossack dancer
  ___
 (_*_)
\(o_O)
 (] [)>
 (" ")

authors: Bob Jarvis - Слава Україні

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/