Tic Tac Toe/Game Logic One

From Second Life Wiki
Jump to: navigation, search

Now we're ready to flesh out the game. We get a little stricter in our if else cascade and keep track of who's turn it is. We also record the game state.

// Message constants
integer MSG_RESET      = 0;
integer MSG_TOUCH      = 1;
integer MSG_SET_X      = 2;
integer MSG_SET_O      = 3;
integer MSG_IDLE       = 4;
integer MSG_IDLE_TOUCH = 5;
 
// Game timeout
integer GAME_TIMEOUT = 20;
 
// Game state
key player_x;
key player_o;
string turn;
string game;
 
update_game(string player, integer move)
{
    game = llInsertString(llDeleteSubString(game, move, move), move, player);
    llSay(0, "game = "+game);
}
 
default
{
    state_entry()
    {
        player_x = NULL_KEY;
        player_o = NULL_KEY;
        game = "---------";
        turn = "x";
 
        llMessageLinked(LINK_ALL_CHILDREN, MSG_RESET, "", NULL_KEY);
        state playing;
    }
}
 
state playing
{
    link_message(integer from, integer msg_id, string str, key id)
    {
        if (msg_id == MSG_TOUCH)
        {
            llSay(0, "touch from "+(string)from);
            if (turn == "x" && NULL_KEY == player_x)
            {
                player_x = id;
                update_game(turn, from-2);
                turn = "o";
                llSetTimerEvent(GAME_TIMEOUT);
                llMessageLinked(from, MSG_SET_X, "", NULL_KEY);
            }
            else if (turn == "o" && NULL_KEY == player_o)
            {
                player_o = id;
                update_game(turn, from-2);
                turn = "x";
                llSetTimerEvent(GAME_TIMEOUT);
                llMessageLinked(from, MSG_SET_O, "", NULL_KEY);
            }
            else if (turn == "x" && id == player_x)
            {
                update_game(turn, from-2);
                turn = "o";
                llSetTimerEvent(GAME_TIMEOUT);
                llMessageLinked(from, MSG_SET_X, "", NULL_KEY);
            }
            else if (turn == "o" && id == player_o)
            {
                update_game(turn, from-2);
                turn = "x";
                llSetTimerEvent(GAME_TIMEOUT);
                llMessageLinked(from, MSG_SET_O, "", NULL_KEY);
            }
        }
    }
 
    timer()
    {
        llSetTimerEvent(0);
        state idle;
    }
}
 
state idle
{
    state_entry()
    {
        llSay(0, "state idle");
        llMessageLinked(LINK_ALL_CHILDREN, MSG_IDLE, "", NULL_KEY);
    }
 
    link_message(integer from, integer msg_id, string str, key id)
    {
        if (msg_id == MSG_IDLE_TOUCH) state default;
    }
}

A note about data structures... as you know, lsl doesn't have any. All it has is lists and strings. Use strings. Lists are worthless unless you have wildly heterogenous data, a need for a little extra speed and not much data:

  • Strings are slower, but use memory more efficiently
  • Lists are faster, but gobble up memory at an alarming rate

Store constant width fields in constant length records - your strings can be as long as can fit into whatever remains of the 16k allocated to your script.

If you run out of memory, a common technique is to write data server scripts with just a tiny query API via linked messages.

Everything is there except for the game end checker. If the game ends by winning, we'd like to highlight the winning squares, which would require adding a message and code to the 9 scripts in the X/O boxes. I guess 9 isn't too bad, but still annoying to have to open 9 inventories, delete and drag in a new verion of the script. It's easy to misclick, and becomes old pretty quick - and there is a better way...