My brother introduced me to this app, and I immediately fell in love with the simplicity of the game. So, natively, I decided a port of this to the calc would be awesome. I've written some code in DCS-aided TI-BASIC, and so far I have it loading levels from an AppVar/prgm, displaying splashscreens, and doing some tilemap things. The first line of the AppVar/prgm will be used later to store what level to start loading from, and I have written a program to aid in the creation of new levels. Here is my code, please feel free to comment suggestions or questions. I have not written anything for gameplay, so pressing enter "solves" the puzzle.

Level Creation Code:

Code:
det(0,"LOOPLVLS",5
det(5,"LOOPLVLS",0)-1->C
Repeat 0
C+1->C
ClrDraw
[[0]]->[A]
{8,12->dim([A]
For(A,1,8
For(B,1,12
~1->[A](A,B
End
End
0->A
0->B
Repeat G=92
Pxl-Change(8A,8B
Repeat Ans
getKey
End
Pxl-Change(8A,8B
Ans->G
A-(G=25 and A>0)+(G=34 and A<7->A
B-(G=24 and B>0)+(G=26 and B<11->B
If G=21
Then
[A](A+1,B+1)+1->[A](A+1,B+1:If [A](A+1,B+1)=15
~1->[A](A+1,B+1
End
If G=22 or G=31
Then
[A](A+1,B+1)-1->[A](A+1,B+1:If [A](A+1,B+1)=~2
14->[A](A+1,B+1
End
If [A](A+1,B+1)>=0
Then
real(1,8B,8A,1,8,6,round(12fPart([A](A+1,B+1)/12),0),8iPart([A](A+1,B+1)/12),0,0,1
Else
real(1,8B,8A,1,8,6,11,8*7,0,0,1
End
End
Input Str1
Str1
For(A,1,8
For(B,1,12
Ans+sub("0123456789ABCDEF",[A](A,B)+2,1
End
End
sub(Ans,2,96
If inString("/*-",Str1
Str1+Ans
det(6,"LOOPLVLS",Ans,C
End


The LOOPLVLS AppVar/pgrm with 10 level, in the pattern of :scrambled1:solved1:scrambled2:solved2:..., a / indicates an x-shift of 4 pixels, * is a y-shift, and - shifts both x and y 4 pixels away from the top-left corner.

Code:
1
/0000000000000000000000000000000000000000AD8000000000A5800000000000000000000000000000000000000000
0000000000000000000000000000000000000000BD8000000000A5900000000000000000000000000000000000000000
0000000000000000000000000000000000000000BB8800000000AA990000000000000000000000000000000000000000
0000000000000000000000000000000000000000B8B800000000A9A90000000000000000000000000000000000000000
-0000000000000000000000000000B58000000000C1E000000000AD900000000000000000000000000000000000000000
0000000000000000000000000000BD8000000000E1C000000000A5900000000000000000000000000000000000000000
-000000000000000000000000000070600000000020200000000070600000000000000000000000000000000000000000
0000000000000000000000000000F0F00000000030300000000070700000000000000000000000000000000000000000
0000000000000000000000000000A3D800000000C5E3000000003CEE00000000BC3A0000000000000000000000000000
0000000000000000000000000000B2D800000000EDC3000000003E5C00000000A5290000000000000000000000000000
00000000000000000000000000000BB700000000811B0000000072200000000004700000000000000000000000000000
00000000000000000000000000000B8F00000000B1190000000073300000000007700000000000000000000000000000
0000000000000000000000000000823B00000000AABB00000000F32F00000000F6760000000000000000000000000000
0000000000000000000000000000B22800000000A8B900000000F33F0000000077770000000000000000000000000000
-0000000000000009333A000000046C46000000063134000000046E4600000008333B0000000000000000000000000000
000000000000000B2228000000074D670000000421260000000F456F0000000A22290000000000000000000000000000
-00000000000000085D39000000033E3D0000000ED15C0000000D3522000000083CCA0000000000000000000000000000
000000000000000BDD28000000033E2C0000000E51DC0000000E2C330000000A25590000000000000000000000000000
000000000000000000000000000099990000000999999000000999999000000099990000000000000000000000000000
0000000000000000000000000000B8B80000000B9A9A8000000A8B8B90000000A9A90000000000000000000000000000


And the game part:

Code:
[[15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15][15,15,15,15,15,15,15,15,15,15,15,15->[C]
Input "Graphics Mode:",Z
real(0,0
real(1,22,24,6,13,6,5,50,0,0,1
For(theta,1,10
   det(5,"LOOPLVLS",2theta->Str1
   det(5,"LOOPLVLS",2theta+1->Str2
   0->V
   0->W
   If inString("/*-",sub(Str1,1,1
   Then
      sub(Str1,1,1
      If Ans="/" or Ans="-
      4->V
      sub(Str1,1,1
      If Ans="*" or Ans="-
      4->W
      sub(Str1,2,96->Str1
   End
   {8,12->dim([A]
   [A]->[B]
   For(A,1,8
      For(B,1,12
         inString("0123456789ABCDEF",sub(Str2,12(A-1)+B,1))-2
         If Ans=~1
         Then
            81+60(Z=2->[B](A,B
            Else
            Ans+30Z->[B](A,B
         End
      End
   End
   real(0,1
   Text(~1,27,42-3iPart(log(theta)),"#",theta
   real(0,0
   For(A,1,8
      For(B,1,12
         inString("0123456789ABCDEF",sub(Str1,12(A-1)+B,1))-2
         If Ans!=~1
         Then
            Ans+30Z->[A](A,B
            real(1,8(B-1)+V,8(A-1)+W,1,8,6,round(12fPart(Ans/12),0),8iPart(Ans/12),0,0,0
            Else
            81+30(Z=2->[A](A,B
         End
      End
   End
   real(6,1
   
   Pause
   
   [B]+[C]-4(Z=2)[C]->[B]
   real(2,1,0,0,12,8,0,12,0,8,6,0,8,0
   If V+W
   real(4,(W=4)+3(V=4)+3(VW=16),4,0
   real(6
End


Pic6 looks like this:
Alright, I have "completed" the game, in that it works and functions the way I want it to. Here is the game code:


Code:
:DCS6
"0000000000001C1C223E217240E341C141C1638127423E221C1C000000000000"
det(0,"thetathetaZZLOOP",5
If det(0,"thetathetaZZLOOP
det(0,"thetathetaZZLOOP
If 1=det(5,"thetathetaZZLOOP",0
Then
   det(6,"thetathetaZZLOOP","1",1
   Input "Graphical Mode:",A
   det(6,"thetathetaZZLOOP",det(1,A),2
End
expr(det(5,"thetathetaZZLOOP",2->Z
real(0,0
real(1,22,24,6,13,6,5,50,0,0,1
expr(det(5,"thetathetaZZLOOP",1->theta
Repeat 2theta>det(5,"LOOPLVLS",0
   det(8,"thetathetaZZLOOP",det(1,theta),1
   det(5,"LOOPLVLS",2theta-1->Str1
   det(5,"LOOPLVLS",2theta->Str2
   0->V
   0->W
   If inString("/*-",sub(Str1,1,1
   Then
      sub(Str1,1,1
      If Ans="/" or Ans="-
      4->V
      sub(Str1,1,1
      If Ans="*" or Ans="-
      4->W
      sub(Str1,2,96->Str1
   End
   {8,12->dim([A]
   [A]->[B]
   For(A,1,8
      For(B,1,12
         inString("0123456789ABCDEF",sub(Str2,12(A-1)+B,1))-2
         If Ans=~1
         Then
            95->[B](A,B
            Else
            Ans+15Z->[B](A,B
         End
      End
   End
   real(0,1
   Text(~1,27,42-3iPart(log(theta)),"#",theta
   real(0,0
   For(A,1,8
      For(B,1,12
         inString("0123456789ABCDEF",sub(Str1,12(A-1)+B,1))-2
         If Ans!=~1
         Then
            Ans+15Z->[A](A,B
            real(1,8(B-1)+V,8(A-1)+W,1,8,6,round(12fPart(Ans/12),0),8iPart(Ans/12),0,0,0
            Else
            95->[A](A,B
         End
      End
   End
   0->C
   Repeat sub(Str1,C,1)!="0
      C+1->C
   End
   round(12fPart(C/12)-1,0->A
   round(iPart(C/12),0->B
   real(12,3,8A+V,8B+W,8A+V+7,8B+W+7,1
   Repeat [A]=[B]
      real(1,8A+V,8B+W,1,8,6,round(12fPart([A](B+1,A+1)/12),0),8iPart([A](B+1,A+1)/12),0,0,0
      Repeat Ans
         getKey
      End
      Ans->G
      If max(G={24,25,26,34
      Then
         If G=24 and A>0:Then
            If [A](B+1,A)<95
            A-1->A
         End
         If G=26 and A<11:Then
            If [A](B+1,A+2)<95
            A+1->A
         End
         If G=25 and B>0:Then
            If [A](B,A+1)<95
            B-1->B
         End
         If G=34 and B<7:Then
            If [A](B+2,A+1)<95
            B+1->B
         End
         Else
         [A](B+1,A+1)-15Z->C
         2(C=1)+(C=2)+14(C=3)+5(C=14)+6(C=5)+3(C=6)+8(C=7)+9(C=8)+10(C=9)+7(C=10)+13(C=4)+12(C=13)+11(C=12)+4(C=11)->C
         C+15Z->[A](B+1,A+1
      End
      real(1,8A+V,8B+W,1,8,6,round(12fPart([A](B+1,A+1)/12),0),8iPart([A](B+1,A+1)/12),0,0,0
      real(12,3,8A+V,8B+W,8A+V+7,8B+W+7,1
   End
   real(2,1,0,0,12,8,0,12,0,8,6,0,8,0
   If V+W
   real(4,(W=4)+3(V=4)+3(VW=16),4,0
   real(6
   theta+1->theta
End


It creates a new file "thetathetaZZLOOP" to save current level and graphical preference, the picture is the same (could be modified to look better), and the level appvar/prgm has lost it's first line, and I've ported over 10 more levels.

Please feel free to comment with suggestions to optimize on speed or size.
NoahK wrote:

Code:
(..)
For(A,1,8
For(B,1,12
inString("0123456789ABCDEF",sub(Str2,12(A-1)+B,1))-2
If Ans!=~1

I guess this is always true, inString returns a number from 0 upto the length of the string.
Secondly, I recommend you to replace

Code:
0->C
Repeat sub(Str1,C,1)!="0
C+1->C
End
with this:
Code:
0
Repeat sub(Str1,Ans,1)!="0
Ans+1
End
Ans->C
which is much faster
PT_ wrote:

I guess this is always true, inString returns a number from 0 upto the length of the string.


Ah, at the end of that line, I am subtracting 2, so -1 would correspond with the string being "0", which, for the game, is a blank space and has to be handled a special way.

The Ans usage is definitely faster, thanks for recommending that.


Another thing: Is there a better way to store this than in a matrix. Matrices are memory heavy, make for cumbersome number<->coordinate code, and are probably the slowest thing to read and write to as far as BASIC variables go. I want to use something smaller and faster, possibly a list, but I have been using the matrix to do spritemap (though, in hindsight, I may not need to do that now that I changed how things are displayed). Would a list be a good option? What else could I use?
NoahK wrote:
PT_ wrote:

I guess this is always true, inString returns a number from 0 upto the length of the string.


Ah, at the end of that line, I am subtracting 2, so -1 would correspond with the string being "0", which, for the game, is a blank space and has to be handled a special way.


You could remove "0" from the search string. If inString( can't find the character it returns -1.


Code:
inString("123456789ABCDEF",sub(Str2,12(A-1)+B,1
If Ans+1

However, this would make "1" return 1 instead of 0.
Yeah, so for my purposes, removing "0" from the search string would not do me much good. My current code allows me to check for blanks ("0"'s) while simultaneously adjusting the numbers in a way that lines up with the sprites in the PicVar.
I have contacted the developer of ∞ Loop via email, and he loves the idea of a port, and has even worked on some 8x8 sprites and a splashscreen, which I will use un the game, probably abandoning my own implementations in respect for the original dev's work. I asked him yesterday if he could send me the level's initial and solved states in some form, to which he has not replied yet (I am not expecting fast responses), but looking into it, it seems that most of the levels are randomly generated. A Google search came up with no definite results as to what algorithm was/can be used, and I have no idea where to start. If anyone has any ideas into how levels of increasing size/intricacy could be randomly generated for this game, please post a reply. And, as always, feel free to comment on any optimizations or questions you have.
Alright, here's the deal. I have totally scrapped attempting to store levels individually, because without a time-consuming compression/decompression algorithm, I can only store 600 levels in a 64kB AppVar. So, that being said, I have created an algorithm that generates random levels. Here is some updated (albeit un-optimized) code, nicely annotated for your reading pleasure.


Code:

:DCS6
// An updated icon, per the suggestion of the original App dev.
"00000000000000003E7C7F3EE387C183C183C183E1C77CFE3E7C000000000000"
ClrHome
FnOff
AxesOff
real(0,0
real(1,36,26,3,13,6,3,50,0,0,1
// Credit to the dev
Text(51,5,"TI-BASIC port by NoahK of
Text(57,5,"an App by Jonas Lekevicius

// Make sure the savefile exists and stuff, changed it to an AppVar
det(0,"rowSwap(thetathetaZZLOOP",5
If det(0,"rowSwap(thetathetaZZLOOP
det(0,"rowSwap(thetathetaZZLOOP
If 1=det(5,"rowSwap(thetathetaZZLOOP",0
Then
   det(6,"rowSwap(thetathetaZZLOOP","1",1
End

//loads the most recent level
expr(det(5,"rowSwap(thetathetaZZLOOP",1->theta
Repeat 0// On-Breaks are currently the only way to exit, not really a problem

   //saves the current level
   det(8,"rowSwap(thetathetaZZLOOP",det(1,theta),1
   
   //Here goes the level generator

   //seed the random
   9090sqrt(abs(sin(cos(theta->rand
   //make a level-dependent sized matirx
   4.5log(theta)+2->B
   9log(theta)/3+2->C
   B+(2rand-1)2log(theta)->E
   C+(2rand-1)4log(theta)/3->D
   max({2,D->D
   max({2,E->E
   iPart(min({8,D->D
   iPart(min({12,E->E
   {2D-1,2E-1->dim([C]
   Fill(0,[C]
   //Ranomply select pieces to connect
   (rand-.5)/8+.4->C
   For(A,1,2D-1
      For(B,1,2E-2,2
         If rand>C
         1->[C](A,B+2fPart(A/2
      End
   End
   For(A,1,D-1
      If rand>C
      1->[C](2A,2E-1
   End
   //Display the spash screen, design as per the dev instructed
   {D,E->dim([A]
   real(0,0
   real(1,36,26,3,13,6,3,50,0,0,1
   //set up matrix [A] with the right pieces to connect the connections in [C]
   For(A,1,D
      For(B,1,E
         [C](2A-1,2B-1+(B<E))+2[C](2A-1+(A<D),2B-1)+4[C](2A-1,2B-1-(B>1))+8[C](2A-1-(A>1),2B-1)->F
         35(F=0)+0(F=15)+1(F=5)+2(F=10)+3(F=1)+4(F=13)+5(F=4)+6(F=8)+7(F=6)+8(F=12)+9(F=9)+10(F=3)+11(F=14)+12(F=7)+13(F=11)+14(F=2)->[A](A,B
      End
   End
   //Display the level number
   real(0,1
   Text(~1,28,42-3iPart(log(theta)),"#",theta
   [A]->[B]
   //randomly turn the pieces in [A] to form the scrambled version"
   For(A,1,D
      For(B,1,E
         randInt(0,3->G
         [A](A,B->C
         For(F,1,G
            35(C=35)+2(C=1)+(C=2)+14(C=3)+5(C=14)+6(C=5)+3(C=6)+8(C=7)+9(C=8)+10(C=9)+7(C=10)+13(C=4)+12(C=13)+11(C=12)+4(C=11)->C
         End
         C+45->[A](A,B
         45+[B](A,B->[B](A,B
      End
   End
   //And that ends the random level generator
   dim([A]->L1
   L1(1->S
   L1(2->T
   4(12-T->V
   4(8-S->W

   //Draw the level in the background (buffer)
   real(0,0
   For(A,1,S
      For(B,1,T
         [A](A,B
         If 80>Ans
         real(1,8(B-1)+V,8(A-1)+W,1,8,6,round(12fPart(Ans/12),0),8iPart(Ans/12),0,0,0
      End
   End
   0->A
   0->B

   //update the screen while highlighting the upper-leftmost piece
   real(12,8,8A+V,8B+W,8A+V+7,8B+W+7,1
   
   //begin the gameplay
   Repeat [A]=[B]

      //de-select the current piece
      real(12,8,8A+V,8B+W,8A+V+7,8B+W+7,0
      [A](B+1,A+1
      //If the selected piece isn't a blank space, draw it to the buffer
      If 80>Ans
      real(1,8A+V,8B+W,1,8,6,round(12fPart(Ans/12),0),8iPart(Ans/12),0,0,0
      Repeat Ans
         getKey
      End
      Ans->G
      If max(G={24,25,26,34
      Then

         //some very un-optimized code to change the current selected piece according to geyKey
         If G=24 and A>0:Then
            A-1->A
         End
         If G=26 and A<(T-1:Then
            A+1->A
         End
         If G=25 and B>0:Then
            B-1->B
         End
         If G=34 and B<(S-1:Then
            B+1->B
         End
         Else

         //This is important. Random levels may have more than one solution, so if the user finds a solution that is not what is stored in [B], "Graph" can be pressed to start this snippet of code, which checks for the completion of the puzzle
         If G=15
         Then
            ClrHome
            Output(1,1,"Checking..."
            Fill(0,[C]
            //locate where the endpoints of the pieces are facing
            For(N,1,S
               For(O,1,T
                  [A](N,O)-45->P
                  [C](2N-1,2O-1+(O<T))+max(P={0,1,3,4,9,10,12,13->[C](2N-1,2O-1+(O<T
                  [C](2N-1,2O-1-(O>1))+max(P={0,1,4,5,7,8,11,12->[C](2N-1,2O-1-(O>1
                  [C](2N-1+(N<S),2O-1)+max(P={0,2,7,10,11,12,13,14->[C](2N-1+(N<S),2O-1
                  [C](2N-1-(N>1),2O-1)+max(P={0,2,4,6,8,9,11,13->[C](2N-1-(N>1),2O-1
               End
            End
            0->P
            1->N
            //Find a connection where only 1 piece is pointed towards it, for if this exists, the puzzle is not completely closed yet.
            Repeat N=2S
               1->O
               Repeat O=2T
                  If 1=[C](N,O
                  Then
                     2T-1->O
                     2S-1->N
                     1->P
                  End
                  3->[C](N,O
                  O+1->O
               End
               N+1->N
            End
            //If there was no open connections, set [B] to [A], which would make the Repeat loop for level completion stop looping.
            If not(P
            [A]->[B]
            ClrHome
            Else
            //If getKey isn't the arrows or Graph, rotate the selected piece clockwise
            [A](B+1,A+1)-45->C
            35(C=35)+2(C=1)+(C=2)+14(C=3)+5(C=14)+6(C=5)+3(C=6)+8(C=7)+9(C=8)+10(C=9)+7(C=10)+13(C=4)+12(C=13)+11(C=12)+4(C=11)->C
            C+45->[A](B+1,A+1
         End
      End

      //draw the selected character in the buffer, then invert it and update the LCD
      [A](B+1,A+1
      If 80>Ans
      real(1,8A+V,8B+W,1,8,6,round(12fPart(Ans/12),0),8iPart(Ans/12),0,0,0
      real(12,8,8A+V,8B+W,8A+V+7,8B+W+7,1
   End//of level completion loop
   {S,T->dim([C]
   Fill(15,[C]
   //prepare [B] for displaying the solved state
   [B]+[C]->[B]
   real(0,0
   //Do a tilemap for speed, but because the xLIB DCS routine doesn't draw on the last (64th) line,
   real(2,1,0,0,T,S,0,T,0,S-1,6,0,8,0
   //then cycle through the last line and draw it as individual sprites
   For(A,1,T
      real(1,8(A-1),8S-8,1,8,6,iPart(12fPart([B](S,A)/12)+.5),8iPart([B](S,A)/12),0,0,0
   End

   //center the level on the screen, invert the colors, and update the LCD
   real(4,3,V,0
   real(4,1,W,0
   If V
   real(12,7,0,0,V-1,63,0
   If W
   real(12,7,0,0,95,W-1,0
   real(12,8,0,0,96,64
   real(6
   //on to the next level!
   theta+1->theta
End
So, the game is all done, gameplay is smooth and the graphics are nice and the levels generate randomly, just as intended. But I have one small issue: tilemaps.

The program uses the DCS reincarnations of the xLIB tilemap routines to run, eg. real(2,blah,blah,...). But it does not seem that the routine draws on the 64th row of pixels.

Setting [A] to:
Code:
[[0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0][0,0,0,0,0,0,0,0,0,0,0,0]]

with Pic1 that has

Code:
########
#______#
#______#
#______#
#______#
#______#
#______#
########

in its top-lefthand corner, any variation/combination of

Code:
real(2,0,0,0,12,8,0,12,0,8,1,LOGIC,8,ULCD)

fails to draw a black line at the bottom of the screen.
Kerm and I discussed this over SAX for a while this afternoon, and no solutions came up (and no problem was found in source). I am using DCS7.2b3 on a 2.40 ROM version 84+SE
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement