// implementation of classic snake game... // Landon Jensen 12/1/2015 // adding optional mousebox/keyboard controls from Craige Hales // define grid result = New Window( "snake", < 100, Print( "N out of bounds..." ); Throw(); ); // create invisible table dt = New Table( "snake", Add Rows( myn * myn ), New Column( "x", Numeric, "Continuous" ), New Column( "y", Numeric, "Continuous" ), New Column( "z", Numeric, "Continuous" ), invisible ); // initialize table For( ::rcount = 1, ::rcount <= myn, ::rcount++, For( ::ccount = 1, ::ccount <= myn, ::ccount++, Column( dt, 1 )[(::rcount - 1) * myn + ::ccount] = ::rcount; Column( dt, 2 )[(::rcount - 1) * myn + ::ccount] = ::ccount; Column( dt, 3 )[(::rcount - 1) * myn + ::ccount] = 0; ) ); // get xy positions in a list for quick lookup xys = {}; For( ::i = 1, ::i <= N Rows( dt ), ::i++, Insert Into( xys, Char( Column( dt, "x" )[::i] ) || "::" || Char( Column( dt, "y" )[::i] ) ) ); // display game board and joystick mygame = New Window( "snake", mb = MouseBox( V List Box( mypanel = Graph Builder( Size( 500, 500 ), Show Control Panel( 0 ), Show Legend( 0 ), Variables( X( :x ), Y( :y ), Color( :z ) ), Elements( Heatmap( X, Y, Legend( 7 ) ) ), SendToReport( Dispatch( {}, "x", ScaleBox, {Min( 1 ), Max( myn + 1 ), Inc( 1 ), Minor Ticks( 0 ), Label Row Nesting( 1 ), Label Row( Show Major Labels( 0 ) )} ), Dispatch( {}, "y", ScaleBox, {Min( 1 ), Max( myn + 1 ), Inc( 1 ), Minor Ticks( 0 ), Label Row Nesting( 1 ), Label Row( Show Major Labels( 0 ) )} ), Dispatch( {}, "400", ScaleBox, {Legend Model( 7, Properties( 0, {gradient( {Color Theme( "Blue to Green to Red" ), Width( 12 )} )} ) )} ), Dispatch( {}, "graph title", TextEditBox, {Set Text( "snake" )} ), Dispatch( {}, "X title", TextEditBox, {Set Text( "" )} ), Dispatch( {}, "Y title", TextEditBox, {Set Text( "" )} ) ) ), V List Box( H List Box( Spacer Box(), Button Box( "Up", ::nextdir = 3 ), Spacer Box() ), H List Box( Spacer Box(), Spacer Box(), Button Box( "Left", ::nextdir = 2 ), Spacer Box(), Button Box( "Right", ::nextdir = 4 ), Spacer Box(), Spacer Box() ), H List Box( Spacer Box(), Button Box( "Down", ::nextdir = 1 ), Spacer Box() ) ) ); ) ); // enable keyboard controls mb << setkey( Function( {this, key}, If( key == "DOWN",::nextdir = 1); If( key == "LEFT",::nextdir = 2); If( key == "UP",::nextdir = 3); If( key == "RIGHT",::nextdir = 4); ) ); mb << setkeyenable( 1 ); mb << setfocus; // function to help check index of current location checkloc = Function( {x, y}, Loc( xys, Char( x ) || "::" || Char( y ) ) ); // multiple location function mLoc = Function( {lst1, lst2}, temp = {}; For( ::i = 1, ::i <= Length( lst2 ), ::i++, temp2 = Loc( lst1, lst2[::i] ); If( N Row( temp2 ) > 0, Insert Into( temp, temp2[1] ) ); ); Matrix( temp ); ); // new food location new_food = Function( {xys, snake}, temp = Random Integer( Length( xys ) ); While( N Row( Loc( snake, xys[temp] ) ) > 0, temp = Random Integer( Length( xys ) ) ); xys[temp]; ); // shift snake snake_shift = Function( {snake, x, y}, Insert Into( snake, Char( x ) || "::" || Char( y ), 1 ); Column( dt, 3 )[Loc( xys, snake[1] )] = 2.5; Column( dt, 3 )[Loc( xys, snake[N Items( snake )] )] = 0; snake = Remove( snake, Length( snake ), 1 ); ); // grow snake and place new food snake_grow = Function( {snake, x, y}, Insert Into( snake, Char( x ) || "::" || Char( y ), 1 ); Column( dt, 3 )[Loc( xys, snake[1] )] = 2.5; ::current_food = Words( new_food( xys, snake ), "::" ); ::currentx_food = Num( current_food[1] ); ::currenty_food = Num( current_food[2] ); Column( dt, 3 )[checkloc( currentx_food, currenty_food )] = 5; snake; ); // start counter ::mystart = Today(); // randomly set the initial snake position ::nextdir = 0; ::headx = Random Integer( myn ); ::heady = Random Integer( myn ); ::snake = {}; Insert Into( snake, Char( ::headx ) || "::" || Char( ::heady ) ); Column( dt, 3 )[Loc( xys, snake[1] )] = 2.5; // randomly set the initial food position ::current_food = Words( new_food( xys, snake ), "::" ); ::currentx_food = Num( current_food[1] ); ::currenty_food = Num( current_food[2] ); Column( dt, 3 )[checkloc( currentx_food, currenty_food )] = 5; // force the user to select a direction While( ::nextdir == 0, Wait( 0.2 ) ); // infinite loop While( 1 > 0, ::temp = Words( snake[1], "::" ); ::headx = Num( temp[1] ); ::heady = Num( temp[2] ); If( ::nextdir == 1, If( (::heady - 1) < 1, Caption( "hit the boundary, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( N Row( Loc( snake, Char( ::headx ) || "::" || Char( ::heady - 1 ) ) ) > 0, Caption( "hit the snake, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( ::headx == ::currentx_food & (::heady - 1) == ::currenty_food, snake = snake_grow( snake, ::headx, ::heady - 1 ), snake = snake_shift( snake, ::headx, ::heady - 1 ) ); ); If( ::nextdir == 2, If( (::headx - 1) < 1, Caption( "hit the boundary, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( N Row( Loc( snake, Char( ::headx - 1 ) || "::" || Char( ::heady ) ) ) > 0, Caption( "hit the snake, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( (::headx - 1) == ::currentx_food & ::heady == ::currenty_food, snake = snake_grow( snake, ::headx - 1, ::heady ), snake = snake_shift( snake, ::headx - 1, ::heady ) ); ); If( ::nextdir == 3, If( (::heady + 1) > myn, Caption( "hit the boundary, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( N Row( Loc( snake, Char( ::headx ) || "::" || Char( ::heady + 1 ) ) ) > 0, Caption( "hit the snake, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( ::headx == ::currentx_food & (::heady + 1) == ::currenty_food, snake = snake_grow( snake, ::headx, ::heady + 1 ), snake = snake_shift( snake, ::headx, ::heady + 1 ) ); ); If( ::nextdir == 4, If( (::headx + 1) > myn, Caption( "hit the boundary, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( N Row( Loc( snake, Char( ::headx + 1 ) || "::" || Char( ::heady ) ) ) > 0, Caption( "hit the snake, SCORE=" || Char( Length( snake ) ) ); Throw(); ); If( (::headx + 1) == ::currentx_food & ::heady == ::currenty_food, snake = snake_grow( snake, ::headx + 1, ::heady ), snake = snake_shift( snake, ::headx + 1, ::heady ) ); ); // time step Wait( 0.2 ); ); Print( "SCORE=" || Char( Length( snake ) ) );