Have a nice day!!
Code: Select all
; ==========================================================================================================
; Author: Massimo ([email protected])
; Name: Battleship
; Description: The classic game Battleship running on Notepad
; Date Started: 08/05/2021 dd/mm
; Tested on: Win 10
; System Requirements: Windows
; Required: Notepad
; Note: Feel free to change whatever you want, I am not a native english so if you have any improvements for text messages feel free to change them
; I am just a student so please forgive me for any quirks or unnecessary repetitions or operations
; =========================================================================================================
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
SetKeyDelay, 3
Start(ByRef Grid){ ;This function load up the four grid in the game, a grid is 10x10 so 100 boxes. Note that i used a unidimensional array
Loop, 100{
Grid[A_Index]:="~"
}
return
}
Get_Name(ByRef Player_1, ByRef Player_2){ ;This function is used to get the player's names
SendEvent, `t`tBATTLESHIP by Max`n`n
SendEvent,Welcome captains`, please enter yours names`n
SendEvent,Captain 1(press enter to confirm):{Space}
Input, Player_1,V,{Enter}
SendEvent,Captain 2(press enter to confirm):{Space}
Input, Player_2,V,{Enter}
return
}
Syntax(Coord){ ;This function is used to verify the correct input of coordinates. Since the input of coordinates is a string of 3 characters
Error:=0 ;I used a Loop to split the string "Coord" in 3 characters and use each of them as an individual variable
Loop, Parse, Coord,,, ;<----- "Loop, Parse," https://www.autohotkey.com/docs/commands/LoopParse.htm - Official reference
{
Switch A_Index{
Case 1:
if A_LoopField not in a,b,c,d,e,f,g,h,i,j ;<----- "A_LoopField" https://www.autohotkey.com/docs/Variables.htm#loop - Official reference
{
Error:=1
break
}
Case 2:
if A_LoopField not in 0,1,2,3,4,5,6,7,8,9
{
Error:=1
break
}
Case 3:
if A_LoopField not in u,d,l,r
{
Error:=1
break
}
}
}
return Error
}
Edges(Coord,Length){ ;This function is used to verify if a ship would exceed the edges of the grid, "Length is the length of the ship"
Letter:= ;"Letter" I used this variable to conserve the corresponding number of the 1st character in "Coord"
Num:= ;"Num" I used this variable to conserve the number of the 2nd character in "Coord"
Dir:= ;Direction I used this variable to conserve the 3rd character in "Coord"
Error:=0
Loop, Parse, Coord,,, ;I used a Loop to split the string "Coord" in 3 characters and use each of them as an individual variable
{
if (A_Index==1)
Letter:=Asc(A_LoopField)-96 ;This operation transform the 1st character in "Coord" in a number, Asc() converts char in the corresponding Ascii value
if (A_index==2)
Num:=A_LoopField
if (A_index==3)
Dir:=A_LoopField
}
switch Dir{
case "u": ;===============================================================
Last:=Num-Length ;These operation are different because they depend on direction in Coord.
if(Last<-1) ;Remeber the grid is 10x10. If i would choose coord as a3 with a ship of 3 box, in this case ("u"=up)
Error:=1 ; it would be 3-3=0 so it could be placed. If i would choose a2, 2-3=-1
case "d": ;==============================================================
Last:=Num+Length ;See comment at 78th line
if(Last>10)
Error:=1
case "l":
Last:=Letter-Length ;See comment at 78th line
if(Last<0)
Error:=1
case "r":
Last:=Letter+Length ;See comment at 78th line
if(Last>11)
Error:=1
}
return Error
}
Free_Box(Grid,Coord,Length){ ;This function is used to verify if a ship would be placed on another one
Letter:= ;"Letter" I used this variable to conserve the corresponding number of the 1st character in "Coord"
Num:= ;"Num" I used this variable to conserve the number of the 2nd character in "Coord"
Dir:= ;Direction I used this variable to conserve the 3rd character in "Coord"
Box:=
Error:=0
Loop, Parse, Coord,,, ;I used a Loop to split the string "Coord" in 3 characters and use each of them as an individual variable
{
if (A_Index==1)
Letter:=Asc(A_LoopField)-96 ;This operation transform the 1st character in "Coord" in a number, Asc() converts char in the corresponding Ascii value
if (A_index==2)
Num:=A_LoopField
if (A_index==3)
Dir:=A_LoopField
} ;=================================================================
Box:=(Num*10)+Letter ;Since the variable "Coord" gives to me a letter that I converted in a number (a=1;b=2...) and a numer
Loop, %Length%{ ; I used this operation to get the number of the corresponding box in the grid
switch Dir{ ;=================================================================
case "u":
if (Grid[Box-(10*A_Index-10)]!="~") ;These operation are different because they depend on direction in Coord.
Error:=1
case "d":
if (Grid[Box+(10*A_Index-10)]!="~") ;See comment at 116th line
Error:=1
case "l":
if (Grid[Box-(A_index-1)]!="~") ;See comment at 116th line
Error:=1
case "r":
if (Grid[Box+(A_index-1)]!="~") ;See comment at 116th line
Error:=1
}
if (Error==1)
break
}
return Error
}
Get_Coord(ByRef Grid,Ship){ ;This function get and check the coordinates using the function described above, Syntax(), Edges(), Free_Box()
i:=
Error:=1
Switch Ship{
case "Carrier": i:=1
case "Battleship": i:=1
case "Cruiser": i:=1
case "Destroyer": i:=2
}
loop, %i%{
while(Error==1){
Coord:=""
Input,Coord,V ,{Enter}
if(Syntax(Coord)!=0){
SendEvent,`nYour input is invalid`, try again and remember the correct syntax(ex. b8u) then press enter`nCoordinates:
Error:=1
} else if (Free_box(Grid,Coord,i)!=0){
SendEvent,`nRange already occupied`, try again and remember the correct syntax(ex. b8u) then press enter`nCoordinates:
Error:=1
} else if (Edges(Coord,i)!=0){
SendEvent,`nYour ship would exceed the grid`, try again and remember the correct syntax(ex. b8u) then press enter`nCoordinates:
Error:=1
} else
Error:=0
}
Ships(Grid,Coord,Ship) ;If the coordinates entered by the user are good they will be sent to the Ships() function described below
}
}
Ships(ByRef Grid,Coord,Ship){ ;This function write the ship in the grid
Letter:=
Num:=
Dir:=
Box:=
Length:=
switch Ship{
case "Carrier": Length:=5
case "Battleship": Length:=4
case "Cruiser": Length:=3
case "Destroyer": Length:=2
}
Loop, Parse, Coord,,,
{
if (A_Index==1)
Letter:=Asc(A_LoopField)-96
if (A_index==2)
Num:=A_LoopField
if (A_index==3)
Dir:=A_LoopField
}
Box:=(Num*10)+Letter
Loop, %Length%{
if(A_Index==Length){ ;This if statement is used to check the last box of the ship (the bow)
switch Dir{
case "u": Grid[Box-(10*A_Index-10)]:="A" ;As you can see, to give a sense of direction, I used different characters for up, down, left and right direction
case "d": Grid[Box+(10*A_Index-10)]:="V"
case "l": Grid[Box-(A_index-1)]:="<"
case "r": Grid[Box+(A_index-1)]:=">"
}
} else{
switch Dir{
case "u": Grid[Box-(10*A_Index-10)]:="■" ;This character is used for the body of the ships
case "d": Grid[Box+(10*A_Index-10)]:="■"
case "l": Grid[Box-(A_index-1)]:="■"
case "r": Grid[Box+(A_index-1)]:="■"
}
}
}
}
Fire(Grid, Byref Grid_Hit,Player){ ;This function is used to "fire" each other ships, "Grid" is the variable that store the grid with ships; "Grid_Hit" it stores
Letter:= ; the outcome of player's shot
Num:=
Box:=
Score:=0 ;This variable is used to check the outcome of player's shot; 0=miss, 1=hit
Error:=1
Send, ^a{BackSpace}
Field(Grid_Hit)
SendEvent,`n`nCaptain %Player%`, in which coordinates you want to attack?`nEnter the coordinates:
while(Error==1){
Coord:=""
Input,Coord,V ,{Enter}
Coord:=Coord . "u" ;I added this "u" character to the "Coord" variable even though I don't need it. I did it because the function Syntax()
if(Syntax(Coord)!=0){ ; check for 3 character, if i would omit it, Syntax() would return me error
SendEvent,`n`nYour input is invalid`, try again and remember the correct syntax(ex. b8) then press enter`nCoordinates:
Error:=1
} else
Error:=0
}
Loop, Parse, Coord,,,
{
if (A_Index==1)
Letter:=Asc(A_LoopField)-96
if (A_index==2)
Num:=A_LoopField
}
Box:=(Num*10)+Letter
if (Grid[Box]!="~"){
Score:=1
Grid_Hit[Box]:="X"
SendEvent,{Text}`nYou hit a ship! Keep going`nPress space to continue
KeyWait, Space, D
} else {
Score:=0
Grid_Hit[Box]:="O"
SendEvent,`nUnfortunately you missed the shot`nPress space to continue
KeyWait, Space, D
}
return Score ;If the shot is confirmed it return 1
}
Placement(ByRef Grid,Player){ ;This function is used to group many of the function above to place a ship in the grid
Send, ^a{BackSpace}
SendEvent, `t`tBATTLESHIP by Max`n`n
SendEvent,{Text}So then %Player%`, let's start placing your ships first. Make sure your friend isn't peeking!`n
SendEvent,When you are ready, press Space
KeyWait, Space, D
Send, ^a{BackSpace}
Field(Grid)
Send,`nShips:`nx1) Carrier (5 boxes)`nx1) Battleship (4 boxes)`nx1) Cruiser (3 boxes)`nx2) Destroyer (2 boxes)`n
Send,(Example a3r, the third character indicates the direction for the ship u=up; d=down; l=left; r=right)`n`n
SendEvent,Coordinates for Carrier:
Get_Coord(Grid,"Carrier")
Send, ^a{BackSpace}
Field(Grid)
Send,`nShips:`nx1) Carrier (5 boxes)`nx1) Battleship (4 boxes)`nx1) Cruiser (3 boxes)`nx2) Destroyer (2 boxes)`n
Send,(Example a3r, the third character indicates the direction for the ship u=up; d=down; l=left; r=right)`n`n
SendEvent,Coordinates for Battleship:
Get_Coord(Grid,"Battleship")
Send, ^a{BackSpace}
Field(Grid)
Send,`nShips:`nx1) Carrier (5 boxes)`nx1) Battleship (4 boxes)`nx1) Cruiser (3 boxes)`nx2) Destroyer (2 boxes)`n
Send,(Example a3r, the third character indicates the direction for the ship u=up; d=down; l=left; r=right)`n`n
SendEvent,Coordinates for Cruiser:
Get_Coord(Grid,"Cruiser")
Send, ^a{BackSpace}
Field(Grid)
Send,`nShips:`nx1) Carrier (5 boxes)`nx1) Battleship (4 boxes)`nx1) Cruiser (3 boxes)`nx2) Destroyer (2 boxes)`n
Send,(Example a3r, the third character indicates the direction for the ship u=up; d=down; l=left; r=right)`n`n
SendEvent,Coordinates for Destroyer:
Get_Coord(Grid,"Destroyer")
Send, ^a{BackSpace}
Field(Grid)
Send,`nShips:`nx1) Carrier (5 boxes)`nx1) Battleship (4 boxes)`nx1) Cruiser (3 boxes)`nx2) Destroyer (2 boxes)`n
Send,(Example a3r, the third character indicates the direction for the ship u=up; d=down; l=left; r=right)`n`n
SendEvent,Coordinates for Destroyer:
Get_Coord(Grid,"Destroyer")
return
}
Field(ByRef Grid){ ;This function is used to diplay grids
SendEvent, `t`tBATTLESHIP by Max`n`n
SendEvent,{Space 3}| A | B | C | D | E | F | G | H | I | J{Space}
Loop, 10{
n:=A_Index*10-10
num:=A_index-1
SendEvent,|`n{Space}%num%{Space}
Loop, 10{
a:=Grid[A_Index+n]
Send,| %a%{Space}
}
}SendEvent,|
return
}
Grid_1:=[] ;Array storing player_1's ship
Grid_2:=[] ;Array storing player_2's ship
Grid_3:=[] ;Array storing player_1's shot
Grid_4:=[] ;Array storing player_1's shot
Player_1:="" ;String variable of player_1's name
Player_2:="" ;String variable of player_2's name
Score_1:=0 ;Integer variable storing successful player_1's shots
Score_2:=0 ;Integer variable storing successful player_1's shots
Hit:=1 ;Boolean variable used to conserve the hit or miss player's status; 0=miss, 1=hit
Run, Notepad.exe,,Max
Sleep, 1000
Get_Name(Player_1, Player_2) ;Getting player's name
Start(Grid_1) ;Initializing array
Start(Grid_2) ;Initializing array
Start(Grid_3) ;Initializing array
Start(Grid_4) ;Initializing array
Placement(Grid_1, Player_1) ;Placing player_1's ships
Placement(Grid_2, Player_2) ;Placing player_1's ships
while ((Score_1<16) and (Score_2<16) ){ ;Total number of boxes to be hit is 16
while (Hit==1){ ;Player_1 can hit consecutively as long as his hits are confirmed
Hit:=Fire(Grid_2,Grid_3,Player_1)
Score_1:=Score_1+Hit
}
Hit:=1
if(Score_1==16)
break
while (Hit==1){ ;Player_2 can hit consecutively as long as his hits are confirmed
Hit:=Fire(Grid_1,Grid_4,Player_2)
Score_2:=Score_2+Hit
}
Hit:=1
if(Score_2==16)
break
}
if (Score_1>Score_2){
Send, ^a{BackSpace}
SendEvent, `t`tBATTLESHIP by Max`n`n
SendEvent,{text}CONGRATULATION %Player_1%`, you won!
} else {
Send, ^a{BackSpace}
SendEvent, `t`tBATTLESHIP by Max`n`n
SendEvent,{text}CONGRATULATION %Player_2%`, you won!
}
Send,`n`nPress space to close the game
KeyWait, Space, D
ExitApp