// neighborsLugs
package neighborsLugs

import (
    "math/rand"
)

type PtrFunc func([21]int) ([21]int,bool,bool)
var GetCandidateLugs map[string]PtrFunc

type MEMORY struct {
    k0,k1,k2,k3 int
}

var T MEMORY  

var theOverlaps [30][2]int = [30][2]int{
 {0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4},
 {1, 0}, {1, 5}, {1, 6}, {1, 7}, {0, 8},
 {2, 1}, {2, 5}, {2, 9}, {2,10}, {2,11},
 {3, 2}, {3, 6}, {3, 9}, {3,12}, {3,13},
 {4, 3}, {4, 7}, {4,10}, {4,12}, {4,14},
 {5, 4}, {5, 8}, {5,11}, {5,13}, {5,14},
}

func InitMEMORY() {
    T.k0 = 0
    T.k1 = 0
    T.k2 = 1
    T.k3 = 0
}

func SameThing(CurrentLugs [21]int) ([21]int,bool,bool) {
    return CurrentLugs, true, false
}

func KnownPlaintextAttack( CurrentLugs [21]int) ([21]int, bool, bool) {
    var futurLugs [21]int
    var finish, skip bool
    finish = false; skip = false

    futurLugs = CurrentLugs
    tb := theOverlaps[T.k3]
    lug := tb[0]; ove := tb[1] + 6
    nbOver := 0
    for i:=6; i<21; i++ { nbOver += CurrentLugs[i] }

    if T.k0 == 0 {
        if futurLugs[lug] >= 1 && futurLugs[ove] < 4 && nbOver < 12 {
            futurLugs[ lug ] --
            futurLugs[ ove ] ++    
        } else { skip = true }

        T.k3 ++
        if T.k3 > 20 {
            T.k0 ++; T.k3 = 0
        }        
    } else {
        if futurLugs[lug] < 13 && futurLugs[ove] >= 1 {
            futurLugs[ lug ] ++
            futurLugs[ ove ] --
        } else { skip = true }

        T.k3 ++
        if T.k3 > 20 {
            T.k0 = 0; T.k3 = 0; finish = true
        }        
    }
    return futurLugs, finish, skip
}

func ToogleOver(CurrentLugs [21]int) ([21]int,bool,bool) {
    var futurLugs [21]int
    var finish, skip bool
    finish = false; skip = false

    futurLugs = CurrentLugs
    x := CurrentLugs[T.k1 + 6]
    y := CurrentLugs[T.k2 + 6]
    //fmt.Println("T.k0,T.k1,T.k2,x,y:",T.k0,T.k1,T.k2,x,y)

    if T.k0 == 0 {
        if (x >= 1) && (y < 4) {
            futurLugs[T.k1 + 6] --
            futurLugs[T.k2 + 6] ++
        } else { skip = true }
        T.k2 ++ 
        if (T.k2 + 6) > 20 {
            T.k1 ++ 
            if (T.k1 + 6) > 19 {
                T.k0 ++ ; T.k1 = 0; T.k2 = 1
            } else { T.k2 = T.k1 + 1 }
        }
    } else  {
        if (y >= 1) && (x < 4) {
            futurLugs[T.k1 + 6] ++
            futurLugs[T.k2 + 6] --
        } else { skip = true }
        T.k2 ++ 
        if (T.k2 + 6)> 20 {
            T.k1 ++
            if (T.k1 + 6) > 19 {
                T.k0 = 0 ; T.k1 = 0; T.k2 = 1 
                finish = true
            } else { T.k2 = T.k1 + 1 }
        }
    } 
    return futurLugs, finish, skip
}    

func ToogleAll(CurrentLugs [21]int) ([21]int,bool,bool) {
    var futurLugs [21]int
    var finish, skip bool
    finish = false; skip = false

    futurLugs = CurrentLugs
    x := CurrentLugs[T.k1]
    y := CurrentLugs[T.k2]
    //fmt.Println("T.k0,T.k1,T.k2,x,y:",T.k0,T.k1,T.k2,x,y)

    if T.k0 == 0 {
        if (x >= 1) && (((T.k2 <= 5) && (y < 13))||((T.k2>5)&&(y<4))) {
            futurLugs[T.k1] --
            futurLugs[T.k2] ++
        } else { skip = true }
        T.k2 ++ 
        if T.k2 > 20 {
            T.k1 ++ 
            if T.k1 > 19 {
                T.k0 ++ ; T.k1 = 0; T.k2 = 1
            } else { T.k2 = T.k1 + 1 }
        }
    } else  {
        if (y >= 1) && (((T.k1 <= 5) && (x < 13))||((T.k2>5)&&(x<4))) {
            futurLugs[T.k1] ++
            futurLugs[T.k2] --
        } else { skip = true }
        T.k2 ++ 
        if T.k2 > 20 {
            T.k1 ++
            if T.k1 > 19 {
                T.k0 = 0 ; T.k1 = 0; T.k2 = 1 
                finish = true
            } else { T.k2 = T.k1 + 1 }
        }
    } 
    return futurLugs, finish, skip
}    
func ToogleEachLug(CurrentLugs [21]int) ([21]int,bool,bool) {
    var futurLugs  [21]int
    var finish, skip bool

    finish = false ; skip = false

    futurLugs = CurrentLugs
    x := CurrentLugs[T.k1]
    y := CurrentLugs[T.k2]

    if T.k0 == 0 {
        if x > 1 && y < 13 {
            futurLugs[T.k1] --
            futurLugs[T.k2] ++
        } else { skip = true }
        T.k2 ++ 
        if T.k2 > 5 {
            T.k1 ++ 
            if T.k1 > 4 {
                T.k0 ++ ; T.k1 = 0; T.k2 = 1
            } else { T.k2 = T.k1 + 1 }
        }
    } else  {
        if y > 1 && x < 13 {
            futurLugs[T.k1] ++
            futurLugs[T.k2] --
        } else { skip = true }
        T.k2 ++ 
        if T.k2 > 5 {
            T.k1 ++
            if T.k1 > 4 {
                T.k0 = 0 ; T.k1 = 0; T.k2 = 1 
                finish = true
            } else { T.k2 = T.k1 + 1 }
        }
    } 
    return futurLugs, finish, skip
}    

func InitLugs() ([21]int) {
    lugs := [21]int{}
    for {
        onePresent := false
        total := 0
        for i:= 0; i<6; i++ {
            lugs[i] = rand.Intn(12)+1
            if lugs[i] == 1 { onePresent = true }
            total += lugs[i]
        }
        if onePresent && (total == 27) { 
            break
        }
    }
    return lugs
}

func init() {
    InitMEMORY()

    GetCandidateLugs = map[string]PtrFunc{
        "TA":   ToogleAll,
        "TO":   ToogleOver,
        "TL":   ToogleEachLug,
        "KP":   KnownPlaintextAttack,
        "ST":   SameThing,
    }
}
