;---------------------------------------------------> ;+ ;NAME: ; BATTLESHIP ; ;PURPOSE: ; Play the BattleShip board game against the computer AI. ; ;CALLING SEQUENCE: ; BATTLESHIP ; ;REQUIRED INPUTS: ; none ; ;KEYWORDS: ; none ; ;OUTPUTS: ; none ; ;EXAMPLE: ; IDL> battleship ; IDL begins the game engine. Follow the command line prompts. ;HISTORY: ; Written - Paul Higgins - 29 January 2008 ;- ;---------------------------------------------------> pro battleship_define_common COMMON battleship_param, xsea, ysea, xgame, ygame, blanksea, shipdim xsea=500 ysea=500 xgame=10 ygame=10 blanksea=fltarr(xsea,ysea) shipdim=[2,3,3,4,5] return end ;---------------------------------------------------> function battleship_shipnames, shipind case shipind of 0: name='Recon Craft' 1: name='Gun Boat' 2: name='Submarine' 3: name='Destroyer' 4: name='Aircraft Carrier' endcase return,name end ;---------------------------------------------------> pro battleship_blink,wind,period,duration COMMON battleship_param winbg=fltarr(xsea,ysea)+1 winbg[0]=0 imax=duration/(period*2) wset,wind for i=0,imax-1 do begin wait,period erase wait,period tvscl,winbg,channel=1 endfor return end ;---------------------------------------------------> function battleship_genship, seaarr, mysea=mysea, $ aisea=aisea COMMON battleship_param nships=5 sizesea=size(seaarr) xsea=sizesea[1] ysea=sizesea[2] boxsz=[xsea/xgame, ysea/ygame] ;generate ships shipstack=fltarr(xsea,ysea,nships) shiftstack=shipstack ship1=seaarr ship1[0:boxsz[0]*2-1,ysea-boxsz[1]:ysea-1]=1 shipstack[*,*,0]=ship1 ship2=seaarr ship2[0:boxsz[0]*3-1,ysea-boxsz[1]:ysea-1]=1 shipstack[*,*,1]=ship2 ship3=ship2 shipstack[*,*,2]=ship3 ship4=seaarr ship4[0:boxsz[0]*4-1,ysea-boxsz[1]:ysea-1]=1 shipstack[*,*,3]=ship4 ship5=seaarr ship5[0:boxsz[0]*5-1,ysea-boxsz[1]:ysea-1]=1 shipstack[*,*,4]=ship5 for i=0,4 do begin thisship=shipstack[*,*,i] rurange=[(xgame-shipdim[i]-1),(ygame-2)] rotship=round(randomu(seed)) if rotship eq 1 then begin shiftship=shift(rot(thisship,-90),0,(ygame-shipdim[i])*boxsz[1]) endif else shiftship=thisship nolayer=0 nosplit=0 while nolayer eq 0 do begin shifts=[round(randomu(seed1)*rurange[0])*boxsz[0], $ round(randomu(seed2)*rurange[1])*boxsz[1]] if rotship eq 1 then shifts=reverse(shifts) shiftship=shift(shiftship,shifts[0],-1*shifts[1]) shiftstack[*,*,i]=shiftship shiparr=total(shiftstack,3) wlayer=where(shiparr gt 1) if wlayer[0] eq -1 then nolayer=1 endwhile shiftstack[*,*,i]=shiftship endfor return, shiftstack end ;---------------------------------------------------> pro battleship_display, seaarr, shotvect, $ mysea=mysea, aisea=aisea, shotarr=shotarr COMMON battleship_param seasz=size(seaarr) boxsz=[seasz[1]/xgame, seasz[2]/ygame] if keyword_set(mysea) then begin winind=0 !p.background=0 !p.color=!blue channel=2 endif if keyword_set(aisea) then begin winind=2 !p.background=0 !p.color=!red channel=2 endif shipdim=[2,3,3,4,5] winxs=500 winys=500 blankticks=strarr(10)+' ' xtickv=findgen(xgame)+1 ytickv=findgen(ygame)+1 ;display sea window, winind, xs=winxs, ys=winys tvscl,congrid(seaarr,winxs,winys), channel=channel for i=1,n_elements(shotvect[1,*])-1 do begin thisshot=shotvect[*,i] if thisshot[2] eq 1 then colorcirc=!red else colorcirc=!blue tvcircle, .25, floor(thisshot[0])/boxsz[0]+.5, $ floor(thisshot[1])/boxsz[1]+.5, colorcirc, /data, /fill endfor contour,congrid(seaarr,winxs,winys),level=.5,color=!orange,thick=4,/noerase, $ pos=[0,0,1,1],xstyle=4,ystyle=4 ;show gridlines plot, fltarr(xgame), fltarr(ygame), /xstyle, /ystyle, xgrid=2, ygrid=2, $ xticklen=1, yticklen=1, position=[0,0,1,1], xtickname=blankticks, $ ytickname=blankticks, xticks=xgame, yticks=ygame, xtickv=xtickv, $ ytickv=ytickv, /noerase return end ;---------------------------------------------------> pro battleship_fire, shipstack, shotarr, shotvect, thesea, boatsdown, $ aiguess, aihitboat, myshot=myshot, aishot=aishot COMMON battleship_param ;single array of the ships shiparr=total(shipstack,3) ; size vector of the ship stack stacksz = size(shipstack) ;find the dimensions of a grid box boxsz=[stacksz[1]/xgame,stacksz[2]/ygame] ;how many elements in the shipstack nstack=stacksz[4] if keyword_set(myshot) then begin ;set the active window and prompt the user for a shot wset, 2 print,[[' '],['Click in the RED WINDOW to take a shot.'],[' ']] cursor, xcoord, ycoord, wait=4, /data endif else begin ;generate the computers guess ;print,'2ndpass aiguess' ;help,aiguess coordvect=battleship_aifire(shipstack, aihitboat, aiguess) xcoord=coordvect[0] ycoord=coordvect[1] aiguess[coordvect[2]]=1 endelse ;a 2 element array of the (rounded down) data location of the shot hitloc=[floor(xcoord)*boxsz[0]+boxsz[0]*.5,floor(ycoord)*boxsz[1]+boxsz[1]*.5] ;a sea array with a single pt=1 at the location of the shot. shotptarr=fltarr(stacksz[1],stacksz[2],1) shotptarr[hitloc[0],hitloc[1],0]=1 ;a sea array with filled in grid boxes where there have already been shots made. shotarr[floor(hitloc[0]/boxsz[0])*boxsz[0]: $ floor(hitloc[0]/boxsz[0])*boxsz[0]+boxsz[0]-1, $ floor(hitloc[1]/boxsz[1])*boxsz[1]: $ floor(hitloc[1]/boxsz[1])*boxsz[1]+boxsz[1]-1]=1 ;if a hit was scored, which ship was it? dummy=shipstack for i=0,stacksz[3]-1 do dummy[*,*,i]=dummy[*,*,i]+shotptarr whit = where((dummy) gt 1) ;shotptarr=reform(shotptarr) ;add the shot to the record of all shots taken shotvect=[[shotvect],[floor(xcoord)*boxsz[0],floor(ycoord)*boxsz[1], whit ge 0]] ;the ship in the stack that was hit zstack = whit[0]/(stacksz[1]*stacksz[2]) ;Make array with all shots taken and add to single ship array shotptarr=fltarr(stacksz[1],stacksz[2]) shotstring=shotvect[1,1:*]*stacksz[1]+shotvect[0,1:*] shotptarr[shotstring]=1 hitshiparr = shipstack[*,*,zstack]+shotptarr if keyword_set(myshot) then begin if whit[0] eq -1 then begin print,[[' '],['You Missed!'],[' ']] wait,.5 endif else begin print,[[' '],['You Scored a HIT!'],[' ']] wait,.5 if n_elements(where(hitshiparr gt 1)) ge shipdim[zstack] then begin print,'Enemy '+battleship_shipnames(zstack)+' was DESTROYED!' thesea[where(shipstack[*,*,zstack] ge 1)]=1 boatsdown=boatsdown+1 endif endelse endif else begin if whit[0] eq -1 then begin print,[[' '],['Enemy Missed!'],[' ']] wait,.5 endif else begin print,[[' '],['Enemy Scored a HIT!'],[' ']] wait,.5 if n_elements(where(hitshiparr gt 1)) ge shipdim[zstack] then begin print,'Your '+battleship_shipnames(zstack)+' was DESTROYED!' thesea[where(shipstack[*,*,zstack] ge 1)]=1 battleship_blink,0,.1, .5 shipstack[*,*,zstack]=fltarr(stacksz[1],stacksz[2]) dummystack=shipstack dummystack[*,*,zstack]=fltarr(stacksz[1],stacksz[2]) thesea=total(dummystack,3) boatsdown=boatsdown+1 aihitboat=[0,-1] endif else aihitboat=[1,zstack] endelse endelse return end ;---------------------------------------------------> ;--<< For future use. AI will choose to randomly fire at ;--<< squares on a checkered grid untill it hits a ship. function battleship_shotgrid COMMON battleship_param x=fltarr(xgame,ygame) y=x wx=where(x eq 0) wodd=where(wx mod 2 eq 1) x[wodd]=1 wyodd=where((wx+reform(transpose(x),n_elements(wx))) mod 2 eq 1) y[wyodd]=1 return,y end ;---------------------------------------------------> function battleship_aifire, shipstack, aihitboat, aiguess COMMON battleship_param ;print,'aihitboat',aihitboat ;print,'lastpass aiguess' ;help,aiguess ;wset,3 ;window,3 ;display,aiguess ;wset,0 wdidshoot=where(aiguess gt 0) if aihitboat[0] ne 1 then begin shotgrid=battleship_shotgrid() ; wcanshoot=where(shotgrid ne 0) ; wwne=where(wcanshoot ne wdidshoot) ; wshoot=wcanshoot[wwne] ;help,wshoot ; wwshot=round(randomu(seed)*(n_elements(wshoot)-1)) aig2=aiguess if wdidshoot[0] ne -1 then aig2[wdidshoot]=aig2[wdidshoot]+1 canshoot=shotgrid+aig2 wcanshoot=where(canshoot eq 1) wwshot=round(randomu(seed)*(n_elements(wcanshoot)-1)) coord=[wcanshoot[wwshot] mod xgame, wcanshoot[wwshot]/ygame, $ wcanshoot[wwshot]] endif else begin shiparr=shipstack[*,*,aihitboat[1]] shiparr=rebin(shiparr,10,10,1,/sample) shiparr=reform(shiparr) wship=where(shiparr eq 1) aig2=aiguess aig2[wdidshoot]=aig2[wdidshoot]+1 canshoot=shiparr+aig2 wcanshoot=where(canshoot eq 1) wwshot=round(randomu(seed)*(n_elements(wcanshoot)-1)) ; wtohit=where(wship ne wdidshoot) ;help,wtohit ; wwshot=round(randomu(seed)*(n_elements(wtohit)-1)) coord=[wcanshoot[wwshot] mod xgame, wcanshoot[wwshot]/ygame, $ wcanshoot[wwshot]] endelse ;print,'coord',coord return, coord end ;---------------------------------------------------> pro battleship print,[[' '],$ ['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'],$ [' '],$ ['Interactive Data BattleShip Version 1.0 - By: Paul Higgins'],$ [' '],$ ['XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'],$ [' ']] wait,.5 battleship_define_common COMMON battleship_param mysea=blanksea aisea=blanksea myshotarr=blanksea aishotarr=blanksea myshotvect=['','',''] aishotvect=['','',''] myboatsdown=0 aiboatsdown=0 aiguess=fltarr(10,10) aihitboat=[0,-1] print,[[' '],['Generating ship formations...'],[' ']] battleship_display, mysea, aishotvect, /mysea battleship_display, aisea, myshotvect, /aisea aishipstack=battleship_genship(aisea) happy=0 while happy eq 0 do begin myshipstack=battleship_genship(mysea) battleship_display, mysea+total(myshipstack,3), $ aishotvect, /mysea print,[[' '],['Are you happy with this formation? (Y/N)'],[' ']] ans='' read,ans if strlowcase(ans) ne 'n' then happy=1 endwhile mysea=mysea+total(myshipstack,3) ;BEGIN GAME ENGINE while myboatsdown lt 5 and aiboatsdown lt 5 do begin print,[[' '],['You are being fired upon!!!'],[' ']] wait,.5 ;print,'mainpass aiguess' ;help,aiguess battleship_fire, myshipstack, aishotarr, aishotvect, $ mysea, myboatsdown, aiguess, aihitboat, /aishot battleship_display, mysea, aishotvect, /mysea if myboatsdown eq 5 then break print,[[' '],['Fire a volley back!!!'],[' ']] wait,.5 battleship_fire, aishipstack, myshotarr, myshotvect, $ aisea, aiboatsdown, /myshot battleship_display, aisea, myshotvect, /aisea if aiboatsdown eq 5 then break endwhile ;END GAME ENGINE if myboatsdown eq 5 then print, [[' '],['You have been DESTROYED!!!'], $ ['Reign of the Machines!!!'],[' ']] else print, [[' '], $ ['You have DEFEATED my AI algorithm!!!'],[' ']] print,'GAME OVER' end ;--------------------------------------------------->