Ludo

This is a well known multiplayer board game. Can be played from 2 to 4 players. Rules are as follows:

  1. At the start of the game, the player’s four pieces are placed in the start area of their colour.

  2. Players take it in turn to throw a die. A player must first throw a six to be able to move piece from the starting area onto the starting square.

  3. In each subsequent turn the player moves a piece forward 1 to 6 squares as indicated by the die.

  4. When a player throws a 6 the player may bring a new piece onto the starting square, or may choose to move a piece already in play.

  5. The player is also granted another turn as a bonus, but if a 6 is rolled three times in a row it is counted as a foul and the player therefore loses their turn.

  6. If a player’s piece lands on a square containing an opponent’s piece, the opponent’s piece is captured and returns to the starting area. A piece may not land on a square that already contains a piece of the same colour.

  7. Once a piece has completed a circuit of the board it moves up the home column of its own colour. The player must throw the exact number to advance to the home square. The winner is the first to get all four of their pieces onto the home square.

Here is the link for the demo:
http://youtu.be/ZMQKLykfHhw

I have used a customized sprite for the dice. I am not sure how to upload that sprite pack (Dice.spritepack) to this site. Once downloaded It can be copied to User Applications/Codea/SpritePacks/. i used “i-FunBox” for windows to access file system.

I will post the code as well soon.

Here is the code.

Main



-- Use this function to perform your initial setup
function setup()
    supportedOrientations(LANDSCAPE_ANY)
    displayMode(FULLSCREEN)
    board = Board()
    menu = Menu()
    dice = Dice()
    activePlayer = red
    the3DViewMatrix = viewMatrix()
    tok =nil
    
    numberOfPlayer = 0
    Angle = 0
    Size = 50
    currentRoll = 0
    currentPlayer = 0
    numberOfMove = 1
    players = {1,2,3,4}
    allTokensTried = 0
    occupiedToken = 0
    sixCount = 0
    win = 1
    
   
    flag = false
    face = false
    menuFlag = true
    redFlag = false
    greenFlag = false
    blueFlag = false
    yellowFlag = false
    diceRolled = false
    moveFlag = false
    gameOver = false
    
    
    menu:onEnter()
    
    gameMsg = ""
    gameOverMsg = ""
    inGameMsg = ""
    winMsg1 = ""
    winMsg2 = ""
    winMsg3 = ""
    winMsg4 = ""

end

-- This function gets called once every frame
function draw()
    if menuFlag then
        menu:draw()
        font("Noteworthy-Bold")
        fontSize(20)
        fill(64, 64, 64, 255)
        text(gameMsg,WIDTH/2,HEIGHT-HEIGHT*0.9)
    else
        if win == numberOfPlayer then
            gameOver = true
        end
        perspective(10, WIDTH/HEIGHT)
        -- Position the camera up and back, look at origin
        camera(0,1000,-300, 130,120,0, 0,1,0)
        
        background(220, 220, 220, 255)
        -- Do your drawing here
        if diceRolled and not gameOver then 
            if numberOfMove > 0 and numberOfMove < 4 then 
                rotateDice()
            end
        end
        if numberOfMove == 0 or activePlayer.tokensAtHome == 4 then
            numberOfMove = 1
            sixCount = 0
            changePlayer()
        end
        dice:draw()       
        -- Restore orthographic projection
        ortho()   
        -- Restore the view matrix to the identity
        viewMatrix(matrix())
    
        board:draw()
        if redFlag then
            red:draw()
        end
        if greenFlag then
            green:draw()
        end
        if blueFlag then
            blue:draw()
        end
        if yellowFlag then
            yellow:draw()
        end
        
        -- Draw a label at the top of the screen
        fill(0, 0, 0, 255)
        font("Zapfino")
        fontSize(25)  
        text(dice:name(), board.x, board.y)
    
        font("AmericanTypewriter-Condensed")
        fontSize(22)
        textWrapWidth(200)
        gameMsg = "Turn for "..activePlayer.playerName
        text(gameMsg,WIDTH-120, HEIGHT-HEIGHT*0.15)
        text(winMsg1,WIDTH-120, HEIGHT-HEIGHT*0.35)
        text(winMsg2,WIDTH-120, HEIGHT-HEIGHT*0.37)
        text(winMsg3,WIDTH-120, HEIGHT-HEIGHT*0.39)
        text(winMsg4,WIDTH-120, HEIGHT-HEIGHT*0.41)
        fontSize(16)
        text(inGameMsg, WIDTH-120, HEIGHT-HEIGHT*0.26)
        
        if gameOver then
            fill(0, 0, 0, 141)
            font("Futura-CondensedExtraBold")
            fontSize(150)
            textWrapWidth(1000)
            text("Game Over", board.x, board.y)
        end
        fill(255)
    end
end

function touched (touch)

    if menuFlag then
        menu:touched(touch)
    else
        dice:touched(touch)
        board:touched(touch)
    end
    
    if redFlag and currentPlayer == 1 and moveFlag then
        if allTokensTried < 4 then
            red:touched(touch)
        else 
            moveFlag = false
            changePlayer()
        end
    end
    if greenFlag and currentPlayer == 2 and moveFlag then
        if allTokensTried < 4 then
            green:touched(touch)
        else 
            moveFlag = false
            changePlayer()
        end
    end
    if blueFlag and currentPlayer == 3 and moveFlag then
        if allTokensTried < 4 then
            blue:touched(touch)
        else 
            moveFlag = false
            changePlayer()
        end
    end
    if yellowFlag and currentPlayer == 4 and moveFlag then
        if allTokensTried < 4 then
            yellow:touched(touch)
        else 
            moveFlag = false
            changePlayer()
        end
    end
end

Menu

Menu = class()

function Menu:init()
    -- you can accept and set parameters here
    self.title = "Ludo"
    
end

function Menu:onEnter()
    redFlag = false
    greenFlag = false
    blueFlag = false
    yellowFlag = false
    gameOver = false
    red = nil
    green = nil
    blue = nil
    yellow = nil

    gameMsg = ""
    inGameMsg = ""
    winMsg1 = ""
    winMsg2 = ""
    winMsg3 = ""
    winMsg4 = ""
    
    win = 1
    
end

function Menu:draw()
    -- Codea does not automatically call this method
    background(134, 145, 147, 255)
    rectMode(CENTER)
    strokeWidth(10)
    stroke(255, 255, 255, 255)
    fill(255, 0, 0, 155)
    rect(WIDTH/3, HEIGHT - HEIGHT/3,300,200)
    fill(25,156,44,155)
    rect(WIDTH - WIDTH/3, HEIGHT - HEIGHT/3,300,200)
    fill(10,67,222,155)
    rect(WIDTH/3, HEIGHT/3,300,200)
    fill(244,255,0,155)
    rect(WIDTH - WIDTH/3, HEIGHT/3,300,200)
    
    fill(86, 31, 81, 255)
    noStroke()
    rect(WIDTH-40,40,50,50)
    fontSize(30)
    fill(255, 255, 255, 255)
    text("X",WIDTH-40,40)
    
    ellipseMode(CENTER)
    fill(239, 239, 239, 102)
    noStroke()
    ellipse(WIDTH/2,HEIGHT/2,300,300)
    fill(198, 214, 225, 126)
    ellipse(WIDTH/2,HEIGHT/2,500,500)
    
    font("HelveticaNeue-CondensedBold")
    fontSize(50)
    fill(0, 0, 0, 201)
    text("1 Player", WIDTH/3, HEIGHT - HEIGHT/3)
    text("2 Player", WIDTH - WIDTH/3, HEIGHT - HEIGHT/3)
    text("3 Player", WIDTH/3, HEIGHT/3)
    text("4 Player", WIDTH - WIDTH/3, HEIGHT/3)
    font("MarkerFelt-Wide")
    fill(50, 66, 90, 255)
    fontSize(60)
    text("LUDO",WIDTH/2,HEIGHT-80)
    fill(196, 198, 201, 255)
    text("LUDO",WIDTH/2-5,HEIGHT-75)
end

function Menu:touched(touch)
    if touch.state == ENDED then
        if touch.x > WIDTH/3-150 and touch.x < WIDTH/3+150 and 
           touch.y > HEIGHT-HEIGHT/3-100 and touch.y < HEIGHT-HEIGHT/3+100 then
            --numberOfPlayer = 2
            --currentPlayer = 1
            --menuFlag = false
            
            --red = Tokens(board.x-250, board.y+250,"red")
            --green = Tokens(board.x+250, board.y-250,"green")
            
            --redFlag = true
            --greenFlag = true
            textWrapWidth(500)
            gameMsg = "Single Player vs CPU is not available yet"
        
        elseif touch.x > WIDTH/3-150 and touch.x < WIDTH/3+150 and 
           touch.y > HEIGHT/3-100 and touch.y < HEIGHT/3+100 then
            numberOfPlayer = 3
            currentPlayer = 1
            menuFlag = false
            
            red = Tokens(board.x-250, board.y+250,"red")
            green = Tokens(board.x+250, board.y-250,"green")
            blue = Tokens(board.x+250,board.y+250,"blue")
            
            redFlag = true
            greenFlag = true
            blueFlag = true
            
        elseif touch.x > WIDTH - WIDTH/3-150 and touch.x < WIDTH - WIDTH/3+150 and 
           touch.y > HEIGHT-HEIGHT/3-100 and touch.y < HEIGHT-HEIGHT/3+100 then
            numberOfPlayer = 2
            currentPlayer = 1
            menuFlag = false
            red = Tokens(board.x-250, board.y+250,"red")
            green = Tokens(board.x+250, board.y-250,"green")
            
            redFlag = true
            greenFlag = true

            
        elseif touch.x > WIDTH - WIDTH/3-150 and touch.x < WIDTH - WIDTH/3+150 and 
           touch.y > HEIGHT/3-100 and touch.y < HEIGHT/3+100 then
            numberOfPlayer = 4
            currentPlayer = 1
            menuFlag = false
            
            red = Tokens(board.x-250, board.y+250,"red")
            green = Tokens(board.x+250, board.y-250,"green")
            blue = Tokens(board.x+250,board.y+250,"blue")
            yellow = Tokens(board.x-250,board.y-250,"yellow")
            
            redFlag = true
            greenFlag = true
            blueFlag = true
            yellowFlag = true
                       
        elseif touch.x > WIDTH - 60 and touch.x < WIDTH - 20 and touch.y > 20 and touch.y < 60 then
            close()
        end
        
        activePlayer = red
    end
    -- Codea does not automatically call this method
end

Board

Board = class()

function Board:init(x)
    -- you can accept and set parameters here
    self.x = WIDTH/2-100
    self.y = HEIGHT/2
end

function Board:draw()
    -- Codea does not automatically call this method
    rectMode(CENTER)
    smooth() 
    fill(99, 110, 133, 255)
    noStroke()
    rect(self.x,self.y,765,765)
    fill(255, 255, 255, 255)
    rect(self.x,self.y,750,750)
    
    lineCapMode(SQUARE)
    stroke(0, 0, 0, 255)
    strokeWidth(2)
    line(self.x-125,self.y-375,self.x-125,self.y+375)
    line(self.x+125,self.y-375,self.x+125,self.y+375)
    line(self.x-375,self.y-125,self.x+375,self.y-125)
    line(self.x-375,self.y+125,self.x+375,self.y+125)
    --strokeWidth(7)

    line(self.x-125,self.y-41.5,self.x-41.5,self.y-125)
    line(self.x+125,self.y-41.5,self.x+41.5,self.y-125)
    line(self.x-125,self.y+41.5,self.x-41.5,self.y+125)
    line(self.x+125,self.y+41.5,self.x+41.5,self.y+125)
   
    dy = 21
    dx = 83.3
    side=125
    y=41.5
    w=86
    h=43
    
    for i= 1,2 do
        if i==1 then 
            fill(255, 0, 0, 255)         
        elseif i == 2 then 
            fill(25, 156, 44, 255)           
        end
        local r,g,b,a = fill()
        
        for j=1,6 do
            fill(255, 255, 255, 255)   
            rect(self.x-dx, self.y+side+dy, w, h)             
            rect(self.x+dx, self.y+side+dy, w, h)
            if j==6 then
                rect(self.x, self.y+side+dy, w, h)        
                fill(r,g,b,a)
                rect(self.x, self.y+side+dy, w-15, h-15)
                ellipseMode(CENTER)
                if i == 1 then   
                    ellipse(self.x-dx,self.y+side+dy,40,40)
                    rect(self.x,self.y+dx,w,dx)
                    fill(r,g,b,a-150)
                    rect(self.x-250,self.y+250,120,220)
                    rect(self.x-250,self.y+250,220,120)
                else
                    ellipse(self.x+dx+1,self.y+side+dy,40,40)
                    rect(self.x,self.y-dx,w,dx)
                    fill(r,g,b,a-150)
                    rect(self.x+250,self.y-250,120,220)
                    rect(self.x+250,self.y-250,220,120)
                end
            else
                fill(r,g,b,a)
                rect(self.x, self.y+side+dy, w, h)      
            end
            dy=dy+y
        end
               
        dy=-dy
        y=-y
    end
    
    dx = 21
    dy = 83.3
    side=125
    x=41.5
    h=86
    w=43
    
    for i= 1,2 do
        if i==1 then
            fill(10, 67, 222, 255)
        elseif i == 2 then
            fill(244, 255, 0, 255)   
        end
        local r,g,b,a = fill()
        
        for j=1,6 do
            fill(255, 255, 255, 255)
            rect(self.x+side+dx, self.y-dy, w, h)
            rect(self.x+side+dx, self.y+dy, w, h)   
            if j==6 then
                rect(self.x+side+dx, self.y, w, h)
                fill(r,g,b,a)
                rect(self.x+side+dx, self.y, w-15, h-15)
                ellipseMode(CENTER)
                if i ==1 then
                    ellipse(self.x+side+dx, self.y+dy, 40, 40)
                    rect(self.x+dy,self.y,dy,h)
                    fill(r,g,b,a-150)
                    rect(self.x+250,self.y+250,120,220)
                    rect(self.x+250,self.y+250,220,120)
                else
                    ellipse(self.x+side+dx, self.y-dy, 40, 40)
                    rect(self.x-dy,self.y,dy,h)
                    fill(r,g,b,a-150)
                    rect(self.x-250,self.y-250,120,220)
                    rect(self.x-250,self.y-250,220,120)
                end
            else
                fill(r,g,b,a)
                rect(self.x+side+dx, self.y, w, h)
            end

            dx=dx+x
        end
        dx=-dx
        x=-x
    end
markCurrentPlayer(self.x,self.y)
fill(255, 255, 255, 204)
noStroke()
rect(WIDTH-120,HEIGHT-HEIGHT*0.04,200,40)
fill(79, 83, 111, 255)
font("HelveticaNeue-CondensedBlack")
fontSize(30)
text("Main Menu", WIDTH-120,HEIGHT-HEIGHT*0.04)

fill(129, 127, 127, 134)
rect(WIDTH-120,HEIGHT-HEIGHT*0.3,200,300)
fill(255, 255, 255, 255)
font("HelveticaNeue-CondensedBlack")
end


function Board:touched(touch)
    if touch.state == ENDED then
        if touch.x > WIDTH-220 and touch.x < WIDTH-20 and 
           touch.y > HEIGHT-HEIGHT*0.04-20 and touch.y < HEIGHT-HEIGHT*0.04+20 then
            menuFlag = true
            menu:onEnter()
        end
    end
    -- Codea does not automatically call this method
end

Dice

Dice = class()

function Dice:name()
    return "Ludo"
end

function Dice:init()
    -- all the unique vertices that make up a cube
local vertices = {
      vec3(-0.3, -0.3,  0.3), -- Left  bottom front
      vec3( 0.3, -0.3,  0.3), -- Right bottom front
      vec3( 0.3,  0.3,  0.3), -- Right top    front
      vec3(-0.3,  0.3,  0.3), -- Left  top    front
      vec3(-0.3, -0.3, -0.3), -- Left  bottom back
      vec3( 0.3, -0.3, -0.3), -- Right bottom back
      vec3( 0.3,  0.3, -0.3), -- Right top    back
      vec3(-0.3,  0.3, -0.3), -- Left  top    back
    }

    local faceverts = { vertices[2], vertices[6], vertices[7],
                        vertices[2], vertices[7], vertices[3] }
    local cube = {}
    -- now construct a cube out of the vertices above
    local cubeverts = {
      -- Front
      vertices[1], vertices[2], vertices[3],
      vertices[1], vertices[3], vertices[4],
      -- Right
      vertices[2], vertices[6], vertices[7],
      vertices[2], vertices[7], vertices[3],
      -- Back
      vertices[6], vertices[5], vertices[8],
      vertices[6], vertices[8], vertices[7],
      -- Left
      vertices[5], vertices[1], vertices[4],
      vertices[5], vertices[4], vertices[8],
      -- Top
      vertices[4], vertices[3], vertices[7],
      vertices[4], vertices[7], vertices[8],
      -- Bottom
      vertices[5], vertices[6], vertices[2],
      vertices[5], vertices[2], vertices[1],
    }

    -- all the unique texture positions needed
    local texvertices = { vec2(0.0,1), vec2(0.33,1), vec2(0.66,1),vec2(1,1),
                        vec2(0.0,0.5), vec2(0.33,0.5), vec2(0.66,0.5), vec2(1,0.5),
                        vec2(0.0,0.0), vec2(0.33,0.0), vec2(0.66,0,0), vec2(1,0.0)}
                
    -- apply the texture coordinates to each triangle
    local cubetexCoords = {
      -- Front
      texvertices[5], texvertices[6], texvertices[2],
      texvertices[5], texvertices[2], texvertices[1],
      --Right
      texvertices[6], texvertices[7], texvertices[3],
      texvertices[6], texvertices[3], texvertices[2],
      -- Back
      texvertices[11], texvertices[12], texvertices[8],
      texvertices[11], texvertices[8], texvertices[7],
      -- Left
      texvertices[10], texvertices[11], texvertices[7],
      texvertices[10], texvertices[7], texvertices[6],
      -- Top
      texvertices[7], texvertices[8], texvertices[4],
      texvertices[7], texvertices[4], texvertices[3],
      -- Bottom
      texvertices[9], texvertices[10], texvertices[6],
      texvertices[9], texvertices[6], texvertices[5]
    }
    
    local one = { texvertices[5], texvertices[6], texvertices[2],
                  texvertices[5], texvertices[2], texvertices[1]}
    local two = { texvertices[6], texvertices[7], texvertices[3],
                  texvertices[6], texvertices[3], texvertices[2]}
    local three = { texvertices[7], texvertices[8], texvertices[4],
                    texvertices[7], texvertices[4], texvertices[3]}
    local four = { texvertices[9], texvertices[10], texvertices[6],
                   texvertices[9], texvertices[6], texvertices[5]}
    local five = { texvertices[10], texvertices[11], texvertices[7],
                   texvertices[10], texvertices[7], texvertices[6]}
    local six = { texvertices[11], texvertices[12], texvertices[8],
                  texvertices[11], texvertices[8], texvertices[7]}
    
    faceCoords = {one,two,three,four,five,six}
    
    --[[local x=1
    for i = 1,6 do
        for j =1,6 do
            cube[x] = faceCoords[i][j]
            x = x + 1
        end
    end--]]
    
    -- now we make our 3 different block types
    self.ms = mesh()
    self.ms.vertices = cubeverts
    self.ms.texture = "Dice:Dice"
    --self.ms.texture = img
    self.ms.texCoords = cubetexCoords
    self.ms:setColors(180,180,180,255)
    --color(210, 209, 209, 255)
    
    self.fs = mesh()
    self.fs.vertices = faceverts
    self.fs.texture = "Dice:Dice"
    self.fs.setColors(255,255,255,255)
end

function Dice:draw()
    pushMatrix()
    pushStyle()

    -- apply each transform  need - rotate, scale, translate to the correct place
    resetMatrix()
    rotate(Angle,1,1,0)
    local s = Size*0.5
    scale(s,s,s)
    translate(1,1,0)
    self.ms:draw()
    
    if face then
        self.fs.texCoords = faceCoords[currentRoll]   
        self.fs:draw()
    end
    popStyle()
    popMatrix()
end

function Dice:touched(touch)
    -- Codea does not automatically call this method
    
    if CurrentTouch.state == ENDED  then
        if touch.x > WIDTH-130 and touch.x<WIDTH-20 and touch.y > 0 and touch.y< 110 then         
        flag = true
           diceRolled=true 
        end
    end
end

Tokens

Tokens = class()

function Tokens:init(x,y,col)
    -- you can accept and set parameters here
    
    self.token1origin = vec2(x-35,y+35)
    self.token2origin = vec2(x+35,y+35)
    self.token3origin = vec2(x-35,y-35)
    self.token4origin = vec2(x+35,y-35)
    
    self.token1pos = self.token1origin
    self.token2pos = self.token2origin
    self.token3pos = self.token3origin
    self.token4pos = self.token4origin

    self.tokensAtStart = 4
    self.tokensOnBoard = 0
    self.tokensAtHome = 0
    self.position = {}
    self.token1index = 0
    self.token2index = 0
    self.token3index = 0
    self.token4index = 0
    
    if col == "red" then
        self.playerName = "Player 1"
        fill(139, 43, 35, 255)
        self.position[1] = vec2(board.x-83.3,board.y+125+21*10.9)
    elseif col == "green" then
        self.playerName = "Player 2"
        fill(64, 127, 46, 255)
        self.position[1] = vec2(board.x+83.3,board.y-125-21*10.9)
    elseif col == "blue" then
        self.playerName = "Player 3"
        fill(48, 65, 112, 255)
        self.position[1] = vec2(board.x+125+21*10.9,board.y+83.3)
    elseif col == "yellow" then
        self.playerName = "Player 4"
        fill(143, 140, 34, 255)
        self.position[1] = vec2(board.x-125-21*10.9,board.y-83.3)
    end
    
    self.tokenName = col
    self.r, self.g,self.b,self.a = fill()
    self:setPosition()  
end

function Tokens:setPosition()
    if self.tokenName == "red" then
        a = 41.5 b = 61.5 c = 84.5 
        d=0 f=0 g=1
    elseif self.tokenName == "green" then
        a=-41.5 b=-61.5 c=-84.5
        d=0 f=0 g=1
    elseif self.tokenName == "yellow" then 
        a=0 b=-61.5 c=0
        d=-41.5 f=43 g=-1
    elseif self.tokenName == "blue" then
        a=0 b=61.5 c=0
        d=41.5 f=-43 g=-1
    end
    
    for i = 2,58 do
        if i>1 and i<7 or i>20 and i<26 then
            table.insert(self.position,i,vec2(self.position[i-1].x-d,self.position[i-1].y-a))
        elseif i == 7 then
            table.insert(self.position,i,vec2(self.position[i-1].x-b,self.position[i-1].y-b*g))
        elseif i>7 and i < 13 or i>40 and i<46 then
            table.insert(self.position,i,vec2(self.position[i-1].x-a,self.position[i-1].y+d))
        elseif i==13 or i==14 then
            table.insert(self.position,i,vec2(self.position[i-1].x-d+f,self.position[i-1].y-c))
        elseif i>14 and i<20 or i>33 and i<39 then
            table.insert(self.position,i,vec2(self.position[i-1].x+a*g,self.position[i-1].y-d))
        elseif i == 20 then
            table.insert(self.position,i,vec2(self.position[i-1].x+b*g,self.position[i-1].y-b))
        elseif i==26 or i==27 then
            table.insert(self.position,i,vec2(self.position[i-1].x+c,self.position[i-1].y-d+f))
        elseif i>27 and i<33 or i>46 and i <52 then
            table.insert(self.position,i,vec2(self.position[i-1].x+d,self.position[i-1].y+a))
        elseif i == 33 then
            table.insert(self.position,i,vec2(self.position[i-1].x+b,self.position[i-1].y+b*g))
        elseif i == 39 or i == 40 then
            table.insert(self.position,i,vec2(self.position[i-1].x+d-f,self.position[i-1].y+c))
        elseif i == 46 then
            table.insert(self.position,i,vec2(self.position[i-1].x-b*g,self.position[i-1].y+b))
        elseif i==52 then
            table.insert(self.position,i,vec2(self.position[i-1].x-c,self.position[i-1].y+d-f))
        elseif i<=58 then
            table.insert(self.position,i,vec2(self.position[i-1].x-d+f*c,self.position[i-1].y-a))
            
        end
    end
    
end

function Tokens:draw()
    -- Codea does not automatically call this method
    ellipseMode(CENTER)
    fill(self.r,self.g,self.b,self.a)
    strokeWidth(3)
    stroke(205, 205, 205, 255)
    
    ellipse(self.token1pos.x,self.token1pos.y, 40,40)
    ellipse(self.token2pos.x,self.token2pos.y, 40,40)
    ellipse(self.token3pos.x,self.token3pos.y, 40,40)
    ellipse(self.token4pos.x,self.token4pos.y, 40,40)
    
    strokeWidth(1)
    ellipse(self.token1pos.x,self.token1pos.y, 20,20)
    ellipse(self.token2pos.x,self.token2pos.y, 20,20)
    ellipse(self.token3pos.x,self.token3pos.y, 20,20)
    ellipse(self.token4pos.x,self.token4pos.y, 20,20)
    
    font("HelveticaNeue-CondensedBold")
    fontSize(20)
    fill(224, 224, 224, 255)
    text(self.playerName,self.token1origin.x+40,self.token1origin.y+50)
    fill(1, 1, 1, 255)
    text(self.playerName,self.token1origin.x+38,self.token1origin.y+52)
end

function Tokens:getandsetToken(toknum,x)
    self:settoNextPos(toknum,x)
    setTokentoOrigin()
    
end

function Tokens:settoNextPos(toknum,x)
 
if toknum == 1 then
        self.token1index = x
        self.token1pos = vec2(self.position[self.token1index].x, self.position[self.token1index].y)
    elseif toknum == 2 then 
        self.token2index = x
        self.token2pos = vec2(self.position[self.token2index].x, self.position[self.token2index].y)
    elseif toknum == 3 then
        self.token3index = x
        self.token3pos = vec2(self.position[self.token3index].x, self.position[self.token3index].y)
    elseif toknum == 4 then
        self.token4index = x
        self.token4pos = vec2(self.position[self.token4index].x, self.position[self.token4index].y)
    end
    if x==1 then
        self.tokensAtStart = self.tokensAtStart - 1
        self.tokensOnBoard = self.tokensOnBoard + 1
    elseif x==58 then
        self.tokensOnBoard = self.tokensOnBoard - 1
        self.tokensAtHome = self.tokensAtHome + 1
        
        if win == 1 then
            winMsg1 = "Place 1: "..activePlayer.playerName
        elseif win == 2 then
            winMsg2 = "Place 2: "..activePlayer.playerName
        elseif win == 3 then
            winMsg3 = "Place 3: "..activePlayer.playerName
        end
        win = win + 1  
    end
    numberOfMove = numberOfMove - 1
    if sixCount == 3 then
        inGameMsg = "No more chance for "..activePlayer.playerName.." to roll as six appeared 3 times"
        numberOfMove = 0
    end
    moveFlag = false
end

function Tokens:moveToken(pos,origin,index,toknum)

    if pos == origin and currentRoll == 6 then
        if positionOccupied(index+1) then
            if sameColor() then
                debugmsg = "Try another token"
                allTokensTried = allTokensTried + 1
                return
            else
                self:getandsetToken(toknum,index+1)       
            end
        else
            self:settoNextPos(toknum,index+1)
        end  
    elseif pos~=origin then
        if index+currentRoll <= 58 then
            if positionOccupied(index+currentRoll)then
                if sameColor() then
                    debugmsg = "Try another token"
                    allTokensTried = allTokensTried + 1
                    return
                else      
                    self:getandsetToken(toknum,index+currentRoll)
                end
            else
                self:settoNextPos(toknum,index+currentRoll)
            end
        else
            debugmsg = "Try different token"
            return
        end
    end  
        
    
end

Tokens - Continued

function Tokens:touched(touch)
    if touch.state == ENDED then 
        
        if touch.x>self.token1pos.x-20 and touch.x<self.token1pos.x+20 and
            touch.y<self.token1pos.y+20 and touch.y>self.token1pos.y-20 then
                
            self:moveToken(self.token1pos,self.token1origin,self.token1index,1) 
            
        elseif touch.x>self.token2pos.x-20 and touch.x<self.token2pos.x+20 and
            touch.y<self.token2pos.y+20 and touch.y>self.token2pos.y-20 then
            
            self:moveToken(self.token2pos,self.token2origin,self.token2index,2) 
            
        elseif touch.x>self.token3pos.x-20 and touch.x<self.token3pos.x+20 and
            touch.y<self.token3pos.y+20 and touch.y>self.token3pos.y-20 then
                
            self:moveToken(self.token3pos,self.token3origin,self.token3index,3) 
         
        elseif touch.x>self.token4pos.x-20 and touch.x<self.token4pos.x+20 and
            touch.y<self.token4pos.y+20 and touch.y>self.token4pos.y-20 then
                
            self:moveToken(self.token4pos,self.token4origin,self.token4index,4) 
        end 
        
    end
    -- Codea does not automatically call this method
end

Functions

function rotateDice()
    if flag then
        face=false
        Angle = Angle+10
        if Angle ==520 then
            Angle = 160
            flag=false
            face = true
            currentRoll = math.random(1,6)
            diceRolled = false
            inGameMsg = ""
            if currentRoll == 6 then
                sixCount = sixCount + 1
                numberOfMove = numberOfMove+1
                if activePlayer.tokensAtStart>0 or activePlayer.tokensOnBoard >0 then
                    if moveAvailable() then
                        moveFlag = true
                    else
                        if numberOfMove>1 then
                            return
                        else
                            numberOfMove = 1
                            changePlayer()
                        end
                    end
                end
                    
            elseif currentRoll<6 and currentRoll>0 then
                if activePlayer.tokensOnBoard>0 then
                    numberOfMove = 1
                    if moveAvailable() then
                        moveFlag = true
                    else
                        if numberOfMove>1 then
                            return
                        else
                            numberOfMove = 1
                            changePlayer()
                        end
                    end
                else
                    numberOfMove = 1
                    changePlayer()
                end
            end
        end
    end
end
    

function positionOccupied(nextPos)
    
    for i=1,numberOfPlayer do
        if i==1 then
            tok = red
        elseif i == 2 then
            tok = green
        elseif i == 3 then
            tok = blue
        elseif i == 4 then
            tok = yellow
        end
        
        if tok.token1index~= 0 and math.abs(tok.position[tok.token1index].x-activePlayer.position[nextPos].x)<3 and math.abs(tok.position[tok.token1index].y - activePlayer.position[nextPos].y)<3 then
            occupiedToken = 1
            return true
        elseif tok.token2index~= 0 and math.abs(tok.position[tok.token2index].x-activePlayer.position[nextPos].x)<3 and math.abs(tok.position[tok.token2index].y - activePlayer.position[nextPos].y)<3 then
            occupiedToken = 2
            return true
        elseif tok.token3index~= 0 and math.abs(tok.position[tok.token3index].x -activePlayer.position[nextPos].x)<3 and math.abs(tok.position[tok.token3index].y - activePlayer.position[nextPos].y)<3 then
            occupiedToken = 3
            return true
        elseif tok.token4index~= 0 and math.abs(tok.position[tok.token4index].x-activePlayer.position[nextPos].x)<3 and math.abs(tok.position[tok.token4index].y - activePlayer.position[nextPos].y)<3 then
            occupiedToken = 4
            return true
        end
    end
    tok = nil
    return false
end

function sameColor()
    if tok.tokenName == activePlayer.tokenName then
        return true
    else
        return false
    end  
end

function setTokentoOrigin()
    if occupiedToken == 1 then
        tok.token1index = 0
        tok.token1pos = tok.token1origin
    elseif occupiedToken == 2 then
        tok.token2index = 0
        tok.token2pos = tok.token2origin
    elseif occupiedToken == 3 then
        tok.token3index = 0
        tok.token3pos = tok.token3origin
    elseif occupiedToken == 4 then
        tok.token4index = 0
        tok.token4pos = tok.token4origin
    end
    
    tok.tokensAtStart = tok.tokensAtStart + 1
    tok.tokensOnBoard = tok.tokensOnBoard - 1
    
end

function changePlayer()
        if currentPlayer == numberOfPlayer then
            currentPlayer = 1
            activePlayer = red
        else 
            currentPlayer = currentPlayer + 1
            if currentPlayer == 2 then
                activePlayer = green
            elseif currentPlayer == 3 then
                activePlayer = blue
            elseif currentPlayer == 4 then
                activePlayer = yellow
            end
        end
        allTokensTried = 0
end

function markCurrentPlayer(x,y)
    rectMode(CENTER)
    strokeWidth(4)
    fill(115, 115, 115,0)
    
    if currentPlayer == 1 then
        stroke(255,0,0,150)
        rect(x-250,y+250,240,240)
        stroke(255,0,0,100)
        rect(x-250,y+250,235,235)
        stroke(255,0,0,50)
        rect(x-250,y+250,230,230)
    elseif currentPlayer == 2 then
        stroke(25,156,44,150)
        rect(x+250,y-250,240,240)
        stroke(25,156,44,100)
        rect(x+250,y-250,235,235)
        stroke(25,156,44,50)
        rect(x+250,y-250,230,230)
    elseif currentPlayer == 3 then
        stroke(10,67,222,150)
        rect(x+250,y+250,240,240)
        stroke(10,67,222,100)
        rect(x+250,y+250,235,235)
        stroke(10,67,222,50)
        rect(x+250,y+250,230,230)
    elseif currentPlayer == 4 then
        stroke(244,255,0,150)
        rect(x-250,y-250,240,240)
        stroke(244,255,0,100)
        rect(x-250,y-250,235,235)
        stroke(244,255,0,50)
        rect(x-250,y-250,230,230)
    end
end

function moveAvailable()
    if activePlayer.tokensAtStart>0 and currentRoll==6 then
        return true
    else
        if (activePlayer.token1index>0 and     
        activePlayer.token1index+currentRoll<=#activePlayer.position) or
        (activePlayer.token2index>0 and             
        activePlayer.token2index+currentRoll<=#activePlayer.position) or 
        (activePlayer.token3index>0 and 
        activePlayer.token3index+currentRoll<=#activePlayer.position) or 
        (activePlayer.token4index>0 and 
        activePlayer.token4index+currentRoll<=#activePlayer.position) then
            return true
        else
            return false
        end
    end
end