简体   繁体   中英

generating TTT game tree in lua

I am attempting to write a tic-tac-toe game in lua, and plan on using the minimax algorithm to decide non-human moves. The first step in this involves generating a tree of all possible board states from a single input state. I am trying to recursively do this, but cannot seem to figure out how. (I think) I understand conceptually how this should be done, but am having trouble implementing it in lua.

I am trying to structure my tree in the following manner. Each node is a list with two fields.

{ config = {}, children = {} }

Config is a list of integers (0,1,2) that represent empty, X, and O and defines a TTT board state. Children is a list nodes which are all possible board states one move away from the current node.

Here is my function that I currently have to build the game tree

function tree_builder(board, player)
    supertemp = {}

    for i in ipairs(board.config) do

        --iterate through the current board state. 
        --for each empty location create a new node 
        --representing a possible board state

        if board.config[i] == 0 then
            temp = {config = {}, children = {}}

            for j in ipairs(board.config) do
                temp.config[j] = board.config[j]
            end

        temp.config[i] = player
        temp.children = tree_builder(temp, opposite(player))
        supertemp[i] = temp
        end

    end
    return supertemp
end

The function is called in the following manner:

start_board = {config = {1,0,0,0}, children = {} }
start_board.children = tree_builder(start_board, 1)

When I comment out the recursive element of the function (the line "temp.children = builder(temp, opposite(player))") and only generate the first level of children. the output is correct. When called via code that is conceptually identical to (I am using love2D so formatting is different):

for i in pairs(start_board.children) do
    print (start_board.children[i].config)

The three children are:

1,1,0,0
1,0,1,0
1,0,0,1

However, once I add the recursive element, the following is output for the same three children

1,1,2,1
1,1,2,1
1,1,2,1

I have been searching online for help and most of what I have found is conceptual in nature or involves implementation in different languages. I believe I have implemented the recursive element wrongly, but cannot wrap my head around the reasons why.

Don't understand what opposite(player) means in temp.children = tree_builder(temp, opposite(player)) .

Notice that a recursion need an end condition.

This is my solution under your structure:

local COL = 3
local ROW = 3   

local function printBoard( b )
    local output = ""
    local i = 1
    for _,v in ipairs(b.config) do
        output = output .. v .. ( (i % COL == 0) and '\n' or ',' )
        i = i + 1
    end
    print( output )
end 

local function shallowCopy( t )
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end 

local MAX_STEP = COL * ROW  

local ING = 0
local P1 = 1
local P2 = 2
local TIE = 3   

local STATUS = { [P1] = "P1 Win", [P2] = "P2 Win", [TIE] = "Tied" } 

local start_board = { config = {P1,0,0,0,0,0,0,0,0}, children = {} }    

local function checkIfOver( board, step )
    local config = board.config
    local over = false
    --check rows
    for i=0,ROW-1 do
        over = true
        for j=1,COL do
            if 0 == config[i*COL+1] or config[i*COL+j] ~= config[i*COL+1] then
                over = false
            end
        end
        if over then
            return config[i*COL+1]
        end
    end
    --check cols
    for i=1,COL do
        over = true
        for j=0,ROW-1 do
            if 0 == config[i] or config[i] ~= config[i+COL*j] then
                over = false
            end
        end
        if over then
            return config[i]
        end
    end
    --check diagonals
    if config[1] ~= 0 and config[1] == config[5] and config[5] == config[9] then
        return config[1]
    end
    if config[3] ~=0 and config[3] == config[5] and config[5] == config[7] then
        return config[3]
    end
    if step >= MAX_STEP then    
        return TIE
    else
        return ING
    end
end 

local function treeBuilder( board, step )
    --check the game is over
    local over = checkIfOver( board, step )
    if  over ~= ING then
        printBoard( board )
        print( STATUS[over], '\n---------\n' )
        return
    end
    local child
    local childCfg
    for i,v in ipairs(board.config) do
        if 0 == v then
            child = { config = {}, children = {} }
            childCfg = shallowCopy( board.config )
            childCfg[i] = (step % 2 == 0) and P1 or P2 
            child.config = childCfg
            table.insert( board.children, child )
            treeBuilder( child, step + 1 )
        end
    end
end 

treeBuilder( start_board, 1 )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM