Skip to content

Instantly share code, notes, and snippets.

@rowpsmo1859
Last active December 15, 2016 03:27
Show Gist options
  • Select an option

  • Save rowpsmo1859/7746161ed703e256c73cf2dd501f2b55 to your computer and use it in GitHub Desktop.

Select an option

Save rowpsmo1859/7746161ed703e256c73cf2dd501f2b55 to your computer and use it in GitHub Desktop.

Revisions

  1. rowpsmo1859 revised this gist Dec 10, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions LiveEvolutionTicTac.fsx
    Original file line number Diff line number Diff line change
    @@ -285,7 +285,7 @@ let player1AI =
    StarterRecords = startingRecords
    MutationSequence = minimalMutationSequence
    MaximumMindsPerGeneration = 10
    MaximumThinkCycles = 99
    MaximumThinkCycles = None
    FitnessFunction = fitnessFunction
    FitPopulationSelectionFunction = selectFitPopulation
    ActivationFunctions = activationFunctions
    @@ -323,7 +323,7 @@ let player2AI =
    StarterRecords = startingRecords
    MutationSequence = minimalMutationSequence
    MaximumMindsPerGeneration = 10
    MaximumThinkCycles = 99
    MaximumThinkCycles = None
    FitnessFunction = fitnessFunction
    FitPopulationSelectionFunction = selectFitPopulation
    ActivationFunctions = activationFunctions
  2. rowpsmo1859 revised this gist Dec 9, 2016. 1 changed file with 29 additions and 27 deletions.
    56 changes: 29 additions & 27 deletions LiveEvolutionTicTac.fsx
    Original file line number Diff line number Diff line change
    @@ -104,36 +104,39 @@ let ticTacInstance =
    let! msg = inbox.Receive ()
    match msg with
    | ReceiveMove (playerId, checkSquareCommand, replyChannel) ->
    let updatedGameBoard =
    let updatedGameBoard, boardGameStatus =
    if (gameBoard |> Map.toSeq |> Seq.length) >= 9 then
    gameBoard
    gameBoard, GameOver 0
    else
    let rec processMove squareNumber =
    if squareNumber > 8 then
    processMove 0
    else
    match gameBoard |> Map.tryFind squareNumber with
    | None ->
    gameBoard
    |> Map.add squareNumber playerId
    | Some _ -> processMove (squareNumber+1)
    match checkSquareCommand with
    | Zero -> processMove 0
    | One -> processMove 1
    | Two -> processMove 2
    | Three -> processMove 3
    | Four -> processMove 4
    | Five -> processMove 5
    | Six -> processMove 6
    | Seven -> processMove 7
    | Eight -> processMove 8
    | IDontKnow -> processMove 0
    let gameBoardAfterMove =
    let rec processMove squareNumber =
    if squareNumber > 8 then
    processMove 0
    else
    match gameBoard |> Map.tryFind squareNumber with
    | None ->
    gameBoard
    |> Map.add squareNumber playerId
    | Some _ -> processMove (squareNumber+1)
    match checkSquareCommand with
    | Zero -> processMove 0
    | One -> processMove 1
    | Two -> processMove 2
    | Three -> processMove 3
    | Four -> processMove 4
    | Five -> processMove 5
    | Six -> processMove 6
    | Seven -> processMove 7
    | Eight -> processMove 8
    | IDontKnow -> processMove 0
    gameBoardAfterMove, ContinueGame
    let updatedMoveBuffer =
    lastMoveBuffer
    |> Map.add playerId checkSquareCommand
    let updatedGameStatus =
    updatedGameBoard
    |> checkForWin
    match updatedGameBoard |> checkForWin with
    | GameOver winner -> GameOver winner
    | ContinueGame -> boardGameStatus
    replyChannel.Reply ()
    printGameBoard updatedGameBoard
    return! loop updatedGameBoard updatedMoveBuffer updatedGameStatus
    @@ -344,6 +347,5 @@ let processTurn _ =
    | ContinueGame ->
    ()

    [0..100]
    |> List.iter processTurn
    processTurn ()
    [0..5000]
    |> List.iter processTurn
  3. rowpsmo1859 created this gist Dec 9, 2016.
    349 changes: 349 additions & 0 deletions LiveEvolutionTicTac.fsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,349 @@
    #I "../NeuralFish"
    #load "NeuralFish_dev.fsx"

    open NeuralFish.Types
    open NeuralFish.Core
    open NeuralFish.EvolutionChamber
    open NeuralFish.Exporter

    type SquareId = int

    type PlayerId = int

    type CheckSquare =
    | Zero
    | One
    | Two
    | Three
    | Four
    | Five
    | Six
    | Seven
    | Eight
    | IDontKnow

    type TicTacBoard = Map<SquareId, int>

    type TicTacGameStatus =
    | GameOver of PlayerId
    | ContinueGame

    type TicTacMsg =
    | ReceiveMove of PlayerId*CheckSquare*AsyncReplyChannel<unit>
    | GetGameStatusAndBoard of AsyncReplyChannel<TicTacGameStatus*TicTacBoard>
    | GetLastMove of PlayerId*AsyncReplyChannel<CheckSquare>
    | GetGameBoard of AsyncReplyChannel<TicTacBoard>
    | ClearGame of AsyncReplyChannel<unit>
    | KillGame

    type TicTacInstance = MailboxProcessor<TicTacMsg>

    type MoveBuffer = Map<PlayerId, CheckSquare>

    let winPatterns =
    let row1 = [0; 1; 2]
    let row2 = [3; 4; 5]
    let row3 = [6; 7; 8]
    let column1 = [0; 3; 6]
    let column2 = [1; 4; 7]
    let column3 = [2; 5; 8]
    let backSlash = [0; 4; 8]
    let forwardSlash = [2; 4; 6]
    [
    row1
    row2
    row3
    column1
    column2
    column3
    backSlash
    forwardSlash
    ]

    let ticTacInstance =
    let checkForWin (gameBoard : TicTacBoard) =
    let checkWinPattern playerId winPattern =
    let checkIfPlayerOccupiesSquare playerId squareId =
    match gameBoard |> Map.tryFind squareId with
    | None -> false
    | Some playerIdThatOccupiesSquare ->
    (playerIdThatOccupiesSquare = playerId)
    winPattern |> List.forall (checkIfPlayerOccupiesSquare playerId)
    let didPlayer1Win =
    let checkWinFunction = checkWinPattern 1
    winPatterns |> List.exists checkWinFunction
    let didPlayer2Win =
    let checkWinFunction = checkWinPattern 2
    winPatterns |> List.exists checkWinFunction
    if didPlayer1Win then
    printfn "Player 1 Wins!"
    GameOver 1
    else if didPlayer2Win then
    printfn "Player 2 Wins!"
    GameOver 2
    else ContinueGame
    let printGameBoard (gameBoard : TicTacBoard) =
    let printSquare squareId =
    let squareContents =
    match gameBoard |> Map.tryFind squareId with
    | None -> 0
    | Some playerId -> playerId
    if [2; 5; 8] |> List.contains squareId then
    printfn "| %i |" squareContents
    else
    printf "| %i " squareContents
    printfn "------------------------------------"
    [0..8]
    |> Seq.iter printSquare
    printfn "------------------------------------"
    TicTacInstance.Start(fun inbox ->
    let rec loop (gameBoard : TicTacBoard)
    (lastMoveBuffer : MoveBuffer)
    (gameStatus : TicTacGameStatus)=
    async {
    let! msg = inbox.Receive ()
    match msg with
    | ReceiveMove (playerId, checkSquareCommand, replyChannel) ->
    let updatedGameBoard =
    if (gameBoard |> Map.toSeq |> Seq.length) >= 9 then
    gameBoard
    else
    let rec processMove squareNumber =
    if squareNumber > 8 then
    processMove 0
    else
    match gameBoard |> Map.tryFind squareNumber with
    | None ->
    gameBoard
    |> Map.add squareNumber playerId
    | Some _ -> processMove (squareNumber+1)
    match checkSquareCommand with
    | Zero -> processMove 0
    | One -> processMove 1
    | Two -> processMove 2
    | Three -> processMove 3
    | Four -> processMove 4
    | Five -> processMove 5
    | Six -> processMove 6
    | Seven -> processMove 7
    | Eight -> processMove 8
    | IDontKnow -> processMove 0
    let updatedMoveBuffer =
    lastMoveBuffer
    |> Map.add playerId checkSquareCommand
    let updatedGameStatus =
    updatedGameBoard
    |> checkForWin
    replyChannel.Reply ()
    printGameBoard updatedGameBoard
    return! loop updatedGameBoard updatedMoveBuffer updatedGameStatus
    | GetGameBoard replyChannel ->
    async {
    gameBoard
    |> replyChannel.Reply
    } |> Async.Start
    return! loop gameBoard lastMoveBuffer gameStatus
    | GetLastMove (playerId, replyChannel) ->
    async {
    let lastMove =
    match lastMoveBuffer |> Map.tryFind playerId with
    | None -> IDontKnow
    | Some move -> move
    lastMove
    |> replyChannel.Reply
    } |> Async.Start
    return! loop gameBoard lastMoveBuffer gameStatus
    | GetGameStatusAndBoard replyChannel ->
    (gameStatus, gameBoard)
    |> replyChannel.Reply
    return! loop gameBoard lastMoveBuffer gameStatus
    | ClearGame replyChannel ->
    printfn "New TicTacToe Game"
    printGameBoard Map.empty
    replyChannel.Reply()
    return! loop Map.empty Map.empty ContinueGame
    | KillGame ->
    ()
    }
    loop Map.empty Map.empty ContinueGame
    )

    let gameActionOutputHookId = 0

    let getOutputHook playerId : OutputHookFunction =
    (fun neuralOutput ->
    let interpretedAnswer =
    match neuralOutput |> round with
    | 0.0 -> Zero
    | 1.0 -> One
    | 2.0 -> Two
    | 3.0 -> Three
    | 4.0 -> Four
    | 5.0 -> Five
    | 6.0 -> Six
    | 7.0 -> Seven
    | 8.0 -> Eight
    | _ -> IDontKnow
    (fun r -> ReceiveMove(playerId, interpretedAnswer, r))
    |> ticTacInstance.PostAndReply
    )

    let getFitnessFunction playerId : LiveFitnessFunction =
    (fun _ ->
    let lastMove =
    (fun r -> GetLastMove(playerId, r))
    |> ticTacInstance.PostAndReply
    let gameStatus, gameBoard =
    GetGameStatusAndBoard
    |> ticTacInstance.PostAndReply
    match gameStatus with
    | GameOver winner ->
    if (winner = playerId) then
    10.0, EndThinkCycle
    else
    0.0, EndThinkCycle
    | ContinueGame ->
    let maybeAnswerSquareId =
    match lastMove with
    | Zero -> Some 0
    | One -> Some 1
    | Two -> Some 2
    | Three -> Some 3
    | Four -> Some 4
    | Five -> Some 5
    | Six -> Some 6
    | Seven -> Some 7
    | Eight -> Some 8
    | IDontKnow -> None
    match maybeAnswerSquareId with
    | None -> -4.0, ContinueThinkCycle
    | Some answerSquareId ->
    if (gameBoard |> Map.find answerSquareId) = playerId then
    0.0, ContinueThinkCycle
    else
    -2.0, ContinueThinkCycle
    )

    let getSyncFunction playerId : SyncFunction =
    (fun () ->
    let constructDataVector (recordedMovesOnBoard : TicTacBoard) =
    let getRecordedMove squareId =
    match recordedMovesOnBoard |> Map.tryFind squareId with
    | None -> 0.0
    | Some playerId -> playerId |> float
    [0..8]
    |> Seq.map getRecordedMove
    GetGameBoard
    |> ticTacInstance.PostAndReply
    |> constructDataVector
    )

    let selectFitPopulation : FitPopulationSelectionFunction =
    (fun scoredNodeRecords ->
    let dividedLength =
    let length = (scoredNodeRecords |> Array.length) / 5
    if (length < 2) then
    2
    else
    length
    scoredNodeRecords
    |> Array.sortByDescending(fun (_,(score,_)) -> score)
    |> Array.chunkBySize dividedLength
    |> Array.head
    |> Array.Parallel.map (fun (key,(_,value)) -> key, value)
    |> Map.ofArray
    )
    let infoLog = (fun _ -> ())

    let player1AI =
    let playerId = 1
    let activationFunctions =
    Map.empty
    |> Map.add 0 sigmoid
    let outputHookFunctionIds : OutputHookFunctionIds =
    [gameActionOutputHookId]
    |> List.toSeq
    let learningAlgorithm = Hebbian 0.7
    let startingRecords : GenerationRecords =
    let nodeRecords =
    getDefaultNodeRecords activationFunctions outputHookFunctionIds 0 learningAlgorithm infoLog
    Map.empty
    |> Map.add 0 nodeRecords
    let outputHooks : OutputHookFunctions =
    let outputHook = getOutputHook playerId
    Map.empty
    |> Map.add gameActionOutputHookId outputHook
    let syncFunctions : SyncFunctions =
    let syncFunction = getSyncFunction playerId
    Map.empty
    |> Map.add 0 syncFunction
    let fitnessFunction = getFitnessFunction playerId
    {
    StarterRecords = startingRecords
    MutationSequence = minimalMutationSequence
    MaximumMindsPerGeneration = 10
    MaximumThinkCycles = 99
    FitnessFunction = fitnessFunction
    FitPopulationSelectionFunction = selectFitPopulation
    ActivationFunctions = activationFunctions
    SyncFunctions = syncFunctions
    OutputHookFunctions = outputHooks
    EndOfGenerationFunctionOption = None
    NeuronLearningAlgorithm = learningAlgorithm
    InfoLog = infoLog
    } |> getLiveEvolutionInstance

    let player2AI =
    let playerId = 2
    let activationFunctions =
    Map.empty
    |> Map.add 0 sigmoid
    let outputHookFunctionIds : OutputHookFunctionIds =
    [gameActionOutputHookId]
    |> List.toSeq
    let learningAlgorithm = Hebbian 0.7
    let startingRecords : GenerationRecords =
    let nodeRecords =
    getDefaultNodeRecords activationFunctions outputHookFunctionIds 0 learningAlgorithm infoLog
    Map.empty
    |> Map.add 0 nodeRecords
    let outputHooks : OutputHookFunctions =
    let outputHook = getOutputHook playerId
    Map.empty
    |> Map.add gameActionOutputHookId outputHook
    let syncFunctions : SyncFunctions =
    let syncFunction = getSyncFunction playerId
    Map.empty
    |> Map.add 0 syncFunction
    let fitnessFunction = getFitnessFunction playerId
    {
    StarterRecords = startingRecords
    MutationSequence = minimalMutationSequence
    MaximumMindsPerGeneration = 10
    MaximumThinkCycles = 99
    FitnessFunction = fitnessFunction
    FitPopulationSelectionFunction = selectFitPopulation
    ActivationFunctions = activationFunctions
    SyncFunctions = syncFunctions
    OutputHookFunctions = outputHooks
    EndOfGenerationFunctionOption = None
    NeuronLearningAlgorithm = learningAlgorithm
    InfoLog = infoLog
    } |> getLiveEvolutionInstance

    let processTurn _ =

    SynchronizeActiveCortex |> player1AI.PostAndReply
    SynchronizeActiveCortex |> player2AI.PostAndReply

    let gameStatus, _ = GetGameStatusAndBoard |> ticTacInstance.PostAndReply
    match gameStatus with
    | GameOver winner ->
    ClearGame
    |> ticTacInstance.PostAndReply
    | ContinueGame ->
    ()

    [0..100]
    |> List.iter processTurn
    processTurn ()