De DigiWiki.
// One-Prim Noughts and Crosses - OpenSim LSL script by Warin Cascabel (26 February 2009)
// As this script makes use of OpenSim-specific extensions to the Linden Scripting Language.
// This script will NOT work in Second Life.
// Internal variables.
list Spaces = [-1,-1,-1,-1,-1,-1,-1,-1,-1]; // Keeps track of what's in which space of the board. -1=empty, 0=O, 1=X
integer GameOver = 0; // If nonzero, signals which row, column or diagonal has the win (or -1 for a draw)
integer WhoseTurn = 1; // Whose turn is it next? 0=O, 1=X
// DrawBoard()
// Builds the dynamic texture command based on the contents of the Spaces list and the GameOver variable.
DrawBoard()
{
string dl; // holds the draw list
integer i; // iterator for our for loop
integer x; // holds the horizontal coordinate of each space
integer y; // holds the vertical coordinate of each space
dl = osSetPenColor("", "white" ); // Set the background to solid white
dl = osMovePen( dl, 0, 0 );
dl = osDrawFilledRectangle( dl, 128, 128 );
dl = osSetPenColor( dl, "black" ); // Draw the grid in black
dl = osSetPenSize( dl, 2 );
dl = osDrawLine( dl, 43, 3, 43, 125 );
dl = osDrawLine( dl, 86, 3, 86, 125 );
dl = osDrawLine( dl, 3, 43, 125, 43 );
dl = osDrawLine( dl, 3, 86, 125, 86 );
dl = osSetPenSize( dl, 6 ); // Increase the pen size for our Xs and Os.
for (i = 0; i < 9; ++i) // For each element in the Spaces list:
{
integer who = llList2Integer( Spaces, i ); // Get its value
if (who > -1) // Do nothing if it's -1 (empty)
{
x = (i % 3) * 43 + 21; // Calculate the center of the square
y = (i / 3) * 43 + 21;
if (who == 0) // If it's an O:
{
dl = osSetPenColour( dl, "lime" ); // Select a bright green pen color
dl = osMovePen( dl, x-17, y-17 ); // Move the pen to the upper left corner of the square
dl = osDrawEllipse( dl, 35, 35 ); // Draw the O
}
else // If it's an X:
{
dl = osSetPenColor( dl, "blue" ); // Select a bright blue pen color
dl = osDrawLine( dl, x-17, y-17, x+17, y+17 ); // Draw the first line of the X
dl = osDrawLine( dl, x-17, y+17, x+17, y-17 ); // Draw the second line of the X
}
}
}
if (GameOver > 0) // if GameOver is 1 or more, we will draw a red line through the winning row, column or diagonal
{
dl = osSetPenColor( dl, "orangered" ); // Select an orange-red color
if (GameOver == 1) dl = osDrawLine( dl, 5, 21, 125, 21 ); // Draw a horizontal, vertical or diagonal line,
else if (GameOver == 2) dl = osDrawLine( dl, 3, 64, 125, 64 ); // based on the value of GameOver. This is
else if (GameOver == 3) dl = osDrawLine( dl, 3, 107, 125, 107 ); // really kind of kludgy, but it gets the job
else if (GameOver == 4) dl = osDrawLine( dl, 21, 3, 21, 125 ); // done.
else if (GameOver == 5) dl = osDrawLine( dl, 64, 3, 64, 125 );
else if (GameOver == 6) dl = osDrawLine( dl, 107, 3, 107, 125 );
else if (GameOver == 7) dl = osDrawLine( dl, 3, 3, 125, 125 );
else if (GameOver == 8) dl = osDrawLine( dl, 125, 3, 3, 125 );
}
osSetDynamicTextureData( "", "vector", dl, "width:128,height:128,alpha:false", 0 ); // Draw the dynamic texture
}
// CheckForWin() - returns an integer value of -1 for a draw, 0 if there are still moves that can be made, or a positive
// integer specifying which row, column or diagonal contains the win. This is REALLY kludgy.
//
integer CheckForWin()
{
integer s1 = llList2Integer( Spaces, 0 ); // Get each space's value into its own integer for use in the tests below,
integer s2 = llList2Integer( Spaces, 1 ); // which calls llList2Integer() 9 times (instead of the 33 times that it
integer s3 = llList2Integer( Spaces, 2 ); // would take to call the function for each space in the tests below).
integer s4 = llList2Integer( Spaces, 3 );
integer s5 = llList2Integer( Spaces, 4 );
integer s6 = llList2Integer( Spaces, 5 );
integer s7 = llList2Integer( Spaces, 6 );
integer s8 = llList2Integer( Spaces, 7 );
integer s9 = llList2Integer( Spaces, 8 );
if ((s1 != -1) && (s1 == s2) && (s1 == s3)) return 1; // Top row
if ((s4 != -1) && (s4 == s5) && (s4 == s6)) return 2; // Middle row
if ((s7 != -1) && (s7 == s8) && (s7 == s9)) return 3; // Bottom row
if ((s1 != -1) && (s1 == s4) && (s1 == s7)) return 4; // Left column
if ((s2 != -1) && (s2 == s5) && (s2 == s8)) return 5; // Middle column
if ((s3 != -1) && (s3 == s6) && (s3 == s9)) return 6; // Right column
if ((s1 != -1) && (s1 == s5) && (s1 == s9)) return 7; // Top left to bottom right
if ((s3 != -1) && (s3 == s5) && (s3 == s7)) return 8; // Top right to bottom left
if ((s1 == -1) || (s2 == -1) || (s3 == -1) || (s4 == -1) || (s5 == -1) ||
(s6 == -1) || (s7 == -1) || (s8 == -1) || (s9 == -1)) return 0; // At least one space is open
return -1; // No more moves can be made, but nobody won.
}
default
{
state_entry() // Start the game.
{
DrawBoard(); // Draw an empty board.
}
// The actual game logic all happens in touch_start(). It retrieves the coordinates of where on the front face the user
// touched, and from that calculates which space was touched. If it's empty, it fills it in with an X or an O, depending
// on whose turn it is, checks to see if there's a winner, and redraws the game board.
touch_start( integer numTouchers )
{
if (llDetectedTouchFace( 0 ) != 1) return; // Only accept touches from the "front" face.
if (GameOver) llResetScript(); // If the game's over, start a new one.
vector v = llDetectedTouchST( 0 ); // Get X,Y coords of the touch on the face.
integer index = llFloor( v.x * 3.0 ) + (3 * llFloor( (1-v.y) * 3.0 )); // Turn that into index into the Spaces list.
if (llList2Integer( Spaces, index ) >= 0) return; // If space is already filled, ignore touch.
Spaces = llListReplaceList( Spaces, [ WhoseTurn ], index, index ); // Set the value of the space to X or O.
WhoseTurn = 1 - WhoseTurn; // Swap whose turn it will be next.
GameOver = CheckForWin(); // See if anybody won yet
DrawBoard(); // Draw the new board.
}
}