|
Post by plus on Jul 30, 2024 6:36:03 GMT
Don't miss my last post on page 1, it's possible to skip because I posted these 2 back to back. OK and even more exciting is this: The Computer AI Action Flik See how the Computer AI tracks down and sinks the Players ships without interruption from the Player, you will still have to answer the Notices ' Computer AI Action Flik ' Battleship Mod842 b+ 2024-07-25 uses a garanteed AI to find Destroyer in 50 shots ' unlike Battleship 2 which AI uses mod 3 it is screwed if fails to find Destroyer when mod 3 shooting ' covers the ocean taking something like up to 66 shots to garantee finding Destroyer. ' 2024-07-26 some improvements when showing where computer ships were if it wins, show only parts not shot. ' add sounds for when a ship gets tada for when player gets computer ship, ding when computer gets your ship. ' Thanks John T and again thanks to tsh73 who got me inspired for restarting Battleship AI experiments.
' This code starts from my first Battleship coded for JB: ' Battleship based on Hasbro Game b+ 2024-07-23 allot of code ported out of old QB64 version
Global PXO, PYO, CXO, CYO, SXO, SYO Global dir, aiI, currentHits, pTurn, GameOn ' preserve between AI calls Global x1, y1, bombx, bomby, hit2 '''''''''''''''''''''''''''''''''' Set Once and forget it! ''''''''''''''''' PXO = 5 : PYO = 6 ' offsets for player grid CXO = 32 : CYO = 6 ' offsets for computer grid player shoots at SXO = 65 : SYO = 10 ' offsets ship tally DIM shipLen(10), shipName$(10), AIshots$(50) For i = 1 To 10 ' not sure I need names yet Select Case i Case 1: shipLen(i) = 5: shipName$(i) = "Carrier" Case 2: shipLen(i) = 4: shipName$(i) = "Battleship" Case 3: shipLen(i) = 3: shipName$(i) = "Cruiser" Case 4: shipLen(i) = 3: shipName$(i) = "Submarine" Case 5: shipLen(i) = 2: shipName$(i) = "Destroyer" Case 6: shipLen(i) = 5: shipName$(i) = "Carrier" Case 7: shipLen(i) = 4: shipName$(i) = "Battleship" Case 8: shipLen(i) = 3: shipName$(i) = "Cruiser" Case 9: shipLen(i) = 3: shipName$(i) = "Submarine" Case 10: shipLen(i) = 2: shipName$(i) = "Destroyer" End Select Next dim t(50) ' shuffle see Setup for i = 1 to 50 : t(i) = i : next
while 1 'run game loop until player quits scan call Setup call Shoot wend
sub Setup ' clear arrays and variables dim shipX(10), shipY(10), shipHor(10), shipHits$(10), shipSunk(10) ' not using 0 index dim p(9, 9), c(9, 9) pTurn = 0: GameOn = 0 ' globals ' for Computer AI dim hits(9, 9) dir = 0: aiI = 0: currentHits = 0 ' globals
'setup 2 bombing patterns to cover sea in checkerboard pattern one is chosen in each game s1$ = "A0B1C2D3E4F5G6H7I8J9I0J1A8B9E0F1G2H3I4J5A4B5C6D7E8F9C0D1E2F3G4H5I6J7A6B7C8D9G0H1I2J3A2B3C4D5E6F7G8H9" s2$ = "A9B8C7D6E5F4G3H2I1J0B0A1I9J8A5B4C3D2E1F0E9F8G7H6I5J4A3B2C1D0A7B6C5D4E3F2G1H0C9D8E7F6G5H4I3J2G9H8I7J6" If Rnd(0) < .5 Then shots$ = s1$ Else shots$ = s2$ ' don't be predictable with bombing patterns ' shuffle sections: priority diagonal then sub diagonals, Mod 8 then mod 4 then mod 2 start = 1 : stp = 10 : call shuff start, stp start = 11 :stp = 14 : call shuff start, stp start = 15 :stp = 26 : call shuff start, stp start = 27 :stp = 50 : call shuff start, stp for i = 1 to 50 ' stow into an array AIshots$(i) = Mid$(shots$, 2 * t(i) - 1, 2) next cls ' Game Board draw once per game Print "" Print " Player Computer" Print "" Print " A B C D E F G H I J A B C D E F G H I J" Print " ------------------- -------------------" Print " 0| . . . . . . . . . . 0| . . . . . . . . . ." Print " 1| . . . . . . . . . . 1| . . . . . . . . . ." Print " 2| . . . . . . . . . . 2| . . . . . . . . . ." Print " 3| . . . . . . . . . . 3| . . . . . . . . . . Ships: P C" Print " 4| . . . . . . . . . . 4| . . . . . . . . . . Carrier . ." Print " 5| . . . . . . . . . . 5| . . . . . . . . . . Battleship . ." Print " 6| . . . . . . . . . . 6| . . . . . . . . . . Cruiser . ." Print " 7| . . . . . . . . . . 7| . . . . . . . . . . Submarine . ." Print " 8| . . . . . . . . . . 8| . . . . . . . . . . Destroyer . ." Print " 9| . . . . . . . . . . 9| . . . . . . . . . ." Print " ------------------- -------------------" Print " A B C D E F G H I J A B C D E F G H I J" 'locate 5, 6: print "X" ' check offsets ' check AIshots$((aiI) OK 'for i = 1 to 50 'double check checker board coverage 50 cells in priority order ' x = instr("ABCDEFGHIJ", left$(AIshots$(i), 1)) - 1 ' y = val(mid$(AIshots$(i), 2, 1)) ' call LP x, y, "p", "O" ' call pause 500 'next For i = 1 To 10 ' restring ship hits shipHits$(i) = String$(shipLen(i), "o") Next call autosetup 0 call autosetup 1 end sub
Sub autosetup AItf ' there is surely a shorter way to do this but I am eager to get on with other stuff If AItf Then 'setup Computer's ships 'setup a board with ships, Computer or AI's setup For S = 6 To 10 OK = 0 While OK = 0 shipHor(S) = rand(0, 1) If shipHor(S) Then sy = rand(0, 9) sx = rand(0, 10 - shipLen(S)) OK = 1 For xx = 0 To shipLen(S) - 1 If c(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then shipX(S) = sx: shipY(S) = sy For xx = 0 To shipLen(S) - 1 c(sx + xx, sy) = S 'call LP sx + xx, sy, "c", str$(S mod 10) ' for debugg Next End If Else sx = rand(0, 9) sy = rand(0, 10 - shipLen(S)) OK = 1 For yy = 0 To shipLen(S) - 1 If c(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then shipX(S) = sx: shipY(S) = sy For yy = 0 To shipLen(S) - 1 c(sx, sy + yy) = S 'call LP sx, sy + yy, "c", str$(S mod 10) ' for debugg Next End If End If Wend Next Else 'setup Player's ships For S = 1 to 5 OK = 0 While OK = 0 shipHor(S) = rand(0, 1) If shipHor(S) Then sy = rand(0, 9) sx = rand(0, 10 - shipLen(S)) OK = 1 For xx = 0 To shipLen(S) - 1 If p(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then shipX(S) = sx: shipY(S) = sy For xx = 0 To shipLen(S) - 1 p(sx + xx, sy) = S call LP sx + xx, sy, "p", str$(S) Next End If Else sx = rand(0, 9) sy = rand(0, 10 - shipLen(S)) OK = 1 For yy = 0 To shipLen(S) - 1 If p(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then shipX(S) = sx: shipY(S) = sy For yy = 0 To shipLen(S) - 1 p(sx, sy + yy) = S call LP sx, sy + yy, "p", str$(S) Next End If End If Wend Next End If End Sub
sub message m$ locate 1, 20: print m$; end sub
sub clearMessage locate 1, 20: print space$(80); locate 1, 20: print "" end sub
sub LP x, y, pcGrid$, s$ if pcGrid$ = "p" then locate PXO + 2 * x, PYO + y else locate CXO + 2 * x, CYO + y Print s$; end sub
function rand(low, high) ' Random integer from low to high inclusive rand = int(rnd(0) * (high - low + 1)) + low end function
sub Shoot GameOn = 1 While GameOn scan 'If pTurn Then pTurn = 0 Else pTurn = 1 'If pTurn Then ' player ' Locate 1, 20: Input "Enter your next bomb site letter digit "; place$ ' If place$ = "" Then GameOn = 0 ' place$ = upper$(place$) ' bx = instr("ABCDEFGHIJ", left$(place$, 1)) - 1 ' by = val(mid$(place$, 2, 1)) ' if bx >= 0 and bx < 10 then ' better check ' if by >= 0 and by < 10 then ' If c(bx, by) <> 0 Then 'hit ' call LP bx, by, "c", "X" ' call hitEval "c", bx, by 'game could end here ' Else ' call LP bx, by, "c", "o" ' End If ' end if ' end if ' call clearMessage 'Else 'AI's turn if it gets a hit it will bomb around the ship until it is finished 'could be trouble if 2 ships are next to each other. Some effort to work it, still might get confused. 'hits() array tracks red = 1 and white pegs = -1 like a human player for AI
If dir Then 'we are working around the latest hit with bombx, bomby to test If p(bombx, bomby) <> 0 Then 'hit! hit2 = 1 hits(bombx, bomby) = 1: currentHits = currentHits + 1 call LP bombx, bomby, "p", "X"
'we need to know stuff but can't use this info for AI finding the ship 'when hitEval announces a ship sunk we can reduce the currentHits count by that ships amount 'if still have more current hits, continue bombing area as another ship is there call hitEval "p", bombx, bomby 'this will reduce currentHits by the amount a ship could take when sunk If currentHits = 0 Then 'clear our checklist we sank all ships we hit, call off bombing of area x1 = 0: y1 = 0: dir = 0 Else call decideWhereToBombNext End If Else 'no hit from checklist scratch off one item hit2 = 0 hits(bombx, bomby) = -1 call LP bombx, bomby, "p", "o" call decideWhereToBombNext End If ' are we still working on hit
Else 'not working on any hits x1, y1 = 0, dir = 0, currentHits might be = 0 'random but systematic shooting, bring up next good shooting location [alreadyHit] aiI = aiI + 1 ' next random shoot if aiI > 50 then ' we should never get this far but just in case x = rand(0, 9) y = rand(0, 9) else ' normal shooting pattern by diagonals to form checker board coverage x = instr("ABCDEFGHIJ", left$(AIshots$(aiI), 1)) - 1 y = val(mid$(AIshots$(aiI), 2, 1)) end if if hits(x, y) <> 0 then goto [alreadyHit]
' was that shot just fired a hit or miss If p(x, y) <> 0 Then ' test our shot just fired is hit! x1 = x: y1 = y 'save first hit to come back to hits(x1, y1) = 1: currentHits = currentHits + 1 call LP x1, y1, "p", "X" ' we need to know stuff but can't use this info for AI finding the ship ' keep the same as for the player call hitEval "p", x1, y1 'did we just happen to finish off a ship? current hits = 0 If currentHits = 0 Then 'must of finished off an ship x1 = 0: y1 = 0: dir = 0 'we are done Else dir = -1 ' this signals we are working on a hit call decideWhereToBombNext End If Else 'no hit hits(x, y) = -1 call LP x, y, "p", "o" End If End If 'rI was hit or not 'End If 'whose turn is it call pause 1500 ' a sec pause to allow us to see computers move Wend call message "Play Again? press y for yes, n for no..." k$ = input$(1) cls if k$ = "n" then end end sub
Sub hitEval board$, bbx, bby ' hmm I could have used Global pTurn and not pass board$ 'this is like a referee for both players to announce a ship sunk and a game won? If board$ <> "p" Then playwave "ding.wav" S = c(bbx, bby) ' which ship number you$ = "Player" my$ = "Computer's" istart = 6 istop = 10 Else playwave "hello.wav" ' tada sounds same as ding S = p(bbx, bby) you$ = "Computer" my$ = "Player's" istart = 1 istop = 5 End If If shipHor(S) Then d = bbx - shipX(S) + 1 Else d = bby - shipY(S) + 1 shipHits$(S) = SubStr$(shipHits$(S), d, "X") If shipHits$(S) = String$(shipLen(S), "X") Then shipSunk(S) = 1 If board$ = "p" Then currentHits = currentHits - shipLen(S) call updateStatus notice you$ + " sank " + my$ + " " + shipName$(S); "!" tot = 0 For i = istart To istop If shipSunk(i) = 1 Then tot = tot + 1 Next If tot = 5 Then call updateStatus ' might not need this call
if you$ = "Computer" then call ShowComputersShips ' not seeing ??? test again missed again
Notice "Congratulations " + you$ + ", you sank all " + my$ + " ships! GameOver..." GameOn = 0 End If End If End Sub
Sub decideWhereToBombNext 'find next good location, mark the direction we took If dir = -1 Then ' hit2 = 0 'when direction = 0 reset 2nd hit signal to 0 If x1 + 1 <= 9 Then If hits(x1 + 1, y1) = 0 Then bombx = x1 + 1: bomby = y1: dir = 1: Exit Sub End If End If 'still here? If y1 + 1 <= 9 Then If hits(x1, y1 + 1) = 0 Then bombx = x1: bomby = y1 + 1: dir = 2: Exit Sub End If End If 'still here? If x1 - 1 >= 0 Then If hits(x1 - 1, y1) = 0 Then bombx = x1 - 1: bomby = y1: dir = 3: Exit Sub End If End If 'still here OK this has to do it! If y1 - 1 >= 0 Then If hits(x1, y1 - 1) = 0 Then bombx = x1: bomby = y1 - 1: dir = 4: Exit Sub End If End If 'still here ???? damn! give up and go back to random shots dir = 0: Exit Sub ' < this signals that End If
'setup next bombx, bomby If hit2 Then 'whatever direction we are taking, continue if we can Select Case dir Case 1 If bombx + 1 <= 9 Then If hits(bombx + 1, bomby) = 0 Then bombx = bombx + 1: Exit Sub End If End If Case 2 If bomby + 1 <= 9 Then If hits(bombx, bomby + 1) = 0 Then bomby = bomby + 1: Exit Sub End If End If Case 3 If bombx - 1 >= 0 Then If hits(bombx - 1, bomby) = 0 Then bombx = bombx - 1: Exit Sub End If End If Case 4 If bomby - 1 >= 0 Then If hits(bombx, bomby - 1) = 0 Then bomby = bomby - 1: dir = 4: Exit Sub End If End If End Select End If
'still here? then we have to change direction and go back to x1, y1 the first hit hit2 = 0 'reset this for the new direction check While dir < 4 dir = dir + 1 Select Case dir Case 2 If y1 + 1 <= 9 Then If hits(x1, y1 + 1) = 0 Then bombx = x1: bomby = y1 + 1: Exit Sub End If End If Case 3 If x1 - 1 >= 0 Then If hits(x1 - 1, y1) = 0 Then bombx = x1 - 1: bomby = y1: Exit Sub End If End If Case 4 If y1 - 1 >= 0 Then If hits(x1, y1 - 1) = 0 Then bombx = x1: bomby = y1 - 1: Exit Sub End If End If End Select Wend 'still here, well we've run out of directions dir = 0 'back to random bombing End Sub
function SubStr$(s$, place, subst$) for i = 1 to len(s$) if i = place then r$ = r$ + subst$ else r$ = r$ + mid$(s$, i, 1) next SubStr$ = r$ end function
function String$(number, s$) for i = 1 to number r$ = r$ + s$ next String$ = r$ end function
Sub updateStatus ' ships area For i = 1 To 5 ' row 10 carrier player colum 66 computer column 68 If shipSunk(i) Then Locate 65, i + 9: Print "X"; If shipSunk(i + 5) Then Locate 67, i + 9: Print "X" Next End Sub
sub ShowComputersShips For S = 6 To 10 If shipHor(S) Then sx = shipX(S): sy = shipY(S) For xx = 0 To shipLen(S) - 1 If Mid$(shipHits$(S), xx + 1, 1) = "o" Then call LP sx + xx, sy, "c", str$(S mod 10) Next Else sx = shipX(S) : sy = shipY(S) For yy = 0 To shipLen(S) - 1 If Mid$(shipHits$(S), yy + 1, 1) = "o" then call LP sx, sy + yy, "c", str$(S mod 10) Next End If Next end sub
sub pause mil 'tsh version has scan built-in t0 = time$("ms") while time$("ms") < t0 + mil : scan : wend end sub
sub shuff start, stp for i = stp to start + 1 step -1 r = rand(start, stp) temp = t(i) t(i) = t(r) t(r) = temp next end sub
Seeing this run for awhile I can see where my Computer AI can be improved. When hitting 2 ships next to each other it seems to be calling off the attack when one ship is sunk. It is suppose to see that currentHits is not 0 yet another hit is unaccounted for so it sould go back to it's first hit x1, y1 if I recall and try a new direction from there or try new directions along the ship just sunk. I can make this AI better! Update: uh oh! It is possible for the AI to not finish off a second ship hit until long after the 50 shots are all used up and random firing is needed to find that hole. I did need this code "escape clause"! if aiI > 50 then ' we should never get this far but just in case x = rand(0, 9) y = rand(0, 9)
b = b + ...
|
|
|
Post by tsh73 on Jul 30, 2024 13:31:54 GMT
I see then it make second hit RIGHT and in a third hit RIGHT falls off the ship, it continues DOWN from first hit (and of cource misses - ship is a line, so it should shoot LEFT!)
|
|
|
Post by plus on Jul 30, 2024 14:09:34 GMT
It does try RIGHT first after every new hit, thats programmed. When that does not lead to hit it does try South, Down. No hit that way then try LEFT. No hit, then try North, up. Still no hit (hit2 variable a 2nd hit after hit variable) after trying all 4 directions (Dir variable) then it goes back to random shooting from the AiShots$(AiI) array. It's presently calling off the attack in the area too soon. It might go back to first hit after shot from AiShots$(AiI) array and try another direction even with a hit from one direction. The signal to do that is when CurrentHits > 0 right after deducted a newly ship sunken from CurrentHits Count. That might be hard to understand without familiarity with code. Anyway, my next step for improving the AI is to allow Player to setup scenario's to test the AI handling with bunches of ships side by side. A little more participation in The Computer AI Action Flik. BTW in the middle of not sleeping last night the idea hit me. "hey show movies with JB don't just try to explain with words." I more that just liked the idea, I jumped up and did it! and Rod was there up late too and saw it first! b = b + ...
|
|
|
Post by tsh73 on Jul 30, 2024 14:13:16 GMT
Yes, idea of movie is a great one.
|
|
|
Post by plus on Jul 30, 2024 20:36:25 GMT
I see then it make second hit RIGHT and in a third hit RIGHT falls off the ship, it continues DOWN from first hit (and of cource misses - ship is a line, so it should shoot LEFT!) OK I get it now! If have success going right then try left when can't go right any further THEN try the vertical directions. OK good! 1st improvement to AI. Update: yep saves an extra shot or 2. I just realized this AI can be defended with vertical ships because horizontals are always tested first. Also I have started some error checking code on player's input so program doesn't bug out when human makes an error. ie human shoots same shot again on ship already sunk, "Congrats you sunk my Battleship (again!)" LOL b = b + ...
|
|
|
Post by plus on Aug 1, 2024 16:38:24 GMT
I am studying cases when/where AI fails to sustain an attack when current hits > 0 after a ship is sunk. The attack needs to persist for the original hit area until currentHits is zero, = no ships left in area of first hit in sequence after random fire gets a first hit. Towards that end I need to restructure: Add HitX(), HitY() track where we have hits 1, 0 for untested yet I suppose we have to track if missed at that spot too, -1 that would replace X1, Y1 with the array ordered by hitIndex, kinda of confused at moment to include misses or not. BTW 17 is max amount of hits possible if you hit everything on Board, could have a cluster convoy. Dir() = 0 1 2 3 4 test all 4 directions for each hit, 0 no direction tested, 5 all directions tested and so hitIndex for that place is played out the 3 above are indexed with hitIndex When currentHits does go to 0 after all ships sunk then call new ZeroOutHits sub maybe need a tryThisIndexNext global also when deciding where to bomb next, set to 1 in ZeroOut This would track where we are in the hit List. Well that sketches out my next mods and experiment towards a more intelligent AI. There, you 'all have it in my words before the code is written! b = b + ...
|
|
|
Post by plus on Aug 2, 2024 1:09:53 GMT
Turns out I needed an array for each possible direction for each hit.
I got the AI working perfectly, persisting in an attack even after it sinks a ship IF CurrentHits is still > 0 after the sunkin ships length is deducted from the CurrentHits tally it means there is still another ship already hit in the vicinity! So the AI reviews all the recent hitX(), hity() locations and tests every direction from them looking for that partly hit ship. And it finds it and finishes it off before going back to random shooting pattern hunting for next ship to sink.
' JB port BS Mod842 Counting Hits 1 2024-08-01" ' b+ 2024-07-26 port from JB ' Battleship Mod842 b+ 2024-07-25 uses a garanteed AI to find Destroyer in 50 shots ' unlike Battleship 2 which AI uses mod 3 it is screwed if fails to find Destroyer when mod 3 ' shooting covers the ocean taking something like up to 66 shots to garantee finding Destroyer. ' This code starts from my first Battleship coded for JB: ' Battleship based on Hasbro Game b+ 2024-07-23 allot of code ported out of old QB64 version ' 2024-07-26 besides port trans back to QB64, fix the showing of computer ships so only the ones ' or parts not hit with ship number. Add Sound when ship is hit.
' 2024-07-29 Oh I forgot, MessageBox does not work for older versions of QB64. ' Actually that turns out to be no problem at all!!! ' I think I can use View Print and not need my Message and Message Clear subroutines. ' This might be a very cool fix! Also I am going to work on my organization and commenting. ' OK View Print did not scroll inside the view text port so I had to cls before turning off ' View Print. I was thinking scrolling would be cool, no cls needed but no.
' Fix a bug that has been here from beginning, check player's bomb site to see if already done ' if so BEEP him, definitely don't want to sink a ship twice which is what has been happening. ' So we should use computer c() to track players shots. -1 for miss but what about when ship ' is hit??? c(x, y) = c(x, y) + 10 so if c(x, y) is > 5 and < 11 then good hit. ' if c(x,y) > 10 then already hit. BEEPing now for places already bombed plus give player another ' chance to shoot.
' Need to check place$ to see if player screwed up placement instructions, done.
' 2024-07-30 BS Mod842 AI Movie - last night I got this great idea and want to share it. ' This Movie shows The Computer AI in action finding and sinking ships, it does so with ' minimum interruption from viewer/Player. I do want to set it so the Player can setup ' tricky ship placements to test how well the AI handles them, also excellent tool to ' improve the AI because just watching a number of these I see AI failures clearly some ' holes left in coverage...
' 2024-07-30 BS Mod842 AI Movie 2 tsh suggest if running successfully one way and stop ' the reverse direction and go opposite ie heading dir 1 right then go left if stopped.
' 2024-07-31 still with Movie 2 - Take out View Print with Locate and ClearPartial sub ' to clear only bottom part of screen. Now I have code portable to all Basics.
' 2024-08-01 BS Mod 842 Counting Hits as posted at JB today: ' ========================================================================================================= ' I am studying cases when/where AI fails to sustain an attack when current hits > 0 after a ship is sunk. ' The attack needs to persist for the original hit area until currentHits is zero, = no ships left in ' area of first hit in sequence after random fire gets a first hit. ' ' Towards that end I need to restructure: ' Add HitX(), HitY() track where we have hits 1, 0 for untested ' yet I suppose we have to track if missed at that spot too, -1 ' that would replace X1, Y1 with the array ordered by hitIndex ' kinda of confused at moment to include misses or not. ' BTW 17 is max amount of hits possible if you hit everything on Board, could have a cluster convoy. ' ' Dir() = 0 1 2 3 4 test all 4 directions for each hit, 0 no direction tested, ' 5 = all directions tested and so hitIndex for that place is played out ' ' the 3 (new arrays) above are indexed with hitIndex (global) ' ' When currentHits does go to 0 after all ships sunk then call new ZeroOutHits sub ' ' Maybe need a tryThisIndexNext global also when deciding where to bomb next, ' set to 1 in ZeroOut This would track where we are in the hit List. ' ' Well that sketches out my next mods and experiment towards a more intelligent AI. ' There, you 'all have it in my words before the code is written! :) ' ========================================================================================================= ' note: previous version had Dir2 that never got used
' oh I need 4 arrays for 4 directions possible because can't depend on directions going in order from ' 1 to 4.
' Offsets for the Game board print at top of screen P is for Player, C is for Computer ' S is for Ships Sunk tally on far right of screen (x,y) offsets: Global PXO, PYO, CXO, CYO, SXO, SYO
Global PTurn, GameOn ' TF players turn or not and GameOn if still running game
' internal tracking of P() Players ships, C() Computer ships Dim P(9, 9), C(9, 9), Hits(9, 9) ' player board, computer board and hits tracking for AI
Dim ShipLen(10), ShipHor(10), ShipX(10), ShipY(10), ShipSunk(10) Dim ShipName$(10), ShipHits$(10) ' Ship arrays are 0 based but are really numbered 1 to 10, 0 is ignored ' ShipName$() are names of ships according to length in character cells see approx line 38 ' ShipLen() is the length or how many character cells a ship is long, 5 down to 2 according to index ' ShipHor() is a T/F value (0|-1) if it is Setup horizontal see SetUp where ships are positioned ' ShipX() and ShipY() locate the top of a ship if vertically set or the left start of ship if horizontal ' ShipHits$() tracks which cell on each ship was hit ' ShipSunk() T/F if ship has been sunk
' this stuff is for the AI for computer's turn to play Dim AiShots$(50) ' AiShots sequence pattern coverage of board when c not working a hit Global AiI ' index for AiShots$() Global Dir ' for AI bombing testing 4 directions from last hit for more of ship hit
Global CurrentHits ' tracks how many hits have been made ' when ship is sunk subtract it's length Global BombX, BombY, Hit2 ' tracking bombs and hits for AI to sink ship ' Bombx, Bomby is next bomb location when working a first hit area ' Hit2 indicates the direction we are going was success on last hit, keep going!
' new for Counting Hits D1 east right, D2, west left, D3 down south, D4 up North Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) Global HitI, tryNextI ' HitI is HitIndex tryNextI tracks open slots of left of currentHits to shoot around
' set one time only stuff PXO = 8: PYO = 6 ' offsets for player grid display, tracks players ships and computers shots CXO = 35: CYO = 6 ' offsets for computer grid display, player shots hit= X miss= o SXO = 68: SYO = 10 ' offsets ships sunk tally For i = 1 To 10 Select Case i Case 1: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 2: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 3: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 4: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 5: ShipLen(i) = 2: ShipName$(i) = "Destroyer" Case 6: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 7: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 8: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 9: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 10: ShipLen(i) = 2: ShipName$(i) = "Destroyer" End Select Next
While 1 'run game loop until player quits scan call Setup call Shoot Wend
Sub Setup ' get a game ready to play ' clear shared arrays and variables dim ShipX(10), ShipY(10), ShipHor(10), ShipHits$(10), ShipSunk(10), P(9, 9), C(9, 9), Hits(9, 9) PTurn = 0: GameOn = 0: AiI = 0: CurrentHits = 0 ' globals
'setup 2 bombing patterns to cover sea in checkerboard pattern one is chosen in each game s1$ = "A0B1C2D3E4F5G6H7I8J9I0J1A8B9E0F1G2H3I4J5A4B5C6D7E8F9C0D1E2F3G4H5I6J7A6B7C8D9G0H1I2J3A2B3C4D5E6F7G8H9" s2$ = "A9B8C7D6E5F4G3H2I1J0B0A1I9J8A5B4C3D2E1F0E9F8G7H6I5J4A3B2C1D0A7B6C5D4E3F2G1H0C9D8E7F6G5H4I3J2G9H8I7J6" 'If Rnd(0) < .5 Then shots$ = s1$ Else shots$ = s2$ ' don't be predictable with bombing patterns shots$ = s1$ ' shuffle sections: priority diagonal then sub diagonals, Mod 8 then mod 4 then mod 2 Dim T(50) For i = 1 To 50: T(i) = i: Next ' don't shuffle want to test with predictable bombing 'start = 1: stp = 10: call Shuffle start, stp 'start = 11: stp = 14: call Shuffle start, stp 'start = 15: stp = 26: call Shuffle start, stp 'start = 27: stp = 50: call Shuffle start, stp For i = 1 To 50 ' stow into an array AiShots$(i) = Mid$(shots$, 2 * T(i) - 1, 2) Next call ZeroOutHits Cls ' Game Board draw once per game Print "" Print " Player Computer" Print "" Print " A B C D E F G H I J A B C D E F G H I J" Print " ------------------- -------------------" Print " 0| . . . . . . . . . . 0| . . . . . . . . . ." Print " 1| . . . . . . . . . . 1| . . . . . . . . . ." Print " 2| . . . . . . . . . . 2| . . . . . . . . . ." Print " 3| . . . . . . . . . . 3| . . . . . . . . . . Ships: P C" Print " 4| . . . . . . . . . . 4| . . . . . . . . . . Carrier . ." Print " 5| . . . . . . . . . . 5| . . . . . . . . . . Battleship . ." Print " 6| . . . . . . . . . . 6| . . . . . . . . . . Cruiser . ." Print " 7| . . . . . . . . . . 7| . . . . . . . . . . Submarine . ." Print " 8| . . . . . . . . . . 8| . . . . . . . . . . Destroyer . ." Print " 9| . . . . . . . . . . 9| . . . . . . . . . ." Print " ------------------- -------------------" Print " A B C D E F G H I J A B C D E F G H I J"
'locate 5, 6: print "X"; ' check offsets
' debugg check AIshots$((aiI) OK 'For i = 1 To 50 'double check checker board coverage 50 cells in priority order ' x = InStr("ABCDEFGHIJ", Left$(AiShots$(i), 1)) - 1 ' y = Val(Mid$(AiShots$(i), 2, 1)) ' call LP x, y, "p", "O" ' call pause 1000 'Next
For i = 1 To 10 ' restring ship hits to all clear no hits ShipHits$(i) = String$(ShipLen(i), "o") Next call Autosetup 1 'setup the Computers ships offer to that for player Locate 1, 20 Print " Let computer setup your ships? press y for yes, n for no..."; k$ = Upper$(Input$(1)) call CLSpart
If k$ = "Y" Then call Autosetup 0 Else For s = 1 To 5 ' do it yourself ship placement OK = 0 While OK = 0 [placeAgain] Locate 1, 20 Print " Setting up the " + ShipName$(s) + " with length" + Str$(ShipLen(s)) Print " To place ship:" Print " Enter v for vertical, h for horizontal, letter+digit for top|left of ship." Input " Placement "; place$ call CLSpart place$ = Upper$(place$) ' check place If Left$(place$, 1) <> "V" And Left$(place$, 1) <> "H" Then PlayWave "tada.wav": GoTo [placeAgain] end if sx = InStr("ABCDEFGHIJ", Mid$(place$, 2, 1)) If sx < 1 Or sx > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sx = sx - 1 sy = InStr("0123456789", Mid$(place$, 3, 1)) If sy < 1 Or sy > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sy = sy - 1
If Left$(place$, 1) = "V" Then ShipHor(s) = 0 Else ShipHor(s) = 1 If ShipHor(s) Then ' layout ship horiz If sx <= 10 - ShipLen(s) Then OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If End If Else ' layout vertical If sy <= 10 - ShipLen(s) Then OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", Trim$(Str$(s)) Next End If End If End If Wend Next End If End Sub
Sub Autosetup AItf If AItf Then 'setup Computer's ships 'setup a board with ships, Computer or AI's setup For s = 6 To 10 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If C(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 C(sx + xx, sy) = s 'call LP sx + xx, sy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If C(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 C(sx, sy + yy) = s 'call LP sx, sy + yy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If End If Wend Next Else 'setup Player's ships For s = 1 To 5 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", _Trim$(Str$(s)) Next End If End If Wend Next End If End Sub
Sub FYI Info$ ' in place of a MessageBox Playwave "tada.wav" Locate 1, 20 Print Space$(3); Info$ + " (3 secs)"; locate 1, 20 call pause 3000 call CLSpart End Sub
Sub LP x, y, pcGrid$, s$ If pcGrid$ = "p" Then Locate PXO + 2 * x, PYO + y Else Locate CXO + 2 * x, CYO + y Print s$; End Sub
Function Rand (low, high) ' Random integer from low to high inclusive Rand = Int(Rnd(0) * (high - low + 1)) + low End Function
Sub Shoot GameOn = 1 While GameOn 'If PTurn Then PTurn = 0 Else PTurn = 1 PTurn = 0 ' for the AI Movie If PTurn Then ' player [playerAgain] Locate 1, 20 Input " Enter your next bomb site letter digit "; place$ call CLSpart If place$ = "" Then GameOn = 0 place$ = Upper$(place$) bx = InStr("ABCDEFGHIJ", Left$(place$, 1)) - 1 by = Val(Mid$(place$, 2, 1)) If bx >= 0 And bx < 10 Then ' better check If by >= 0 And by < 10 Then If C(bx, by) = 0 Then 'miss call LP bx, by, "c", "o" C(bx, by) = -1 end if If C(bx, by) > 5 And C(bx, by) < 11 Then 'hit call LP bx, by, "c", "X" playwave "tada.wav" call HitEval "c", bx, by 'game could end here C(bx, by) = C(bx, by) + 10 ' signal we hit this spot already! end if If C(bx, by) = -1 Or C(bx, by) > 10 Then playwave "tada.wav": GoTo [playerAgain] End If End If End If Else 'AI's turn if it gets a hit it will bomb around the ship until it is finished 'could be trouble if 2 ships are next to each other. Some effort to work it, 'still might get confused. 'hits() array tracks red = 1 and white pegs = -1 like a human player for AI
If CurrentHits > 0 Then 'we are working around the latest hit with bombx, bomby to test ' BombX, Bomby already deided in decide... sub If P(BombX, BombY) <> 0 Then 'hit! Hit2 = 1 ' signal AI that bomb x, y was a success, keep that direction going Hits(BombX, BombY) = 1 ' update hits board CurrentHits = CurrentHits + 1 ' update AI hit count Counting Hits!!!! call LP BombX, BombY, "p", "X" ' update display 'new stuff 2024-08-01 mod HitI = HitI + 1 ' increase index HitX(HitI) = BombX ' save location HitY(HitI) = BombY
' when hitEval announces a ship sunk we can reduce the currentHits count ' by that ships amount if still have more current hits, continue bombing ' area as another ship is there playwave "tada.wav" ' wakeup player! call HitEval "p", BombX, BombY ' this will reduce currentHits by ship sank If CurrentHits = 0 Then ' clear our checklist we sank all ships we hit, Call ZeroOutHits ' call off bombing of area Else call DecideWhereToBombNext End If Else 'no hit from checklist scratch off one item Hit2 = 0 ' signal ai that direction was not successful move on to next Hits(BombX, BombY) = -1 ' update ALL the hits on board call LP BombX, BombY, "p", "o" ' update board display call DecideWhereToBombNext End If ' are we still working on hit Else 'not working on any hits x1, y1 = 0, dir = 0, currentHits might be = 0 'random but systematic shooting, bring up next good shooting location
[alreadyHit] AiI = AiI + 1 ' next random shoot If AiI > 50 Then ' we should never get this far but just in case x = Rand(0, 9) y = Rand(0, 9) Else ' normal shooting pattern by diagonals to form checker board coverage x = InStr("ABCDEFGHIJ", Left$(AiShots$(AiI), 1)) - 1 y = Val(Mid$(AiShots$(AiI), 2, 1)) End If If Hits(x, y) <> 0 Then GoTo [alreadyHit]
' was that shot just fired a hit or miss If P(x, y) <> 0 Then ' test our shot just fired is hit! CurrentHits = CurrentHits + 1 ' counting hits!! HitI = HitI + 1 HitX(HitI) = x HitY(HitI) = y Hits(x, y) = 1 ' update board call LP HitX(HitI), HitY(HitI), "p", "X" ' update display of board playwave "tada.wav" ' wakeup player! call HitEval "p", HitX(HitI), HitY(HitI) ' see if ship sunk 'did we just happen to finish off a ship? If CurrentHits = 0 Then ' finished off all ships in area of hit call ZeroOutHits Else call DecideWhereToBombNext ' still working the hit area End If Else 'no hit Hits(x, y) = -1 ' record in board call LP x, y, "p", "o" ' update display End If End If 'rI was hit or not End If 'whose turn is it call pause 1000 ' a sec pause to allow us to see computers move Wend Locate 1, 20 Print " Play Again? press y for yes, n for no..."; k$ = Input$(1) call CLSpart If k$ = "n" Then End End Sub
Sub HitEval board$, bbx, bby 'a referee for both players to announce a ship sunk and a game won? If board$ <> "p" Then s = C(bbx, bby) ' which ship number you$ = "Player": my$ = "Computer's" istart = 6: istop = 10 Else s = P(bbx, bby) you$ = "Computer": my$ = "Player's" istart = 1: istop = 5 End If If ShipHor(s) Then D = bbx - ShipX(s) + 1 Else D = bby - ShipY(s) + 1 ShipHits$(s) = SubStr$(ShipHits$(s), D, "X") If ShipHits$(s) = String$(ShipLen(s), "X") Then ShipSunk(s) = 1 ' this is only thing ref does to help Computer AI If board$ = "p" Then CurrentHits = CurrentHits - ShipLen(s) call UpdateStatus call FYI "Congrats: " + you$ + " sank " + my$ + " " + ShipName$(s) + "!" tot = 0 For i = istart To istop If ShipSunk(i) = 1 Then tot = tot + 1 Next If tot = 5 Then call UpdateStatus If you$ = "Computer" Then call ShowComputersShips call FYI "Congrats: " + you$ + ", you sank all " + my$ + " ships! Game Over" GameOn = 0 End If End If End Sub
Sub DecideWhereToBombNext ' this sets the next place to try with bombX, bombY If Hit2 Then 'whatever direction we are taking, continue if we can Select Case Dir Case 1 If BombX + 1 <= 9 Then If Hits(BombX + 1, BombY) = 0 Then BombX = BombX + 1: Exit Sub End If End If Case 2 If BombX - 1 >= 0 Then If Hits(BombX - 1, BombY) = 0 Then BombX = BombX - 1: Exit Sub End If End If Case 3 If BombY + 1 <= 9 Then If Hits(BombX, BombY + 1) = 0 Then BombY = BombY + 1: Exit Sub End If End If Case 4 If BombY - 1 >= 0 Then If Hits(BombX, BombY - 1) = 0 Then BombY = BombY - 1: Exit Sub End If End If End Select ' still here then the direction is no longer good to try Hit2 = 0 ' turn off signal End If
tryNextI = 1 'vsearch next open hit location not tested While tryNextI <= HitI ' Not CurrentHits !!! If D1(tryNextI) = 0 Then D1(tryNextI) = 1 If HitX(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI) + 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) + 1: BombY = HitY(tryNextI): Dir = 1: Exit Sub End If End If End If If D2(tryNextI) = 0 Then D2(tryNextI) = 1 If HitX(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI) - 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) - 1: BombY = HitY(tryNextI): Dir = 2: Exit Sub End If End If End If If D3(tryNextI) = 0 Then D3(tryNextI) = 1 If HitY(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI), HitY(tryNextI) + 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) + 1: Dir = 3: Exit Sub End If End If End If If D4(tryNextI) = 0 Then D4(tryNextI) = 1 If HitY(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI), HitY(tryNextI) - 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) - 1: Dir = 4: Exit Sub End If End If End If tryNextI = tryNextI + 1 Wend ' exhausted all hit locations hit1 area played out!!! CurrentHits = 0 ' abandon hit area call ZeroOutHits End Sub
Sub UpdateStatus ' ships sunk area of the display For i = 1 To 5 ' row 10 carrier player colum 66 computer column 68 If ShipSunk(i) Then Locate 68, i + 9: Print "X"; If ShipSunk(i + 5) Then Locate 70, i + 9: Print "X"; Next locate 1, 20 End Sub
Sub ShowComputersShips ' fixed this so only empty spaces not bombed are displayed For s = 6 To 10 If ShipHor(s) Then sx = ShipX(s): sy = ShipY(s) For xx = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), xx + 1, 1) = "o" Then call LP sx + xx, sy, "c", Trim$(Str$(s Mod 10)) End If Next Else sx = ShipX(s): sy = ShipY(s) For yy = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), yy + 1, 1) = "o" Then call LP sx, sy + yy, "c", Trim$(Str$(s Mod 10)) End If Next End If Next End Sub
Sub CLSpart ' clear lower part of screen For i = 20 To 25 Locate 1, i: Print Space$(80) Next Locate 1, 20 End Sub
Sub ZeroOutHits ' at setup and everytime CurrentHits is set back to zero Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) HitI = 0: Dir = 0: Hit2 = 0: tryNextI = 0 End Sub
function SubStr$(s$, place, subst$) for i = 1 to len(s$) if i = place then r$ = r$ + subst$ else r$ = r$ + mid$(s$, i, 1) next SubStr$ = r$ end function
function String$(number, s$) for i = 1 to number r$ = r$ + s$ next String$ = r$ end function
sub pause mil 'tsh version has scan built-in t0 = time$("ms") while time$("ms") < t0 + mil : scan : wend end sub
sub shuff start, stp for i = stp to start + 1 step -1 r = Rand(start, stp) temp = T(i) T(i) = T(r) T(r) = temp next end sub
b = b + ...
|
|
|
Post by plus on Aug 2, 2024 8:20:54 GMT
Now to put you the Player back in the game! In this version we are doing more checks on the Player's input to avoid erroring out. If player accidently enters a place already bombed he will be asked for another place, same if he mistypes letters or digits for bomb sites or placing ships. ' JB port BS Mod842 Counting Hits 2 Player back 2024-08-01" ' b+ 2024-07-26 port from JB ' Battleship Mod842 b+ 2024-07-25 uses a garanteed AI to find Destroyer in 50 shots ' unlike Battleship 2 which AI uses mod 3 it is screwed if fails to find Destroyer when mod 3 ' shooting covers the ocean taking something like up to 66 shots to garantee finding Destroyer. ' This code starts from my first Battleship coded for JB: ' Battleship based on Hasbro Game b+ 2024-07-23 allot of code ported out of old QB64 version ' 2024-07-26 besides port trans back to QB64, fix the showing of computer ships so only the ones ' or parts not hit with ship number. Add Sound when ship is hit.
' 2024-07-29 Oh I forgot, MessageBox does not work for older versions of QB64. ' Actually that turns out to be no problem at all!!! ' I think I can use View Print and not need my Message and Message Clear subroutines. ' This might be a very cool fix! Also I am going to work on my organization and commenting. ' OK View Print did not scroll inside the view text port so I had to cls before turning off ' View Print. I was thinking scrolling would be cool, no cls needed but no.
' Fix a bug that has been here from beginning, check player's bomb site to see if already done ' if so BEEP him, definitely don't want to sink a ship twice which is what has been happening. ' So we should use computer c() to track players shots. -1 for miss but what about when ship ' is hit??? c(x, y) = c(x, y) + 10 so if c(x, y) is > 5 and < 11 then good hit. ' if c(x,y) > 10 then already hit. BEEPing now for places already bombed plus give player another ' chance to shoot.
' Need to check place$ to see if player screwed up placement instructions, done.
' 2024-07-30 BS Mod842 AI Movie - last night I got this great idea and want to share it. ' This Movie shows The Computer AI in action finding and sinking ships, it does so with ' minimum interruption from viewer/Player. I do want to set it so the Player can setup ' tricky ship placements to test how well the AI handles them, also excellent tool to ' improve the AI because just watching a number of these I see AI failures clearly some ' holes left in coverage...
' 2024-07-30 BS Mod842 AI Movie 2 tsh suggest if running successfully one way and stop ' the reverse direction and go opposite ie heading dir 1 right then go left if stopped.
' 2024-07-31 still with Movie 2 - Take out View Print with Locate and ClearPartial sub ' to clear only bottom part of screen. Now I have code portable to all Basics.
' 2024-08-01 BS Mod 842 Counting Hits as posted at JB today: ' ========================================================================================================= ' I am studying cases when/where AI fails to sustain an attack when current hits > 0 after a ship is sunk. ' The attack needs to persist for the original hit area until currentHits is zero, = no ships left in ' area of first hit in sequence after random fire gets a first hit. ' ' Towards that end I need to restructure: ' Add HitX(), HitY() track where we have hits 1, 0 for untested ' yet I suppose we have to track if missed at that spot too, -1 ' that would replace X1, Y1 with the array ordered by hitIndex ' kinda of confused at moment to include misses or not. ' BTW 17 is max amount of hits possible if you hit everything on Board, could have a cluster convoy. ' ' Dir() = 0 1 2 3 4 test all 4 directions for each hit, 0 no direction tested, ' 5 = all directions tested and so hitIndex for that place is played out ' ' the 3 (new arrays) above are indexed with hitIndex (global) ' ' When currentHits does go to 0 after all ships sunk then call new ZeroOutHits sub ' ' Maybe need a tryThisIndexNext global also when deciding where to bomb next, ' set to 1 in ZeroOut This would track where we are in the hit List. ' ' Well that sketches out my next mods and experiment towards a more intelligent AI. ' There, you 'all have it in my words before the code is written! :) ' ========================================================================================================= ' note: previous version had Dir2 that never got used
' oh I need 4 arrays for 4 directions possible because can't depend on directions going in order from ' 1 to 4.
' Offsets for the Game board print at top of screen P is for Player, C is for Computer ' S is for Ships Sunk tally on far right of screen (x,y) offsets: Global PXO, PYO, CXO, CYO, SXO, SYO
Global PTurn, GameOn ' TF players turn or not and GameOn if still running game
' internal tracking of P() Players ships, C() Computer ships Dim P(9, 9), C(9, 9), Hits(9, 9) ' player board, computer board and hits tracking for AI
Dim ShipLen(10), ShipHor(10), ShipX(10), ShipY(10), ShipSunk(10) Dim ShipName$(10), ShipHits$(10) ' Ship arrays are 0 based but are really numbered 1 to 10, 0 is ignored ' ShipName$() are names of ships according to length in character cells see approx line 38 ' ShipLen() is the length or how many character cells a ship is long, 5 down to 2 according to index ' ShipHor() is a T/F value (0|-1) if it is Setup horizontal see SetUp where ships are positioned ' ShipX() and ShipY() locate the top of a ship if vertically set or the left start of ship if horizontal ' ShipHits$() tracks which cell on each ship was hit ' ShipSunk() T/F if ship has been sunk
' this stuff is for the AI for computer's turn to play Dim AiShots$(50) ' AiShots sequence pattern coverage of board when c not working a hit Global AiI ' index for AiShots$() Global Dir ' for AI bombing testing 4 directions from last hit for more of ship hit
Global CurrentHits ' tracks how many hits have been made ' when ship is sunk subtract it's length Global BombX, BombY, Hit2 ' tracking bombs and hits for AI to sink ship ' Bombx, Bomby is next bomb location when working a first hit area ' Hit2 indicates the direction we are going was success on last hit, keep going!
' new for Counting Hits D1 east right, D2, west left, D3 down south, D4 up North Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) Global HitI, tryNextI ' HitI is HitIndex tryNextI tracks open slots of left of currentHits to shoot around
' set one time only stuff PXO = 8: PYO = 6 ' offsets for player grid display, tracks players ships and computers shots CXO = 35: CYO = 6 ' offsets for computer grid display, player shots hit= X miss= o SXO = 68: SYO = 10 ' offsets ships sunk tally For i = 1 To 10 Select Case i Case 1: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 2: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 3: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 4: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 5: ShipLen(i) = 2: ShipName$(i) = "Destroyer" Case 6: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 7: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 8: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 9: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 10: ShipLen(i) = 2: ShipName$(i) = "Destroyer" End Select Next
While 1 'run game loop until player quits scan call Setup call Shoot Wend
Sub Setup ' get a game ready to play ' clear shared arrays and variables dim ShipX(10), ShipY(10), ShipHor(10), ShipHits$(10), ShipSunk(10), P(9, 9), C(9, 9), Hits(9, 9) PTurn = 0: GameOn = 0: AiI = 0: CurrentHits = 0 ' globals
'setup 2 bombing patterns to cover sea in checkerboard pattern one is chosen in each game s1$ = "A0B1C2D3E4F5G6H7I8J9I0J1A8B9E0F1G2H3I4J5A4B5C6D7E8F9C0D1E2F3G4H5I6J7A6B7C8D9G0H1I2J3A2B3C4D5E6F7G8H9" s2$ = "A9B8C7D6E5F4G3H2I1J0B0A1I9J8A5B4C3D2E1F0E9F8G7H6I5J4A3B2C1D0A7B6C5D4E3F2G1H0C9D8E7F6G5H4I3J2G9H8I7J6" If Rnd(0) < .5 Then shots$ = s1$ Else shots$ = s2$ ' don't be predictable with bombing patterns 'shots$ = s1$ ' shuffle sections: priority diagonal then sub diagonals, Mod 8 then mod 4 then mod 2 Dim T(50) For i = 1 To 50: T(i) = i: Next ' don't shuffle want to test with predictable bombing start = 1: stp = 10: call shuff start, stp start = 11: stp = 14: call shuff start, stp start = 15: stp = 26: call shuff start, stp start = 27: stp = 50: call shuff start, stp For i = 1 To 50 ' stow into an array AiShots$(i) = Mid$(shots$, 2 * T(i) - 1, 2) Next call ZeroOutHits Cls ' Game Board draw once per game Print "" Print " Player Computer" Print "" Print " A B C D E F G H I J A B C D E F G H I J" Print " ------------------- -------------------" Print " 0| . . . . . . . . . . 0| . . . . . . . . . ." Print " 1| . . . . . . . . . . 1| . . . . . . . . . ." Print " 2| . . . . . . . . . . 2| . . . . . . . . . ." Print " 3| . . . . . . . . . . 3| . . . . . . . . . . Ships: P C" Print " 4| . . . . . . . . . . 4| . . . . . . . . . . Carrier . ." Print " 5| . . . . . . . . . . 5| . . . . . . . . . . Battleship . ." Print " 6| . . . . . . . . . . 6| . . . . . . . . . . Cruiser . ." Print " 7| . . . . . . . . . . 7| . . . . . . . . . . Submarine . ." Print " 8| . . . . . . . . . . 8| . . . . . . . . . . Destroyer . ." Print " 9| . . . . . . . . . . 9| . . . . . . . . . ." Print " ------------------- -------------------" Print " A B C D E F G H I J A B C D E F G H I J"
'locate 5, 6: print "X"; ' check offsets
' debugg check AIshots$((aiI) OK 'For i = 1 To 50 'double check checker board coverage 50 cells in priority order ' x = InStr("ABCDEFGHIJ", Left$(AiShots$(i), 1)) - 1 ' y = Val(Mid$(AiShots$(i), 2, 1)) ' call LP x, y, "p", "O" ' call pause 1000 'Next
For i = 1 To 10 ' restring ship hits to all clear no hits ShipHits$(i) = String$(ShipLen(i), "o") Next call Autosetup 1 'setup the Computers ships offer to that for player Locate 1, 20 Print " Let computer setup your ships? press y for yes, n for no..."; k$ = Upper$(Input$(1)) call CLSpart
If k$ = "Y" Then call Autosetup 0 Else For s = 1 To 5 ' do it yourself ship placement OK = 0 While OK = 0 [placeAgain] Locate 1, 20 Print " Setting up the " + ShipName$(s) + " with length " + Str$(ShipLen(s)) Print " To place ship:" Print " Enter v for vertical, h for horizontal, letter+digit for top|left of ship." Input " Placement "; place$ call CLSpart place$ = Upper$(place$) ' check place If Left$(place$, 1) <> "V" And Left$(place$, 1) <> "H" Then PlayWave "tada.wav": GoTo [placeAgain] end if sx = InStr("ABCDEFGHIJ", Mid$(place$, 2, 1)) If sx < 1 Or sx > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sx = sx - 1 sy = InStr("0123456789", Mid$(place$, 3, 1)) If sy < 1 Or sy > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sy = sy - 1
If Left$(place$, 1) = "V" Then ShipHor(s) = 0 Else ShipHor(s) = 1 If ShipHor(s) Then ' layout ship horiz If sx <= 10 - ShipLen(s) Then OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If End If Else ' layout vertical If sy <= 10 - ShipLen(s) Then OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", Trim$(Str$(s)) Next End If End If End If Wend Next End If End Sub
Sub Autosetup AItf If AItf Then 'setup Computer's ships 'setup a board with ships, Computer or AI's setup For s = 6 To 10 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If C(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 C(sx + xx, sy) = s 'call LP sx + xx, sy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If C(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 C(sx, sy + yy) = s 'call LP sx, sy + yy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If End If Wend Next Else 'setup Player's ships For s = 1 To 5 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", _Trim$(Str$(s)) Next End If End If Wend Next End If End Sub
Sub FYI Info$ ' in place of a MessageBox Playwave "tada.wav" Locate 1, 20 Print Space$(3); Info$ + " (3 secs)"; locate 1, 20 call pause 3000 call CLSpart End Sub
Sub LP x, y, pcGrid$, s$ If pcGrid$ = "p" Then Locate PXO + 2 * x, PYO + y Else Locate CXO + 2 * x, CYO + y Print s$; End Sub
Function Rand (low, high) ' Random integer from low to high inclusive Rand = Int(Rnd(0) * (high - low + 1)) + low End Function
Sub Shoot GameOn = 1 While GameOn If PTurn = 1 Then PTurn = 0 Else PTurn = 1 'PTurn = 0 ' for the AI Movie If PTurn Then ' player [playerAgain] Locate 1, 20 Input " Enter your next bomb site letter digit "; place$ call CLSpart place$ = Upper$(place$) bx = InStr("ABCDEFGHIJ", Left$(place$, 1)) - 1 by = instr("0123456789", Mid$(place$, 2, 1)) - 1 If bx >= 0 And bx < 10 Then ' better check If by >= 0 And by < 10 Then select case case C(bx, by) = 0 'miss call LP bx, by, "c", "o" C(bx, by) = -1 case C(bx, by) > 5 And C(bx, by) < 11 'hit call LP bx, by, "c", "X" playwave "tada.wav" call HitEval "c", bx, by 'game could end here C(bx, by) = C(bx, by) + 10 ' signal we hit this spot already! case C(bx, by) = -1 Or C(bx, by) > 10 ' already played playwave "tada.wav": GoTo [playerAgain] End select End If End If Else
'AI's turn if it gets a hit it will bomb around the ship until it is finished 'could be trouble if 2 ships are next to each other. Some effort to work it, 'still might get confused. 'hits() array tracks red = 1 and white pegs = -1 like a human player for AI
If CurrentHits > 0 Then 'we are working around the latest hit with bombx, bomby to test ' BombX, Bomby already deided in decide... sub If P(BombX, BombY) <> 0 Then 'hit! Hit2 = 1 ' signal AI that bomb x, y was a success, keep that direction going Hits(BombX, BombY) = 1 ' update hits board CurrentHits = CurrentHits + 1 ' update AI hit count Counting Hits!!!! call LP BombX, BombY, "p", "X" ' update display 'new stuff 2024-08-01 mod HitI = HitI + 1 ' increase index HitX(HitI) = BombX ' save location HitY(HitI) = BombY
' when hitEval announces a ship sunk we can reduce the currentHits count ' by that ships amount if still have more current hits, continue bombing ' area as another ship is there playwave "tada.wav" ' wakeup player! call HitEval "p", BombX, BombY ' this will reduce currentHits by ship sank If CurrentHits = 0 Then ' clear our checklist we sank all ships we hit, Call ZeroOutHits ' call off bombing of area Else call DecideWhereToBombNext End If Else 'no hit from checklist scratch off one item Hit2 = 0 ' signal ai that direction was not successful move on to next Hits(BombX, BombY) = -1 ' update ALL the hits on board call LP BombX, BombY, "p", "o" ' update board display call DecideWhereToBombNext End If ' are we still working on hit Else 'not working on any hits x1, y1 = 0, dir = 0, currentHits might be = 0 'random but systematic shooting, bring up next good shooting location
[alreadyHit] AiI = AiI + 1 ' next random shoot If AiI > 50 Then ' we should never get this far but just in case x = Rand(0, 9) y = Rand(0, 9) Else ' normal shooting pattern by diagonals to form checker board coverage x = InStr("ABCDEFGHIJ", Left$(AiShots$(AiI), 1)) - 1 y = Val(Mid$(AiShots$(AiI), 2, 1)) End If If Hits(x, y) <> 0 Then GoTo [alreadyHit]
' was that shot just fired a hit or miss If P(x, y) <> 0 Then ' test our shot just fired is hit! CurrentHits = CurrentHits + 1 ' counting hits!! HitI = HitI + 1 HitX(HitI) = x HitY(HitI) = y Hits(x, y) = 1 ' update board call LP HitX(HitI), HitY(HitI), "p", "X" ' update display of board playwave "tada.wav" ' wakeup player! call HitEval "p", HitX(HitI), HitY(HitI) ' see if ship sunk 'did we just happen to finish off a ship? If CurrentHits = 0 Then ' finished off all ships in area of hit call ZeroOutHits Else call DecideWhereToBombNext ' still working the hit area End If Else 'no hit Hits(x, y) = -1 ' record in board call LP x, y, "p", "o" ' update display End If End If 'rI was hit or not End If 'whose turn is it call pause 1000 ' a sec pause to allow us to see computers move Wend Locate 1, 20 Print " Play Again? press y for yes, n for no..."; k$ = Input$(1) call CLSpart If k$ = "n" Then End End Sub
Sub HitEval board$, bbx, bby 'a referee for both players to announce a ship sunk and a game won? If board$ <> "p" Then s = C(bbx, bby) ' which ship number you$ = "Player": my$ = "Computer's" istart = 6: istop = 10 Else s = P(bbx, bby) you$ = "Computer": my$ = "Player's" istart = 1: istop = 5 End If If ShipHor(s) Then D = bbx - ShipX(s) + 1 Else D = bby - ShipY(s) + 1 ShipHits$(s) = SubStr$(ShipHits$(s), D, "X") If ShipHits$(s) = String$(ShipLen(s), "X") Then ShipSunk(s) = 1 ' this is only thing ref does to help Computer AI If board$ = "p" Then CurrentHits = CurrentHits - ShipLen(s) call UpdateStatus call FYI "Congrats: " + you$ + " sank " + my$ + " " + ShipName$(s) + "!" tot = 0 For i = istart To istop If ShipSunk(i) = 1 Then tot = tot + 1 Next If tot = 5 Then call UpdateStatus If you$ = "Computer" Then call ShowComputersShips call FYI "Congrats: " + you$ + ", you sank all " + my$ + " ships! Game Over" GameOn = 0 End If End If End Sub
Sub DecideWhereToBombNext ' this sets the next place to try with bombX, bombY If Hit2 Then 'whatever direction we are taking, continue if we can Select Case Dir Case 1 If BombX + 1 <= 9 Then If Hits(BombX + 1, BombY) = 0 Then BombX = BombX + 1: Exit Sub End If End If Case 2 If BombX - 1 >= 0 Then If Hits(BombX - 1, BombY) = 0 Then BombX = BombX - 1: Exit Sub End If End If Case 3 If BombY + 1 <= 9 Then If Hits(BombX, BombY + 1) = 0 Then BombY = BombY + 1: Exit Sub End If End If Case 4 If BombY - 1 >= 0 Then If Hits(BombX, BombY - 1) = 0 Then BombY = BombY - 1: Exit Sub End If End If End Select ' still here then the direction is no longer good to try Hit2 = 0 ' turn off signal End If
tryNextI = 1 'vsearch next open hit location not tested While tryNextI <= HitI ' Not CurrentHits !!! If D1(tryNextI) = 0 Then D1(tryNextI) = 1 If HitX(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI) + 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) + 1: BombY = HitY(tryNextI): Dir = 1: Exit Sub End If End If End If If D2(tryNextI) = 0 Then D2(tryNextI) = 1 If HitX(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI) - 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) - 1: BombY = HitY(tryNextI): Dir = 2: Exit Sub End If End If End If If D3(tryNextI) = 0 Then D3(tryNextI) = 1 If HitY(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI), HitY(tryNextI) + 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) + 1: Dir = 3: Exit Sub End If End If End If If D4(tryNextI) = 0 Then D4(tryNextI) = 1 If HitY(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI), HitY(tryNextI) - 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) - 1: Dir = 4: Exit Sub End If End If End If tryNextI = tryNextI + 1 Wend ' exhausted all hit locations hit1 area played out!!! CurrentHits = 0 ' abandon hit area call ZeroOutHits End Sub
Sub UpdateStatus ' ships sunk area of the display For i = 1 To 5 ' row 10 carrier player colum 66 computer column 68 If ShipSunk(i) Then Locate 68, i + 9: Print "X"; If ShipSunk(i + 5) Then Locate 70, i + 9: Print "X"; Next locate 1, 20 End Sub
Sub ShowComputersShips ' fixed this so only empty spaces not bombed are displayed For s = 6 To 10 If ShipHor(s) Then sx = ShipX(s): sy = ShipY(s) For xx = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), xx + 1, 1) = "o" Then call LP sx + xx, sy, "c", Trim$(Str$(s Mod 10)) End If Next Else sx = ShipX(s): sy = ShipY(s) For yy = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), yy + 1, 1) = "o" Then call LP sx, sy + yy, "c", Trim$(Str$(s Mod 10)) End If Next End If Next End Sub
Sub CLSpart ' clear lower part of screen For i = 20 To 25 Locate 1, i: Print Space$(80) Next Locate 1, 20 End Sub
Sub ZeroOutHits ' at setup and everytime CurrentHits is set back to zero Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) HitI = 0: Dir = 0: Hit2 = 0: tryNextI = 0 End Sub
function SubStr$(s$, place, subst$) for i = 1 to len(s$) if i = place then r$ = r$ + subst$ else r$ = r$ + mid$(s$, i, 1) next SubStr$ = r$ end function
function String$(number, s$) for i = 1 to number r$ = r$ + s$ next String$ = r$ end function
sub pause mil 'tsh version has scan built-in t0 = time$("ms") while time$("ms") < t0 + mil : scan : wend end sub
sub shuff start, stp for i = stp to start + 1 step -1 r = Rand(start, stp) temp = T(i) T(i) = T(r) T(r) = temp next end sub
This might be my final "ultimate" version unless someone runs into a pattern of problems. b = b + ...
|
|
|
Post by plus on Aug 2, 2024 14:07:56 GMT
Dang! just had an idea to do random directions from the hit list looking for partially hit ships that explain why CurrentHits still > 0.
Good AI for shooting is to not be predictable.
I thought I was done ;-))
b = b + ...
|
|
|
Post by tsh73 on Aug 2, 2024 18:46:15 GMT
(finally) With a bit of luck I won ;) (not at first try)
And here some attention-drawing sub (used instead of "call LP " on computer "shoot" section)
sub animateLP x, y, pcGrid$, s$ if s$=lower$(s$) then S$=upper$(s$) else S$=lower$(s$) for i = 1 to 4 call LP x, y, pcGrid$, s$ call pause 100 call LP x, y, pcGrid$, S$ call pause 100 next call LP x, y, pcGrid$, s$ end sub
|
|
|
Post by plus on Aug 2, 2024 22:16:49 GMT
Yes or you can also blink it on/off with a space.
I use the same wave pattern as the AI and usually edge out the AI regularly unless it finds the Destroyer fast. I have a better sense of random placement, I think, when I see some of the ship positions, yet that Destroyer can sure draw allot of empty hits looking for it.
b = b + ...
|
|
|
Post by plus on Aug 3, 2024 12:39:23 GMT
(finally) With a bit of luck I won (not at first try) And here some attention-drawing sub (used instead of "call LP " on computer "shoot" section) sub animateLP x, y, pcGrid$, s$ if s$=lower$(s$) then S$=upper$(s$) else S$=lower$(s$) for i = 1 to 4 call LP x, y, pcGrid$, s$ call pause 100 call LP x, y, pcGrid$, S$ call pause 100 next call LP x, y, pcGrid$, s$ end sub Dang it! I am stuck thinking about this issue you, tsh73, have about seeing last hit by AI. I personally don't like the pause idea because it delays my typing in of my next shot, the beeps and ships sunk tell me what I need to know but I know what the computer AI is doing; it only gets interesting, to me, around a cluster of ships and a hit in there. I prefer to stay focused on my wave pattern or persisting in attack with a ship or more wounded. One track mind I guess. BTW the Playwave seems to delay game worse than the pauses inserted! But still to please my audience (of one?) I have been thinking of flashing the last computer move on a timer. This takes some globals that save the lastToggle, lastAIx, lastAIy, lastAIhit$ "o" or "X", 4 added globals and a sub for on timer plus adding to code turning timer on and off at right times... sheesh wait... that silly cursor does blink on/off at last place something was printed in JB, I think. What if we used THAT to show where last hit was placed by computer? Piggy back onto THAT without need of much else, I think, hmm... ehhh the cursor moves for all the prompts to player. Do we have a long enough pause right after we print the last AI hit on screen? so that the cursor will hang there for a bit. Ah good experiment I think! or combine paragraph 2 with paragraph 3 for hybrid experiment. PS I can't believe I am still fiddling around here with BS (Battle Ship), I thought I was done 2024-08-01 after posting latest. Nope I am not done until I have served my audience (of one?) as best I can specially if they are not asking too much. b = b + ...
|
|
|
Post by plus on Aug 3, 2024 14:11:40 GMT
Worked great! adding a pause after a hit or miss on computer's shot shows a blinking cursor at the last print. So if the shot was a miss I paused 6 secs for you to find the miss. If the shot was a hit, I pause 2 or 2.5 secs (forgot) and then Playwave to prolong the pause the cursor stops blinking but IS right next to last hit. JB doen't show line numbers in IDE so I have to post the code all over again instead of just telling you the 6 lines to add or change: ' JB port BS Mod842 Counting Hits 3 Player back 2024-08-03" ' b+ 2024-07-26 port from JB ' Battleship Mod842 b+ 2024-07-25 uses a garanteed AI to find Destroyer in 50 shots ' unlike Battleship 2 which AI uses mod 3 it is screwed if fails to find Destroyer when mod 3 ' shooting covers the ocean taking something like up to 66 shots to garantee finding Destroyer. ' This code starts from my first Battleship coded for JB: ' Battleship based on Hasbro Game b+ 2024-07-23 allot of code ported out of old QB64 version ' 2024-07-26 besides port trans back to QB64, fix the showing of computer ships so only the ones ' or parts not hit with ship number. Add Sound when ship is hit.
' 2024-07-29 Oh I forgot, MessageBox does not work for older versions of QB64. ' Actually that turns out to be no problem at all!!! ' I think I can use View Print and not need my Message and Message Clear subroutines. ' This might be a very cool fix! Also I am going to work on my organization and commenting. ' OK View Print did not scroll inside the view text port so I had to cls before turning off ' View Print. I was thinking scrolling would be cool, no cls needed but no.
' Fix a bug that has been here from beginning, check player's bomb site to see if already done ' if so BEEP him, definitely don't want to sink a ship twice which is what has been happening. ' So we should use computer c() to track players shots. -1 for miss but what about when ship ' is hit??? c(x, y) = c(x, y) + 10 so if c(x, y) is > 5 and < 11 then good hit. ' if c(x,y) > 10 then already hit. BEEPing now for places already bombed plus give player another ' chance to shoot.
' Need to check place$ to see if player screwed up placement instructions, done.
' 2024-07-30 BS Mod842 AI Movie - last night I got this great idea and want to share it. ' This Movie shows The Computer AI in action finding and sinking ships, it does so with ' minimum interruption from viewer/Player. I do want to set it so the Player can setup ' tricky ship placements to test how well the AI handles them, also excellent tool to ' improve the AI because just watching a number of these I see AI failures clearly some ' holes left in coverage...
' 2024-07-30 BS Mod842 AI Movie 2 tsh suggest if running successfully one way and stop ' the reverse direction and go opposite ie heading dir 1 right then go left if stopped.
' 2024-07-31 still with Movie 2 - Take out View Print with Locate and ClearPartial sub ' to clear only bottom part of screen. Now I have code portable to all Basics.
' 2024-08-01 BS Mod 842 Counting Hits as posted at JB today: ' ========================================================================================================= ' I am studying cases when/where AI fails to sustain an attack when current hits > 0 after a ship is sunk. ' The attack needs to persist for the original hit area until currentHits is zero, = no ships left in ' area of first hit in sequence after random fire gets a first hit. ' ' Towards that end I need to restructure: ' Add HitX(), HitY() track where we have hits 1, 0 for untested ' yet I suppose we have to track if missed at that spot too, -1 ' that would replace X1, Y1 with the array ordered by hitIndex ' kinda of confused at moment to include misses or not. ' BTW 17 is max amount of hits possible if you hit everything on Board, could have a cluster convoy. ' ' Dir() = 0 1 2 3 4 test all 4 directions for each hit, 0 no direction tested, ' 5 = all directions tested and so hitIndex for that place is played out ' ' the 3 (new arrays) above are indexed with hitIndex (global) ' ' When currentHits does go to 0 after all ships sunk then call new ZeroOutHits sub ' ' Maybe need a tryThisIndexNext global also when deciding where to bomb next, ' set to 1 in ZeroOut This would track where we are in the hit List. ' ' Well that sketches out my next mods and experiment towards a more intelligent AI. ' There, you 'all have it in my words before the code is written! :) ' ========================================================================================================= ' note: previous version had Dir2 that never got used
' oh I need 4 arrays for 4 directions possible because can't depend on directions going in order from ' 1 to 4.
' JB port BS Mod842 Counting Hits 3 Player back 2024-08-03 try pause after printing computer hits. ' See if cursor will flash enough to point to last hit???
' Offsets for the Game board print at top of screen P is for Player, C is for Computer ' S is for Ships Sunk tally on far right of screen (x,y) offsets: Global PXO, PYO, CXO, CYO, SXO, SYO
Global PTurn, GameOn ' TF players turn or not and GameOn if still running game
' internal tracking of P() Players ships, C() Computer ships Dim P(9, 9), C(9, 9), Hits(9, 9) ' player board, computer board and hits tracking for AI
Dim ShipLen(10), ShipHor(10), ShipX(10), ShipY(10), ShipSunk(10) Dim ShipName$(10), ShipHits$(10) ' Ship arrays are 0 based but are really numbered 1 to 10, 0 is ignored ' ShipName$() are names of ships according to length in character cells see approx line 38 ' ShipLen() is the length or how many character cells a ship is long, 5 down to 2 according to index ' ShipHor() is a T/F value (0|-1) if it is Setup horizontal see SetUp where ships are positioned ' ShipX() and ShipY() locate the top of a ship if vertically set or the left start of ship if horizontal ' ShipHits$() tracks which cell on each ship was hit ' ShipSunk() T/F if ship has been sunk
' this stuff is for the AI for computer's turn to play Dim AiShots$(50) ' AiShots sequence pattern coverage of board when c not working a hit Global AiI ' index for AiShots$() Global Dir ' for AI bombing testing 4 directions from last hit for more of ship hit
Global CurrentHits ' tracks how many hits have been made ' when ship is sunk subtract it's length Global BombX, BombY, Hit2 ' tracking bombs and hits for AI to sink ship ' Bombx, Bomby is next bomb location when working a first hit area ' Hit2 indicates the direction we are going was success on last hit, keep going!
' new for Counting Hits D1 east right, D2, west left, D3 down south, D4 up North Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) Global HitI, tryNextI ' HitI is HitIndex tryNextI tracks open slots of left of currentHits to shoot around
' set one time only stuff PXO = 8: PYO = 6 ' offsets for player grid display, tracks players ships and computers shots CXO = 35: CYO = 6 ' offsets for computer grid display, player shots hit= X miss= o SXO = 68: SYO = 10 ' offsets ships sunk tally For i = 1 To 10 Select Case i Case 1: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 2: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 3: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 4: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 5: ShipLen(i) = 2: ShipName$(i) = "Destroyer" Case 6: ShipLen(i) = 5: ShipName$(i) = "Carrier" Case 7: ShipLen(i) = 4: ShipName$(i) = "Battleship" Case 8: ShipLen(i) = 3: ShipName$(i) = "Cruiser" Case 9: ShipLen(i) = 3: ShipName$(i) = "Submarine" Case 10: ShipLen(i) = 2: ShipName$(i) = "Destroyer" End Select Next
While 1 'run game loop until player quits scan call Setup call Shoot Wend
Sub Setup ' get a game ready to play ' clear shared arrays and variables dim ShipX(10), ShipY(10), ShipHor(10), ShipHits$(10), ShipSunk(10), P(9, 9), C(9, 9), Hits(9, 9) PTurn = 0: GameOn = 0: AiI = 0: CurrentHits = 0 ' globals
'setup 2 bombing patterns to cover sea in checkerboard pattern one is chosen in each game s1$ = "A0B1C2D3E4F5G6H7I8J9I0J1A8B9E0F1G2H3I4J5A4B5C6D7E8F9C0D1E2F3G4H5I6J7A6B7C8D9G0H1I2J3A2B3C4D5E6F7G8H9" s2$ = "A9B8C7D6E5F4G3H2I1J0B0A1I9J8A5B4C3D2E1F0E9F8G7H6I5J4A3B2C1D0A7B6C5D4E3F2G1H0C9D8E7F6G5H4I3J2G9H8I7J6" If Rnd(0) < .5 Then shots$ = s1$ Else shots$ = s2$ ' don't be predictable with bombing patterns 'shots$ = s1$ ' shuffle sections: priority diagonal then sub diagonals, Mod 8 then mod 4 then mod 2 Dim T(50) For i = 1 To 50: T(i) = i: Next ' don't shuffle want to test with predictable bombing start = 1: stp = 10: call shuff start, stp start = 11: stp = 14: call shuff start, stp start = 15: stp = 26: call shuff start, stp start = 27: stp = 50: call shuff start, stp For i = 1 To 50 ' stow into an array AiShots$(i) = Mid$(shots$, 2 * T(i) - 1, 2) Next call ZeroOutHits Cls ' Game Board draw once per game Print "" Print " Player Computer" Print "" Print " A B C D E F G H I J A B C D E F G H I J" Print " ------------------- -------------------" Print " 0| . . . . . . . . . . 0| . . . . . . . . . ." Print " 1| . . . . . . . . . . 1| . . . . . . . . . ." Print " 2| . . . . . . . . . . 2| . . . . . . . . . ." Print " 3| . . . . . . . . . . 3| . . . . . . . . . . Ships: P C" Print " 4| . . . . . . . . . . 4| . . . . . . . . . . Carrier . ." Print " 5| . . . . . . . . . . 5| . . . . . . . . . . Battleship . ." Print " 6| . . . . . . . . . . 6| . . . . . . . . . . Cruiser . ." Print " 7| . . . . . . . . . . 7| . . . . . . . . . . Submarine . ." Print " 8| . . . . . . . . . . 8| . . . . . . . . . . Destroyer . ." Print " 9| . . . . . . . . . . 9| . . . . . . . . . ." Print " ------------------- -------------------" Print " A B C D E F G H I J A B C D E F G H I J"
'locate 5, 6: print "X"; ' check offsets
' debugg check AIshots$((aiI) OK 'For i = 1 To 50 'double check checker board coverage 50 cells in priority order ' x = InStr("ABCDEFGHIJ", Left$(AiShots$(i), 1)) - 1 ' y = Val(Mid$(AiShots$(i), 2, 1)) ' call LP x, y, "p", "O" ' call pause 1000 'Next
For i = 1 To 10 ' restring ship hits to all clear no hits ShipHits$(i) = String$(ShipLen(i), "o") Next call Autosetup 1 'setup the Computers ships offer to that for player Locate 1, 20 Print " Let computer setup your ships? press y for yes, n for no..."; k$ = Upper$(Input$(1)) call CLSpart
If k$ = "Y" Then call Autosetup 0 Else For s = 1 To 5 ' do it yourself ship placement OK = 0 While OK = 0 [placeAgain] Locate 1, 20 Print " Setting up the " + ShipName$(s) + " with length " + Str$(ShipLen(s)) Print " To place ship:" Print " Enter v for vertical, h for horizontal, letter+digit for top|left of ship." Input " Placement "; place$ call CLSpart place$ = Upper$(place$) ' check place If Left$(place$, 1) <> "V" And Left$(place$, 1) <> "H" Then PlayWave "tada.wav": GoTo [placeAgain] end if sx = InStr("ABCDEFGHIJ", Mid$(place$, 2, 1)) If sx < 1 Or sx > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sx = sx - 1 sy = InStr("0123456789", Mid$(place$, 3, 1)) If sy < 1 Or sy > 10 Then PlayWave "tada.wav": GoTo [placeAgain] Else sy = sy - 1
If Left$(place$, 1) = "V" Then ShipHor(s) = 0 Else ShipHor(s) = 1 If ShipHor(s) Then ' layout ship horiz If sx <= 10 - ShipLen(s) Then OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If End If Else ' layout vertical If sy <= 10 - ShipLen(s) Then OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", Trim$(Str$(s)) Next End If End If End If Wend Next End If End Sub
Sub Autosetup AItf If AItf Then 'setup Computer's ships 'setup a board with ships, Computer or AI's setup For s = 6 To 10 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If C(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 C(sx + xx, sy) = s 'call LP sx + xx, sy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If C(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 C(sx, sy + yy) = s 'call LP sx, sy + yy, "c", _Trim$(Str$(S Mod 10)) ' for debugg Next End If End If Wend Next Else 'setup Player's ships For s = 1 To 5 OK = 0 While OK = 0 ShipHor(s) = Rand(0, 1) If ShipHor(s) Then sy = Rand(0, 9) sx = Rand(0, 10 - ShipLen(s)) OK = 1 For xx = 0 To ShipLen(s) - 1 If P(sx + xx, sy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For xx = 0 To ShipLen(s) - 1 P(sx + xx, sy) = s call LP sx + xx, sy, "p", Trim$(Str$(s)) Next End If Else sx = Rand(0, 9) sy = Rand(0, 10 - ShipLen(s)) OK = 1 For yy = 0 To ShipLen(s) - 1 If P(sx, sy + yy) <> 0 Then OK = 0: Exit For Next If OK Then ShipX(s) = sx: ShipY(s) = sy For yy = 0 To ShipLen(s) - 1 P(sx, sy + yy) = s call LP sx, sy + yy, "p", _Trim$(Str$(s)) Next End If End If Wend Next End If End Sub
Sub FYI Info$ ' in place of a MessageBox 'Playwave "tada.wav" ' ????????????????????????? yes or no Locate 1, 20 Print Space$(3); Info$ + " (3 secs)"; locate 1, 20 call pause 4500 ' 8/3 lengthen call CLSpart End Sub
Sub LP x, y, pcGrid$, s$ If pcGrid$ = "p" Then Locate PXO + 2 * x, PYO + y Else Locate CXO + 2 * x, CYO + y Print s$; End Sub
Function Rand (low, high) ' Random integer from low to high inclusive Rand = Int(Rnd(0) * (high - low + 1)) + low End Function
Sub Shoot GameOn = 1 While GameOn If PTurn = 1 Then PTurn = 0 Else PTurn = 1 'PTurn = 0 ' for the AI Movie If PTurn Then ' player [playerAgain] Locate 1, 20 Input " Enter your next bomb site letter digit "; place$ call CLSpart place$ = Upper$(place$) bx = InStr("ABCDEFGHIJ", Left$(place$, 1)) - 1 by = instr("0123456789", Mid$(place$, 2, 1)) - 1 If bx >= 0 And bx < 10 Then ' better check If by >= 0 And by < 10 Then select case case C(bx, by) = 0 'miss call LP bx, by, "c", "o" C(bx, by) = -1 case C(bx, by) > 5 And C(bx, by) < 11 'hit call LP bx, by, "c", "X" playwave "tada.wav" call HitEval "c", bx, by 'game could end here C(bx, by) = C(bx, by) + 10 ' signal we hit this spot already! case C(bx, by) = -1 Or C(bx, by) > 10 ' already played playwave "tada.wav": GoTo [playerAgain] End select End If End If Else
'AI's turn if it gets a hit it will bomb around the ship until it is finished 'could be trouble if 2 ships are next to each other. Some effort to work it, 'still might get confused. 'hits() array tracks red = 1 and white pegs = -1 like a human player for AI
If CurrentHits > 0 Then 'we are working around the latest hit with bombx, bomby to test ' BombX, Bomby already deided in decide... sub If P(BombX, BombY) <> 0 Then 'hit! Hit2 = 1 ' signal AI that bomb x, y was a success, keep that direction going Hits(BombX, BombY) = 1 ' update hits board CurrentHits = CurrentHits + 1 ' update AI hit count Counting Hits!!!! call LP BombX, BombY, "p", "X" ' update display call pause 2500 ' new 8/3 'new stuff 2024-08-01 mod HitI = HitI + 1 ' increase index HitX(HitI) = BombX ' save location HitY(HitI) = BombY
' when hitEval announces a ship sunk we can reduce the currentHits count ' by that ships amount if still have more current hits, continue bombing ' area as another ship is there playwave "tada.wav" ' wakeup player! call HitEval "p", BombX, BombY ' this will reduce currentHits by ship sank If CurrentHits = 0 Then ' clear our checklist we sank all ships we hit, Call ZeroOutHits ' call off bombing of area Else call DecideWhereToBombNext End If Else 'no hit from checklist scratch off one item Hit2 = 0 ' signal ai that direction was not successful move on to next Hits(BombX, BombY) = -1 ' update ALL the hits on board call LP BombX, BombY, "p", "o" ' update board display call pause 6000 ' new 8/3 call DecideWhereToBombNext End If ' are we still working on hit Else 'not working on any hits x1, y1 = 0, dir = 0, currentHits might be = 0 'random but systematic shooting, bring up next good shooting location
[alreadyHit] AiI = AiI + 1 ' next random shoot If AiI > 50 Then ' we should never get this far but just in case x = Rand(0, 9) y = Rand(0, 9) Else ' normal shooting pattern by diagonals to form checker board coverage x = InStr("ABCDEFGHIJ", Left$(AiShots$(AiI), 1)) - 1 y = Val(Mid$(AiShots$(AiI), 2, 1)) End If If Hits(x, y) <> 0 Then GoTo [alreadyHit]
' was that shot just fired a hit or miss If P(x, y) <> 0 Then ' test our shot just fired is hit! CurrentHits = CurrentHits + 1 ' counting hits!! HitI = HitI + 1 HitX(HitI) = x HitY(HitI) = y Hits(x, y) = 1 ' update board call LP HitX(HitI), HitY(HitI), "p", "X" ' update display of board call pause 2500 ' new 8/3 playwave "tada.wav" ' wakeup player! call HitEval "p", HitX(HitI), HitY(HitI) ' see if ship sunk 'did we just happen to finish off a ship? If CurrentHits = 0 Then ' finished off all ships in area of hit call ZeroOutHits Else call DecideWhereToBombNext ' still working the hit area End If Else 'no hit Hits(x, y) = -1 ' record in board call LP x, y, "p", "o" ' update display call pause 6000 ' new 8/3 End If End If 'rI was hit or not End If 'whose turn is it 'call pause 1000 ' a sec pause to allow us to see computers move Wend Locate 1, 20 Print " Play Again? press y for yes, n for no..."; k$ = Input$(1) call CLSpart If k$ = "n" Then End End Sub
Sub HitEval board$, bbx, bby 'a referee for both players to announce a ship sunk and a game won? If board$ <> "p" Then s = C(bbx, bby) ' which ship number you$ = "Player": my$ = "Computer's" istart = 6: istop = 10 Else s = P(bbx, bby) you$ = "Computer": my$ = "Player's" istart = 1: istop = 5 End If If ShipHor(s) Then D = bbx - ShipX(s) + 1 Else D = bby - ShipY(s) + 1 ShipHits$(s) = SubStr$(ShipHits$(s), D, "X") If ShipHits$(s) = String$(ShipLen(s), "X") Then ShipSunk(s) = 1 ' this is only thing ref does to help Computer AI If board$ = "p" Then CurrentHits = CurrentHits - ShipLen(s) call UpdateStatus call FYI "Congrats: " + you$ + " sank " + my$ + " " + ShipName$(s) + "!" tot = 0 For i = istart To istop If ShipSunk(i) = 1 Then tot = tot + 1 Next If tot = 5 Then call UpdateStatus If you$ = "Computer" Then call ShowComputersShips call FYI "Congrats: " + you$ + ", you sank all " + my$ + " ships! Game Over" GameOn = 0 End If End If End Sub
Sub DecideWhereToBombNext ' this sets the next place to try with bombX, bombY If Hit2 Then 'whatever direction we are taking, continue if we can Select Case Dir Case 1 If BombX + 1 <= 9 Then If Hits(BombX + 1, BombY) = 0 Then BombX = BombX + 1: Exit Sub End If End If Case 2 If BombX - 1 >= 0 Then If Hits(BombX - 1, BombY) = 0 Then BombX = BombX - 1: Exit Sub End If End If Case 3 If BombY + 1 <= 9 Then If Hits(BombX, BombY + 1) = 0 Then BombY = BombY + 1: Exit Sub End If End If Case 4 If BombY - 1 >= 0 Then If Hits(BombX, BombY - 1) = 0 Then BombY = BombY - 1: Exit Sub End If End If End Select ' still here then the direction is no longer good to try Hit2 = 0 ' turn off signal End If
tryNextI = 1 'vsearch next open hit location not tested While tryNextI <= HitI ' Not CurrentHits !!! If D1(tryNextI) = 0 Then D1(tryNextI) = 1 If HitX(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI) + 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) + 1: BombY = HitY(tryNextI): Dir = 1: Exit Sub End If End If End If If D2(tryNextI) = 0 Then D2(tryNextI) = 1 If HitX(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI) - 1, HitY(tryNextI)) = 0 Then BombX = HitX(tryNextI) - 1: BombY = HitY(tryNextI): Dir = 2: Exit Sub End If End If End If If D3(tryNextI) = 0 Then D3(tryNextI) = 1 If HitY(tryNextI) + 1 <= 9 Then If Hits(HitX(tryNextI), HitY(tryNextI) + 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) + 1: Dir = 3: Exit Sub End If End If End If If D4(tryNextI) = 0 Then D4(tryNextI) = 1 If HitY(tryNextI) - 1 >= 0 Then If Hits(HitX(tryNextI), HitY(tryNextI) - 1) = 0 Then BombX = HitX(tryNextI): BombY = HitY(tryNextI) - 1: Dir = 4: Exit Sub End If End If End If tryNextI = tryNextI + 1 Wend ' exhausted all hit locations hit1 area played out!!! CurrentHits = 0 ' abandon hit area call ZeroOutHits End Sub
Sub UpdateStatus ' ships sunk area of the display For i = 1 To 5 ' row 10 carrier player colum 66 computer column 68 If ShipSunk(i) Then Locate 68, i + 9: Print "X"; If ShipSunk(i + 5) Then Locate 70, i + 9: Print "X"; Next locate 1, 20 End Sub
Sub ShowComputersShips ' fixed this so only empty spaces not bombed are displayed For s = 6 To 10 If ShipHor(s) Then sx = ShipX(s): sy = ShipY(s) For xx = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), xx + 1, 1) = "o" Then call LP sx + xx, sy, "c", Trim$(Str$(s Mod 10)) End If Next Else sx = ShipX(s): sy = ShipY(s) For yy = 0 To ShipLen(s) - 1 If Mid$(ShipHits$(s), yy + 1, 1) = "o" Then call LP sx, sy + yy, "c", Trim$(Str$(s Mod 10)) End If Next End If Next End Sub
Sub CLSpart ' clear lower part of screen For i = 20 To 25 Locate 1, i: Print Space$(80) Next Locate 1, 20 End Sub
Sub ZeroOutHits ' at setup and everytime CurrentHits is set back to zero Dim HitX(17), HitY(17), D1(17), D2(17), D3(17), D4(17) HitI = 0: Dir = 0: Hit2 = 0: tryNextI = 0 End Sub
function SubStr$(s$, place, subst$) for i = 1 to len(s$) if i = place then r$ = r$ + subst$ else r$ = r$ + mid$(s$, i, 1) next SubStr$ = r$ end function
function String$(number, s$) for i = 1 to number r$ = r$ + s$ next String$ = r$ end function
sub pause mil 'tsh version has scan built-in t0 = time$("ms") while time$("ms") < t0 + mil : scan : wend end sub
sub shuff start, stp for i = stp to start + 1 step -1 r = Rand(start, stp) temp = T(i) T(i) = T(r) T(r) = temp next end sub
My filename, for my reference at least, is in the first line at the top. BTW while testing changes I barely edged out Computer finding the Destroyer when it had found the last ship it needed to finish me off! What a dramatic ending to that game! b = b + ...
|
|
|
Post by plus on Aug 3, 2024 14:26:14 GMT
Using the blinking cursor to point is pretty neat and unique feature to JB, file that lesson for the future!
Also while testing the pauses I discovered something that will shorten a game considerable and pretty much assure the win if AI happens to find Destroyer early before other player (me). Dang I am onto still another mod for the BS AI, can't seem to let go of this thing yet!
b = b + ...
|
|
|
Post by tsh73 on Aug 3, 2024 19:22:12 GMT
Something is wrong, isn't it? I have shot h5 i5 j5 "oXX" but it doesn't show computer destroyer killed
Player Computer
A B C D E F G H I J A B C D E F G H I J ------------------- ------------------- 0| . o . . . . . . o X 0| o . . o . . o . . o 1| o . . o X o . . o X 1| . o . . o . . o . . 2| . . 4 o 2 . . o . X 2| . . o . X o . . o . 3| . . 4 . 2 . o . . . 3| o . . o X . o . . o Ships: P C 4| . o 4 . 2 o . . . o 4| . o . o X o . o . . Carrier X . 5| o . . . X X . . o . 5| . . o X o . . o X X Battleship . . 6| . . . o . . . o . . 6| . . o X o . . . . . Cruiser X X 7| . . o . . . o . . . 7| . . . X . . . . . . Submarine . X 8| . o . . . . . . . o 8| . . . o . . . . . . Destroyer X . 9| o . . . . X X X X X 9| . . . . . . . . . . ------------------- ------------------- A B C D E F G H I J A B C D E F G H I J
Enter your next bomb site letter digit
Here's board opened after my defeat:
Player Computer
A B C D E F G H I J A B C D E F G H I J ------------------- ------------------- 0| . o . . . . . . o X 0| o . . o . . o . . o 1| o . . o X o . . o X 1| . o . . o . . o . . 2| . . X o X . . o . X 2| . . o . X o . . o . 3| . o X o X . o . . . 3| o . . o X . o . . o Ships: P C 4| . o X . X o . . . o 4| . o . o X o . o 7 0 Carrier X . 5| o . o . X X . . o . 5| . 6 o X o . . o X X attleship . X 6| . . . o . . . o . . 6| o 6 o X o . o . 7 o Cruiser X X 7| . . o . . . o . . . 7| o X o X . . . . 7 . Submarine X X 8| . o . . . . . . . o 8| . X . o . . . . . . Destroyer X . 9| o . . . . X X X X X 9| . 6 . . . . . . . o ------------------- ------------------- A B C D E F G H I J A B C D E F G H I J
Play Again? press y for yes, n for no...
|
|