Jump to content

Photo

"Laser Strike" COMPUTE! Magazine program conversion

COMPUTE!

22 replies to this topic

#1 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Mar 15, 2018 10:04 AM

As with Tiles, Laser Strike is another COMPUTE! Magazine type-in program published after the magazine dropped the TI-99/4A, and is another program for which I received permission to sell and distribute my conversion for the TI-99/4A.

 

Laser Strike appears in COMPUTE! Magazine Issue 79, December 1986, Pp. 44-62.  Article  text here .

 

""Laser Strike" is a strategy game based on several popular board games (Battleship is probably the most famous). However, unlike the board games, the action in Laser Strike occurs in outer space. Two players secretly deploy their spaceships around the galaxy and then try to locate the opponent's ships by firing laser strikes on the two-dimensional galaxy grid. The first player to find and destroy all the opponent's ships is the winner."

 

This post contains my 1988 versions.  The first version has a rather simple A.I., which pokes around the board then follows a very simple search around looking for other parts of a hit ship.  The second version has a very sinister A.I. which immediately knows where the rest of a ship is on the grid once it finds one.  A computer player is created with a blank player name (just press ENTER when prompted for the player's name.)

 

Attached File  LaserStrike.png   2.18KB   6 downloads

 

Over the next few months I will be working on cleaning and modernizing this program as I did with Tiles.  A TidBit source, revamped over the ill-advised GCHAR method I use to build the "grids," including a more clandestine placing of computer player ships, and potentially a two-computer player-vs-player system via serial.

 

The listings below contain CTRL characters which do not translate to text.

 

TI BASIC Listing: LASERSTRIK

Spoiler

 

TI BASIC Listing: LASERSTRK+ (sinister A.I.)

Spoiler

Attached Files



#2 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Mar 15, 2018 6:32 PM

:lol:  I just noticed the last two lines of each program is a simple memory sizer for TI BASIC.  An old trick I picked up from a newsletter which came from some magazine.  If you RUN 288 or RUN 330 the variable AP will increase by 8 until the stack fills up with entries from the following GOSUB.  Then PRINT AP and you will get the number of available bytes: 2248 for the first version, 1440 for the second.

 

Attached File  laser_memory.png   2.23KB   3 downloads



#3 Vorticon OFFLINE  

Vorticon

    River Patroller

  • 3,216 posts
  • Location:Eagan, MN, USA

Posted Fri Mar 16, 2018 4:53 AM

Cool trick!



#4 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Fri Mar 16, 2018 4:28 PM

For comparison:

 

Attached File  memory.png   2.2KB   1 downloads



#5 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Tue Mar 27, 2018 10:47 PM

Here is a Tidbit snippet showing the ridiculous ways I tend to get complex trying to avoid redundant or repeating sections, IF-THENs, and branches.  This shit is what drives me nuts writing programs and why I could not do this professionally as I obsess and agonize over a short section for hours or days.
 

FOR Y=R+(5-I)*(J=4) TO R-(5-I)*(J=3)         // Check horizontal spacing
IF (Y<1)+(Y>10)+G(P,ABS(Y),C) THEN DeployError      // ABS() fixes negative subscript during OR operation
NEXT Y
FOR X=C+(5-I)*(J=1) TO C-(5-I)*(J=2)         // Check vertical spacing
IF (X<1)+(X>10)+G(P,R,ABS(X)) THEN DeployError      // ABS() fixes negative subscript during OR operation
NEXT X
CALL VCHAR(8+R+(5-I)*(J=4),C-10+14*P,104+8*I,(I-6)*(J>2))
CALL HCHAR(8+R,C+(5-I)*(J=1)-10+14*P,104+8*I,(I-6)*(J<3))

The most painful discovery and wrench in my progress was that FOR-NEXT-STEP does not accept "0" as a STEP.  Makes perfect sense but I was thinking a zero STEP would just cause the loop to be skipped.  There are other sections which are vexing me but I am breaking them up.  I have added a couple of "features" which have made things a little more complex, but I have also removed some things which have made program, like that above, less complex.  One removed feature of my conversion is the ability to lay a ship in any direction from the marker, whereas the original game only let you lay it RIGHT or DOWN, both positive directions.

 

That HCHAR and VCHAR will put out nothing if the repeat value is zero meant I could try to plot in both directions without using an IF-THEN statement and the execution penalty was negligible for this section.  Ultimately a wiser decision was made and this trick, while really cool, is no longer used.



#6 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Tue Mar 27, 2018 11:16 PM

Here is something REALLY weird I ran into tonight testing the "AI" for deploying computer ships in Classic99.  This section of program:

 

DeployComputerShip: 
   RANDOMIZE
   R=INT(RND*10)+1
   C=INT(RND*10)+1
   ON INT(RND*2)+1 GOSUB DeployXCheck,DeployYCheck
   IF G(P,R,C)<>I THEN DeployComputerShip ELSE DeployNextShip

 

without the RANDOMIZE statement produces the EXACT SAME results for both computer players -- that is, both player's ships are laid in exactly the same positions -- every time the program is run.  There is a RANDOMIZE statement earlier in the program in the execution path so I do not expect this behavior.

 

I have no idea if this behaves the same way on metal. What gives?



#7 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Mon Apr 2, 2018 10:11 PM

All parts of game setup and play are completed including the introduction marquee.  All that remains is the AI and I will be done, much to relief of those around me as my time and thoughts are consumed with this project.

 

I have had a revelation while reworking this program: I am tired of TI BASIC.  When I originally wrote these programs all I had was a console and a tape drive.  Thus such configuration was my target audience should these ever be published.  It was also a challenge to do some of the stuff these more advanced BASICs of other computers could do.  Now, however, Extended BASIC makes the limitations of BASIC just plain aggravating, and that is notwithstanding assembly language.

 

I have four more programs which need to be redone, all of them originally written in TI BASIC and one of which took advantage of capabilities offered by MiniMemory in BASIC with an alternate version which also leveraged some assembly routines.

 

I have not yet decided if I will rework them all in TI BASIC or Extended BASIC.  The idea originally was to make them as "type-in friendly" as possible.  I would still like to meet that if only for nostalgia, otherwise right now TI BASIC is not fun to me; it is frustrating and I am getting to the point where I never want to fire up BASIC, again.

 

If you want to see how it looks right now without the AI -- any computer player will fall through to human player -- see below.  I believe it works exactly as desired as a two-player game in its current form.  It can be pasted into Classic99.  EXSD for Player 1, IMJK for Player 2, SPACE for both, joysticks work, too.  Ships will be deployed onto your opponent's grid.  That is, Player 1 deploys onto GRID 2, and vice-versa.  When deploying the "plus" mark indicates to select a direction, right or down.

 

Spoiler


#8 Opry99er OFFLINE  

Opry99er

    Quadrunner

  • 9,788 posts
  • Location:Hustisford, WI

Posted Mon Apr 2, 2018 10:22 PM

Awesome stuff there, broseph...  I am very much enjoying observing this process.  :)

 

 

But don't give up on console BASIC so easily... There is untapped potential there, and you've obviously got the knack for it (especially now with TIdBiT in the toolbelt)



#9 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Tue Apr 3, 2018 8:02 AM

I definitely agree that my frustration level would be over 9000 right now were it not for Tidbit.

 

Here are some screen shots from play, me versus myself as the computer player

 

Attached File  LaserStrike-new(a).png   2.39KB   2 downloadsAttached File  LaserStrike-new(b).png   2.41KB   2 downloadsAttached File  LaserStrike-new(c).png   2.69KB   2 downloadsAttached File  LaserStrike-new(d).png   2.73KB   2 downloads



#10 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Wed Apr 4, 2018 8:24 PM

Working up an AI for this, I found some really neat articles on algorithms for playing Battle Ship.  I have been working up a flow chart (ick!) to build my own AI and resisting the urge to just copy the one used in the original game.

 

Once I release the final version I will include some of the articles I found, whether I implement any of them or not it still makes for interesting reading.



#11 Vorticon OFFLINE  

Vorticon

    River Patroller

  • 3,216 posts
  • Location:Eagan, MN, USA

Posted Thu Apr 5, 2018 11:40 AM

Quick and dirty algorithm:

1- Random shots until hit recorded. Set hit flag.
2- systematic test of the 4 cardinal directions for additional hits unless bounded by edge or previous shots.
3- Follow cardinal direction where hit recorded. If sunk, then clear hit flag and go to 1. If hit go to 3. If no hit then reverse cardinal direction starting with initial hit and go back to 3.

This obviously can be refined further by pre-scanning the grid and creating a list of all possible locations where a particular target could be residing, sorted by ship size. Not terribly helpful until about 50% of the grid has been shot at. It's slow but will make the AI extremely deadly...

#12 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Apr 5, 2018 12:08 PM

Essentially my flow chart goes like this:

 

Check for any ships with hits and parts remaining

Check spacing in all four directions

If only one part has been hit:

Is there a miss adjacent?

Does the ship fit in one direction versus another?

Try the best possible direction, or pick one if more than one.

If multiple parts have been hit:

Is it horizontal or vertical?

Check spacing in both directions

Fire at best possible spot.

 

Otherwise, look at four quadrants

Choose quadrant with most empty space (percentage-wise) less hit ship parts

Choose random spot in selected quadrant

check spacing: is it within space of longest remaining ship?

Fire at best possible or random spot if no best spot, giving space for shortest remaining ship.

 

I want the AI to be a moderately capable opponent.  I am considering using the other player's "score" to determine how analytical the AI becomes.

 

In my original iterations the AI could lose its place on a ship after determining its location by poking around randomly.  The second version automatically knows where the rest of a ship is when it first finds it (cheats in that regard, but the initial find is also random.)



#13 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Apr 5, 2018 7:48 PM

AI aside, hearkening back to the use of complex formulas, the question becomes is performance more greatly impacted by using a formula like C+32+14*P or an array like C+GX(P).

 

For something that small (number added to number times variable) it may not make a difference, but what about C+14*P-10-42*(P<0) where you are expecting values P={-2,-1,1,2}, but you still have to reference the array by taking a variable and adding a number.  Thus, GX(P+3) to return GX({1,2,4,5}).  I would assume the act of "variable plus number times variable minus number minus variable compared to number times number," noting the parenthesis has to be interpreted for precedence order, would take longer than "array lookup of element variable plus number."

 

Just more to obsess.  I have memory available to set up some arrays for the longer formulas so that is not a concern.



#14 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Apr 5, 2018 9:46 PM

Another thing I learned while working on Tiles is not everything runs the same in emulation and on the metal.  I played this a little tonight on a real console and am very pleased with the results, in particular the sounds.  BASIC is very difficult to get just the right sounds.  Partly because when the 9919 gets a new noise command it restarts the noise generator.



#15 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Sun May 13, 2018 9:48 PM

Here is an irritating thing I have found with IF/THEN/ELSE that I cannot figure out.

 

I like to cut down on the logic in IF/THEN/ELSE statements by using variables as the expression.  For instance,

IF G(P,0,0)THEN 2270 ELSE 2540

Even though in this statement G(P,0,0) is always 1 when executed, sometimes the ELSE clause is effected and execution is transferred to line 2540.

 

Stranger still is I do not see this behavior in my other programs.  I really have no idea WTF is going on but it is changing game flow and forcing me to use comparisons rather than zero and non-zero variables.  Really aggravating and so far I have not seen it happen in Extended BASIC, only console BASIC.

 

EDIT: yeah, I had no idea...



#16 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Sun May 13, 2018 10:45 PM

Sunnuva...!!!  Now, even with the comparison G(P,0,0)=0 execution is still going to the wrong place.  So far as I can tell there is no other way for program flow to get there.

 

*sigh*

 

EDIT: As well, I have found that my random numbers are the same each run, even with a RANDOMIZE statement earlier in the program. Almost as if it has a specific scope.  This is in Classic99 but I do not expect different behavior on a real console.  I will test tomorrow -- I am too tired to continue mucking about.


  • RXB likes this

#17 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Mon May 14, 2018 12:01 AM

Okay, thanks to the good ol' TRACE statement I was able to figure out that under some circumstances the check routine following is bouncing back to a line which it should not be.  That is, well after the decision but invisible to me because the program offers no other feedback.

 

Sunnuva...

 

HOWEVER, in order to not get a predictable repeat of random numbers I have to put a RANDOMIZE statement before each use of RNDTHIS is genuinely legit and frustratingly confusing.



#18 Ksarul OFFLINE  

Ksarul

    River Patroller

  • 4,672 posts

Posted Mon May 14, 2018 4:42 AM

RANDOMIZE resets the random seed number--one time. The seed will then follow a predictable sequence until RANDOMIZE is used again to reset the seed. There is also a considerable time hit for using RANDOMIZE, but it is worth it to ensure that your pseudo-random numbers are as close to truly random as you can make them. I explored this particular issue in detail when I was writing a character generation program for the 1st Edition of Advanced Dungeons and Dragons back around 1988.



#19 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Mon May 14, 2018 6:44 AM

Right, but the seed should be different for each program run with just a single RANDOMIZE statement, correct?  The game has lines like these:

 

200 R=INT(RND*10)+1

201 C=INT(RND*10)+1

 

If I only use the single RANDOMIZE earlier in the program then the values selected are demonstrably the same: ships get deployed in the same places every run and positions fired upon are the same.  Quite annoying.



#20 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Mon May 14, 2018 7:12 AM

Maybe the issue is one of timing?  For kicks and grins I put a short test program together and ran it a few times.  Notice the first and third runs produce the same series of numbers.  Based upon the behavior described above, I suspect if I had continued this I would have received more identical sets.

 

10 RANDOMIZE
20 PRINT INT(RND*10)+1;
30 GOTO 20

 

Attached File  Clipboard01.png   3.99KB   1 downloads



#21 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,695 posts
  • Location:Silver Run, Maryland

Posted Mon May 14, 2018 9:45 AM

A few things to remember with TI Basic regarding pseudo-random number generation:

  1. At program start, the random number seed at >83C0 always starts with the same number (>3567 in Classic99).
  2. RANDOMIZE uses the VDP interrupt timer value (1 byte, ticking 0 – 255) at >8379 to replace only the LSB of the seed at >83C0.
  3. At least in Classic99, the VDP timer only ticks (1 tick = 1/60 second) the LSN (Least Significant Nybble) of 4 bits (0 – 15) while in command mode.

Your comment about timing is, indeed, relevant.  At program start (RUN), the VDP timer jumps into the  0 – 255 timer cycle with a value of 0 – 15.  With RANDOMIZE as the first statement, there is a high likelihood that the seed will start with the same number.  If the VDP timer were zeroed at program start, it would be a virtual certainty.

 

One thing you might try is to run RND without a limit before RANDOMIZE to force a change in both bytes of the seed.  RND calls the GPL RAND function at least 7 times, with each call to RAND swapping the bytes of the seed before beginning its calculations.  This makes RND a good bit slower than RANDOMIZE, by the way [Edit: 0.0125 s vs. 0.0015 s]:

10 A = RND
20 RANDOMIZE
30 PRINT INT(RND*10)+1;
40 GOTO 30 

Edit: Actually, RANDOMIZE should be run before RND to avoid starting with another constant. So, perhaps, the following:

10 RANDOMIZE
20 A = RND
30 RANDOMIZE
40 PRINT INT(RND*10)+1;
50 GOTO 40 

...lee



#22 OLD CS1 OFFLINE  

OLD CS1

    Quadrunner

  • Topic Starter
  • 5,313 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Mon May 14, 2018 11:22 AM

Thanks for the insight.  Except for the un-bounded RND, I am doing close to the same at this point.  In the game I have a RANDOMIZE in the loops immediate before using RND, which follows after other RNDs.  So far the results are satisfying, but I have no technical details on what it is doing in the background.  I will try with the un-bounded RND and see if that makes a difference.



#23 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,695 posts
  • Location:Silver Run, Maryland

Posted Mon May 14, 2018 12:46 PM

Thanks for the insight.  Except for the un-bounded RND, I am doing close to the same at this point.  In the game I have a RANDOMIZE in the loops immediate before using RND, which follows after other RNDs.  So far the results are satisfying, but I have no technical details on what it is doing in the background.  I will try with the un-bounded RND and see if that makes a difference.

 

I only suggested the unbounded RND because it eliminates the multiplication and truncation steps.  It has no effect on the seed.

 

...lee







Also tagged with one or more of these keywords: COMPUTE!

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users