Can you win with two more moves at Three Men's Morris?

C# - 739 663 bytes

Complete program, reads input from argv, and appears to work. Run it like

ThreeMill 1 2 1 1 2 0 0 0 2

If this method of input is unacceptable, I'll be glad to change it (never like using argv).

using System;using System.Linq;class P{static void Main(string[]A){var I=new[]{0,3,6,1,4,7,2,5,8};Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" ";Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0;Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I.Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))).Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;})).DefaultIfEmpty(B).ToArray();int h,G;Console.WriteLine(":"+"(|))"[V(A,"1").Max(z=>((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0)+(h>G?W(z,"1")*2:2))]);}}

I was disinclined to post this yesterday, because I've not been able to golf it down much (not had all that much time, and I might be out of practice), but since there hasn't been a response yet, I'll post it anyway, I certainly don't expect the bounty, I'd rather it went to someone who's put a bit more effort into theirs before posting!

Edit: replaced all the bools with ints, which meant I could make better use of Linq, and managed to collapse both foreach loops, giving big savings. I am slightly amazed that the h counter works... ++ is such a subtle utility.

The program is very simple, it just explores every possible set of moves (stores board state in a string[]). It iterates over all of our possible moves (the boards that result thereof), and counts the number of responses by our opponent that we can successful beat (G) (i.e. those that we win, and he doesn't). It also counts the number of possible responses (h). If we can win any, then it's a possible, and we add 1 to the sum, if we can win them all, it's a definite, and we add 2 to the sum. The maximum some is therefore our best possible outcome, and we index into the string "(|))" to return the appropriate face. Note that we need the extra ")" because the sum can be 2 or 3 if it's a definite (it's possible that we don't appear to be able to beat any responses having already won on the first go, so the possible check is a tad misleading).

The program checks for a victory by producing a string from the board, that is space-separated rows and columns, and just looks for a string of 3 of the player's character in this string (e.g. "201 201 021 220 002 111 " is a win for us)

using System;
using System.Linq; // all important

class P
{
    static void Main(string[]A) // transform to int?
    {
        var I=new[]{0,3,6,1,4,7,2,5,8}; // vertical indexes
        Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" "; // joins the strings up, so that there is a space separating each group of three (including at end)
        Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0; // checks if a particular player wins
        Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I // for each imagineable move
            .Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))) // where it's legal
            .Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;}) // select the resulting board
        ).DefaultIfEmpty(B) // allow not-moving
        .ToArray();

        int h, // h stores the number of responses the opponent has to each move
        G; // G stores the number of responses by the opponent we can beat

        Console.WriteLine(":"+"(|))"[ // we index into this to decide which smiley
            V(A,"1").Max(z=>
                    ((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0) // if there is atleast 1 reponse by the opponent we can beat, we can possibly win
                    +(h>G?W(z,"1")*2:2) // if there are moves which we can't win, then if we have already won (one-move), else, we can definitely win
                   ) // sum is therefore 0 if impossible, 1 if possible, >2 (no more than 3) if definite 
            ]);

    }
}

Here is my test script:

ThreeMill 2 1 0 2 1 2 0 0 1
ThreeMill 2 1 0 0 1 0 2 2 1
ThreeMill 1 0 1 1 0 2 0 2 2
ThreeMill 1 2 2 2 1 0 0 0 1

ThreeMill 1 0 1 1 2 2 2 0 0
ThreeMill 1 0 1 1 2 0 2 0 2
ThreeMill 1 2 2 0 0 1 2 1 0

ThreeMill 1 0 0 1 2 2 2 0 1
ThreeMill 1 2 1 1 2 0 0 0 2
ThreeMill 1 0 1 2 0 2 1 0 2

Which outputs

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)