mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-01 15:49:59 -08:00
240 lines
6.0 KiB
Plaintext
240 lines
6.0 KiB
Plaintext
print " "*33 + "Salvo"
|
|
print " "*15 + "Creative Computing Morristown New Jersey"
|
|
print; print; print
|
|
|
|
import "listUtil"
|
|
|
|
Ship = {}
|
|
Ship.name = "Ship"
|
|
Ship.positions = null // list of [x,y] coordinates for this ship
|
|
Ship.shots = 1 // how many shots this ship provides
|
|
Ship.hitPoints = 1 // how many hits this ship can take before sinking
|
|
Ship.make = function(name, shots=1, size=2)
|
|
result = new Ship
|
|
result.name = name
|
|
result.shots = shots
|
|
result.positions = []
|
|
result.hitPoints = size
|
|
return result
|
|
end function
|
|
|
|
Board = {}
|
|
Board.ships = null // list of Ship instances
|
|
Board.splash = null // 2D array of: none, or turn on which it was hit
|
|
Board.shipAt = function(xy)
|
|
for ship in self.ships
|
|
if ship.positions.contains(xy) then return ship
|
|
end for
|
|
end function
|
|
Board.isEmptySpot = function(xy)
|
|
return 0 < xy[0] < 11 and 0 < xy[1] < 11 and self.shipAt(xy) == null
|
|
end function
|
|
Board.make = function
|
|
result = new Board
|
|
result.ships = []
|
|
result.splash = list.init2d(11, 11)
|
|
return result
|
|
end function
|
|
Board.totalShots = function
|
|
sum = 0
|
|
for ship in self.ships
|
|
sum += ship.shots
|
|
end for
|
|
return sum
|
|
end function
|
|
|
|
computerBoard = Board.make
|
|
playerBoard = Board.make
|
|
|
|
directions = [[-1,-1], [-1,0], [-1,1], [0,-1], [0,1], [1,-1], [1,0], [1,1]]
|
|
|
|
randomPosition = function
|
|
return [1 + floor(rnd*10), 1 + floor(rnd*10)]
|
|
end function
|
|
|
|
inputCoords = function(prompt="?")
|
|
while true
|
|
inp = input(prompt + "? ").replace(",", " ").replace(" ", " ").split
|
|
if inp.len != 2 then
|
|
print "Please enter coordinates such as: 5,3"
|
|
else
|
|
x = inp[0].val
|
|
y = inp[1].val
|
|
if 0 < x < 11 and 0 < y < 11 then return [x,y]
|
|
print "X and Y coordinates must be in the range 1-10."
|
|
end if
|
|
end while
|
|
end function
|
|
|
|
inBounds = function(pos)
|
|
return 0 < pos[0] < 11 and 0 < pos[1] < 11
|
|
end function
|
|
|
|
placeComputerShips = function
|
|
placeOne = function(ship)
|
|
while true
|
|
pos = randomPosition
|
|
dir = directions.any
|
|
ok = true
|
|
p = pos[:]
|
|
for i in range(0, ship.hitPoints - 1)
|
|
if not computerBoard.isEmptySpot(p) then ok = false
|
|
p.add dir
|
|
end for
|
|
if ok then break
|
|
end while
|
|
for i in range(0, ship.hitPoints - 1)
|
|
ship.positions.push pos[:]
|
|
pos.add dir
|
|
end for
|
|
computerBoard.ships.push ship
|
|
end function
|
|
placeOne Ship.make("Battleship", 3, 5)
|
|
placeOne Ship.make("Cruiser", 2, 3)
|
|
placeOne Ship.make("Destroyer<A>", 1, 2)
|
|
placeOne Ship.make("Destroyer<B>", 1, 2)
|
|
end function
|
|
|
|
placePlayerShips = function
|
|
placeOne = function(ship)
|
|
print ship.name
|
|
playerBoard.ships.push ship
|
|
// Note: like the original BASIC program, we do no validation on
|
|
// the input other than making sure it is in range. So you can
|
|
// have a ship scattered all over the map, have ships overlap, etc.
|
|
for i in range(1, ship.hitPoints)
|
|
ship.positions.push inputCoords
|
|
end for
|
|
end function
|
|
print "Enter coordinates for..."
|
|
placeOne Ship.make("Battleship", 3, 5)
|
|
placeOne Ship.make("Cruiser", 2, 3)
|
|
placeOne Ship.make("Destroyer<A>", 1, 2)
|
|
placeOne Ship.make("Destroyer<B>", 1, 2)
|
|
end function
|
|
|
|
printComputerShips = function
|
|
for ship in computerBoard.ships
|
|
print ship.name
|
|
for pos in ship.positions
|
|
print " " + pos.join(" ")
|
|
end for
|
|
end for
|
|
end function
|
|
|
|
doPlayerTurn = function(turnNum = 1)
|
|
shots = playerBoard.totalShots
|
|
print "You have " + shots + " shot" + "s"*(shots!=1) + "."
|
|
if shots < 1 then
|
|
print "I have won."
|
|
exit
|
|
end if
|
|
hits = []
|
|
for i in range(1, shots)
|
|
while true
|
|
pos = inputCoords
|
|
prevHitOnTurn = computerBoard.splash[pos[0]][pos[1]]
|
|
if prevHitOnTurn == null then break
|
|
print "You shot there before on turn " + prevHitOnTurn
|
|
end while
|
|
computerBoard.splash[pos[0]][pos[1]] = turnNum
|
|
hit = computerBoard.shipAt(pos)
|
|
if hit then hits.push hit
|
|
end for
|
|
for hit in hits
|
|
print "You hit my " + hit.name + "."
|
|
hit.hitPoints -= 1
|
|
if hit.hitPoints == 0 then
|
|
print "...and sank it!" // (not in original BASIC program)
|
|
computerBoard.ships.removeVal hit
|
|
end if
|
|
end for
|
|
end function
|
|
|
|
pickShot = function
|
|
// Pick a spot for the computer to shoot at. We'll do this by
|
|
// computing a "neighbor score" for each spot: the number of
|
|
// neighboring spots that (1) we have previously hit, and (2)
|
|
// contain an enemy ship. Then we'll pick randomly from the
|
|
// set of spots with the highest neighbor score.
|
|
bestScore = 0
|
|
spots = []
|
|
for i in range(1,10)
|
|
for j in range(1,10)
|
|
pos = [i,j]
|
|
if playerBoard.splash[pos[0]][pos[1]] then continue
|
|
score = 0
|
|
for dir in directions
|
|
n = pos.plus(dir)
|
|
if inBounds(n) and playerBoard.splash[n[0]][n[1]] and playerBoard.shipAt(n) then
|
|
score += 1
|
|
end if
|
|
end for
|
|
if score > bestScore then
|
|
bestScore = score
|
|
spots = [pos]
|
|
else if score == bestScore then
|
|
spots.push pos
|
|
end if
|
|
end for
|
|
end for
|
|
return spots.any
|
|
end function
|
|
|
|
doComputerTurn = function(turnNum = 1)
|
|
shots = computerBoard.totalShots
|
|
print "I have " + shots + " shot" + "s"*(shots!=1) + "."
|
|
if shots < 1 then
|
|
print "You have won."
|
|
exit
|
|
end if
|
|
hits = []
|
|
for i in range(1, shots)
|
|
pos = pickShot
|
|
playerBoard.splash[pos[0]][pos[1]] = turnNum
|
|
hit = playerBoard.shipAt(pos)
|
|
if hit then hits.push hit
|
|
if seeComputerShots then print " " + pos.join(" ")
|
|
end for
|
|
for hit in hits
|
|
print "I hit your " + hit.name + "."
|
|
hit.hitPoints -= 1
|
|
if hit.hitPoints == 0 then
|
|
print "...and sank it!" // (not in original BASIC program)
|
|
playerBoard.ships.removeVal hit
|
|
end if
|
|
end for
|
|
end function
|
|
|
|
// Main Program
|
|
|
|
placeComputerShips
|
|
placePlayerShips
|
|
while true
|
|
yn = input("Do you want to start? ").lower
|
|
if yn == "where are your ships?" then
|
|
printComputerShips
|
|
else if yn and (yn[0] == "y" or yn[0] == "n") then
|
|
break
|
|
end if
|
|
end while
|
|
startWithPlayer = (yn[0] == "y")
|
|
while true
|
|
yn = input("Do you want to see my shots? ").lower
|
|
if yn and (yn[0] == "y" or yn[0] == "n") then break
|
|
end while
|
|
seeComputerShots = (yn[0] == "y")
|
|
|
|
turnNumber = 1
|
|
while true
|
|
print
|
|
print "Turn " + turnNumber
|
|
if startWithPlayer then
|
|
doPlayerTurn turnNumber
|
|
doComputerTurn turnNumber
|
|
else
|
|
doComputerTurn turnNumber
|
|
doPlayerTurn turnNumber
|
|
end if
|
|
turnNumber += 1
|
|
end while |