Battleship

Post gaming related scripts
Tachipirina
Posts: 5
Joined: 08 Mar 2021, 13:29

Battleship

Post by Tachipirina » 08 Mar 2021, 13:40

Hi guys today i finished my personal code for battleship. I would like to share it with you to receive comments, negatives or positives are both fine, suggestion or whatever you want! Anyway i post both source code and file of source code.
Have a nice day!!
BattleShip.ahk
(13.49 KiB) Downloaded 160 times

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

User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: Battleship

Post by SpeedMaster » 08 Mar 2021, 18:15

I like ASCII games. :thumbup:
I've done a few of them too. :roll:
I had to make a small modification to make your game work for me.
I don't know why but it seems that with the character ~ you have to send two spaces instead of one. :think:
I also changed SendEvent to SendInput to make the game faster.

here is the change I made: (line 285)

Code: Select all

Field(ByRef Grid){																					;This function is used to diplay grids
	SendInput, `t`tBATTLESHIP by Max`n`n
	SendInput,{Space 3}| A | B | C | D | E | F | G | H | I | J{Space}
	Loop, 10{
		n:=A_Index*10-10
		num:=A_index-1
		SendInput,|`n{Space}%num%{Space}
		Loop, 10{
			a:=Grid[A_Index+n]
            if (a=="~")
			  SendInput, |{Space}%a%{Space}{Space}
            else
			  SendInput, |{Space}%a%{Space}
		}
	}SendInput,|
	return
}

Post Reply

Return to “Gaming Scripts (v1)”