Comments

Log in with itch.io to leave a comment.

While we're posting code, here's one I've conjectured to always work:

def loses(triplet):
     c,b,a = sorted(triplet); mod = 1
     if (a,b,c) == (a,a,(0 if a==1 else a)): return True
     while c >= mod//2:
         if (b%mod,c%mod,(b//mod)&~(b//mod+c//mod)) == (mod//2,mod//2,0): return a == b + c + (1 - mod//2 if mod > 1 else 2)
         mod *= 2
     return a == b + c + 1
def move(triplet): #example input: move((99,100,101))
     if loses(triplet): print(triplet,"loses"); return
     a,b,c = triplet
     for trip in [(i,b,c) for i in range(a)]+[(a,j,c) for j in range(b)]+[(a,b,k) for k in range(c)]:
         if loses(trip): print(trip)
(1 edit)

Here's my code too. It lists only winning positions on the left and the two positions to the right are the moves you should make in case one gets rejected.

from functools import cache
@cache
def is_winnable(pos):
    if sum(pos) == 0:
        return False
    elif sum(pos) == 1:
        return True
    lose_psns = []
    for i in range(len(pos)):
        for dots in range(pos[i]):
            child_pos = tuple(sorted(pos[:i] + (dots,) + pos[i+1:], reverse=True))
            if not is_winnable(child_pos):
                lose_psns.append(child_pos)
                if len(lose_psns) >= 2:
                    print(pos, lose_psns)
                    return True
    return False
for a in range(6):
    for b in range(6):
        for c in range(6):
            is_winnable(tuple(sorted((a, b, c), reverse=True)))
(+2)(-1)

#Here's my code to calculate all must-win or must-lose 

#forms in 3d.

set_lose={(0,0,0)}

set_win={(0,1,0),(1,0,0),(0,0,1)}

limit=5

def add_win(i,j,k):

    set_win.add((i,j,k))

    set_win.add((i,k,j))

    set_win.add((k,i,j))

    set_win.add((k,j,i))

    set_win.add((j,i,k))

    set_win.add((j,k,i))

def have_common(a,b):

    if a[0]==b[0]:

        if a[1]==b[1]:

            for i in range(max(a[2],b[2])+1,limit+1):

                add_win(a[0],a[1],i)

        elif a[2]==b[2]:

            for i in range(max(a[1],b[1])+1,limit+1):

                add_win(a[0],i,a[2])

        else:

            if (a[1]>b[1]) and (a[2]<b[2]):

                add_win(a[0],a[1],b[2])

            if(a[1]<b[1]) and (a[2]>b[2]):

                add_win(a[0],b[1],a[2])

    elif a[1]==b[1]:

        if a[2]==b[2]:

            for i in range(max(a[0],b[0])+1,limit+1):

                add_win(i,a[1],a[2])

        else:

            if(a[0]>b[0]) and (a[2]<b[2]):

                add_win(a[0],a[1],b[2])

            if(a[0]<b[0]) and(a[2]>b[2]):

                add_win(b[0],a[1],a[2])

    elif a[2]==b[2]:

        if(a[0]>b[0]) and (a[1]<b[1]):

            add_win(a[0],b[1],a[2])

        if(a[0]<b[0]) and (a[1]>b[1]):

            add_win(b[0],a[1],a[2])

def xinzeng(dot):

    for i in set_lose:

        have_common(i,dot)

for i in range(0,limit+1):

    for j in range(0,limit+1):

        for k in range(0,limit+1):

            dot=(i,j,k)

            if (dot not in set_win)and(dot not in set_lose):

                # print(i,j,k)

                xinzeng(dot)

                set_lose.add(dot)

print(len(set_lose))

for i in set_lose:

    print(i)