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.

»
» 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