mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-31 07:02:27 -08:00
Added logic to generate valid board, refactored generation logic and cleaned up overall structure
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 225,
|
||||
"execution_count": 715,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -33,15 +33,45 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 226,
|
||||
"execution_count": 716,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"random.seed()\n",
|
||||
"\n",
|
||||
"BOARD_WIDTH = 10\n",
|
||||
"BOARD_HEIGHT = 10\n",
|
||||
"\n",
|
||||
"SHIPS = [ (\"BATTLESHIP\", 5),\n",
|
||||
" (\"CRUISER\", 3),\n",
|
||||
" (\"DESTROYER<A>\", 2),\n",
|
||||
" (\"DESTROYER<B>\", 2) ]\n",
|
||||
" \n",
|
||||
"VALID_MOVES = [[-1, 0],\n",
|
||||
" [-1, 1],\n",
|
||||
" [ 0, 1],\n",
|
||||
" [ 1, 1],\n",
|
||||
" [ 1, 0],\n",
|
||||
" [ 1,-1],\n",
|
||||
" [ 0,-1],\n",
|
||||
" [-1,-1]]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 717,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# random number functions\n",
|
||||
"#\n",
|
||||
"# seed the random number generator\n",
|
||||
"random.seed()\n",
|
||||
"\n",
|
||||
"# random_x_y\n",
|
||||
"#\n",
|
||||
"# generate a valid x,y coordinate on the board\n",
|
||||
"# returns: x,y\n",
|
||||
"# x: integer between 1 and BOARD_HEIGHT\n",
|
||||
"# y: integer between 1 and BOARD WIDTH\n",
|
||||
"def random_x_y():\n",
|
||||
" x = random.randrange(1,BOARD_WIDTH+1)\n",
|
||||
" y = random.randrange(1,BOARD_HEIGHT+1)\n",
|
||||
@@ -50,14 +80,14 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 227,
|
||||
"execution_count": 718,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"7 2\n"
|
||||
"8 4\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -68,183 +98,109 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 228,
|
||||
"execution_count": 719,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def random_direction(valid_directions):\n",
|
||||
" idx = random.randrange(len(valid_directions))\n",
|
||||
" return valid_directions[idx]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 229,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(random_direction([0,1,2]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 230,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"SHIPS = [ (\"BATTLESHIP\", 5),\n",
|
||||
" (\"CRUISER\", 3),\n",
|
||||
" (\"DESTROYER<A>\", 2),\n",
|
||||
" (\"DESTROYER<B>\", 2) ]\n",
|
||||
"# TODO: add an optional starting coordinate for testing\n",
|
||||
"# purposes\n",
|
||||
"def generate_ship_coordinates(ship):\n",
|
||||
" \n",
|
||||
" # randomly generate starting x,y coordinates\n",
|
||||
" start_x, start_y = random_x_y()\n",
|
||||
"\n",
|
||||
"# given a coordinate (x,y) and a ship type,\n",
|
||||
"# determine which directions from the coordinate \n",
|
||||
"# a ship could be placed. Directions are numbered\n",
|
||||
"# starting at 0 for up, 1 for up/right, 2 for right, \n",
|
||||
"# etc., clockwise from zero (12 o'clock position)\n",
|
||||
"# returns a vector of direction numbers where\n",
|
||||
"# a ship can be placed, starting at one end of the\n",
|
||||
"# ship to its length\n",
|
||||
"def get_possible_directions(x,y,ship):\n",
|
||||
" # using starting coordinates and the ship type,\n",
|
||||
" # generate a vector of possible directions the ship \n",
|
||||
" # could be placed. directions are numbered 0-7 along\n",
|
||||
" # points of the compass (N, NE, E, SE, S, SW, W, NW)\n",
|
||||
" # clockwise. a vector of valid directions where the\n",
|
||||
" # ship does not go off the board is determined\n",
|
||||
" ship_len = SHIPS[ship][1] - 1\n",
|
||||
" dirs = [False for x in range(8)]\n",
|
||||
" dirs[0] = (x - ship_len) >=1\n",
|
||||
" dirs[2] = (y + ship_len) <= BOARD_WIDTH\n",
|
||||
" dirs[0] = (start_x - ship_len) >=1\n",
|
||||
" dirs[2] = (start_y + ship_len) <= BOARD_WIDTH\n",
|
||||
" dirs[1] = dirs[0] and dirs[2]\n",
|
||||
" dirs[4] = (x + ship_len) <= BOARD_HEIGHT\n",
|
||||
" dirs[4] = (start_x + ship_len) <= BOARD_HEIGHT\n",
|
||||
" dirs[3] = dirs[2] and dirs[4]\n",
|
||||
" dirs[6] = (y - ship_len) >= 1\n",
|
||||
" dirs[6] = (start_y - ship_len) >= 1\n",
|
||||
" dirs[5] = dirs[4] and dirs[6]\n",
|
||||
" dirs[7] = dirs[6] and dirs[0]\n",
|
||||
" directions = [p for p in range(len(dirs)) if dirs[p]]\n",
|
||||
"\n",
|
||||
" return [x for x in range(len(dirs)) if dirs[x]]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 231,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Boundary Conditions\n( 5, 5): [0, 1, 2, 3, 4, 5, 6, 7]\n( 1, 1): [2, 3, 4]\n( 1,10): [4, 5, 6]\n(10,10): [0, 6, 7]\n(10, 1): [0, 1, 2]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\"Boundary Conditions\")\n",
|
||||
"print(\"( 5, 5):\",get_possible_directions(5,5,0))\n",
|
||||
"print(\"( 1, 1):\",get_possible_directions(1,1,0))\n",
|
||||
"print(\"( 1,10):\",get_possible_directions(1,10,0))\n",
|
||||
"print(\"(10,10):\",get_possible_directions(10,10,0))\n",
|
||||
"print(\"(10, 1):\",get_possible_directions(10,1,0))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 232,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"VALID_MOVES = [[-1, 0],\n",
|
||||
" [-1, 1],\n",
|
||||
" [ 0, 1],\n",
|
||||
" [ 1, 1],\n",
|
||||
" [ 1, 0],\n",
|
||||
" [ 1,-1],\n",
|
||||
" [ 0,-1],\n",
|
||||
" [-1,-1]]\n",
|
||||
" # using the vector of valid directions, pick a\n",
|
||||
" # random direction to place the ship\n",
|
||||
" dir_idx = random.randrange(len(directions))\n",
|
||||
" direction = directions[dir_idx]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def generate_ship_coordinates(x_start,y_start,direction,ship):\n",
|
||||
" # using the starting x,y, direction and ship\n",
|
||||
" # type, return the coordinates of each point \n",
|
||||
" # of the ship. VALID_MOVES is a staic array\n",
|
||||
" # of coordinate offsets to walk from starting\n",
|
||||
" # coordinate to the end coordinate in the \n",
|
||||
" # chosen direction\n",
|
||||
" ship_len = SHIPS[ship][1] - 1\n",
|
||||
" d_x = VALID_MOVES[direction][0]\n",
|
||||
" d_y = VALID_MOVES[direction][1]\n",
|
||||
"\n",
|
||||
" coords = [(x_start,y_start)]\n",
|
||||
" x_coord = x_start\n",
|
||||
" y_coord = y_start\n",
|
||||
" coords = [(start_x,start_y)]\n",
|
||||
" x_coord = start_x\n",
|
||||
" y_coord = start_y\n",
|
||||
" for i in range(ship_len):\n",
|
||||
" x_coord = x_coord + d_x\n",
|
||||
" y_coord = y_coord + d_y\n",
|
||||
" coords.append((x_coord,y_coord))\n",
|
||||
" return coords"
|
||||
" return coords\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 233,
|
||||
"execution_count": 720,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"('BATTLESHIP', 5) 2 2 4 [(2, 2), (3, 2), (4, 2), (5, 2), (6, 2)]\n",
|
||||
"('CRUISER', 3) 6 7 3 [(6, 7), (7, 8), (8, 9)]\n",
|
||||
"('DESTROYER<A>', 2) 1 1 3 [(1, 1), (2, 2)]\n",
|
||||
"('DESTROYER<B>', 2) 8 3 6 [(8, 3), (8, 2)]\n"
|
||||
"BATTLESHIP 5 [(9, 2), (8, 3), (7, 4), (6, 5), (5, 6)]\nCRUISER 3 [(3, 8), (2, 9), (1, 10)]\nDESTROYER<A> 2 [(3, 5), (3, 6)]\nDESTROYER<B> 2 [(6, 5), (7, 4)]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"for ship in range(len(SHIPS)):\n",
|
||||
" x,y = random_x_y()\n",
|
||||
" directions = get_possible_directions(x,y,ship)\n",
|
||||
" direction = random_direction(directions)\n",
|
||||
" coords = generate_ship_coordinates(x,y,direction,ship)\n",
|
||||
" print(SHIPS[ship],x,y,direction,coords)"
|
||||
" coords = generate_ship_coordinates(ship)\n",
|
||||
" print(f'{SHIPS[ship][0]:15}',f'{SHIPS[ship][1]:2}',coords)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 234,
|
||||
"execution_count": 721,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"computer_board = [ [ -1 for y in range(BOARD_WIDTH)] \n",
|
||||
" for x in range(BOARD_HEIGHT)]\n",
|
||||
"player_board = [ [ -1 for y in range(BOARD_WIDTH)] \n",
|
||||
" for x in range(BOARD_HEIGHT)]"
|
||||
"def create_blank_board():\n",
|
||||
" return [ [ None for y in range(BOARD_WIDTH)] \n",
|
||||
" for x in range(BOARD_HEIGHT)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 235,
|
||||
"execution_count": 722,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
" 1 2 3 4 5 6 7 8 9 10\n",
|
||||
" 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 4 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 5 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 6 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 7 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 8 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
"10 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n"
|
||||
" 1 2 3 4 5 6 7 8 9 10\n 1 \n 2 \n 3 \n 4 \n 5 \n 6 \n 7 \n 8 \n 9 \n10 \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def print_board(board):\n",
|
||||
"\n",
|
||||
" # print board header (column numbers)\n",
|
||||
" print(' ',end='')\n",
|
||||
" for z in range(BOARD_WIDTH):\n",
|
||||
" print(f'{z+1:3}',end='')\n",
|
||||
@@ -253,62 +209,122 @@
|
||||
" for x in range(len(board)):\n",
|
||||
" print(f'{x+1:2}',end='')\n",
|
||||
" for y in range(len(board[x])):\n",
|
||||
" print(f\"{board[x][y]:3}\",end='')\n",
|
||||
" if(board[x][y] is None):\n",
|
||||
" print(f\"{' ':3}\",end='')\n",
|
||||
" else:\n",
|
||||
" print(f\"{board[x][y]:3}\",end='')\n",
|
||||
" print('')\n",
|
||||
"\n",
|
||||
"computer_board = create_blank_board()\n",
|
||||
"print_board(computer_board)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 236,
|
||||
"execution_count": 723,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def place_ship(board,coords,ship):\n",
|
||||
" for coord in coords:\n",
|
||||
" print(\"--->\",coord)\n",
|
||||
" board[coord[0]-1][coord[1]-1] = 0"
|
||||
" board[coord[0]-1][coord[1]-1] = ship"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 237,
|
||||
"execution_count": 724,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"[(7, 5), (6, 4), (5, 3), (4, 2), (3, 1)]\n",
|
||||
"---> (7, 5)\n",
|
||||
"---> (6, 4)\n",
|
||||
"---> (5, 3)\n",
|
||||
"---> (4, 2)\n",
|
||||
"---> (3, 1)\n",
|
||||
"DESTROYER<B> 2 [(1, 7), (2, 6), (3, 5), (4, 4), (5, 3)]\n",
|
||||
" 1 2 3 4 5 6 7 8 9 10\n",
|
||||
" 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 3 0 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 4 -1 0 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 5 -1 -1 0 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 6 -1 -1 -1 0 -1 -1 -1 -1 -1 -1\n",
|
||||
" 7 -1 -1 -1 -1 0 -1 -1 -1 -1 -1\n",
|
||||
" 8 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
" 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
|
||||
"10 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n"
|
||||
" 1 0 \n",
|
||||
" 2 0 \n",
|
||||
" 3 0 \n",
|
||||
" 4 0 \n",
|
||||
" 5 0 \n",
|
||||
" 6 \n",
|
||||
" 7 \n",
|
||||
" 8 \n",
|
||||
" 9 \n",
|
||||
"10 \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x,y = random_x_y()\n",
|
||||
"ship = 0\n",
|
||||
"directions = get_possible_directions(x,y,ship)\n",
|
||||
"direction = random_direction(directions)\n",
|
||||
"coords = generate_ship_coordinates(x,y,direction,ship)\n",
|
||||
"print(coords)\n",
|
||||
"place_ship(computer_board,coords,0)\n",
|
||||
"print_board(computer_board)"
|
||||
"# test place_ship\n",
|
||||
"board = create_blank_board()\n",
|
||||
"coords = generate_ship_coordinates(0)\n",
|
||||
"print(f'{SHIPS[ship][0]:15}',f'{SHIPS[ship][1]:2}',coords)\n",
|
||||
"place_ship(board,coords,0)\n",
|
||||
"print_board(board)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 725,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
" 1 2 3 4 5 6 7 8 9 10\n 1 1 0 \n 2 1 0 \n 3 1 0 \n 4 0 \n 5 2 0 \n 6 2 \n 7 3 3 \n 8 \n 9 \n10 \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# NOTE: A little quirk that exists here and in the orginal\n",
|
||||
"# game: Ships are allowed to cross each other!\n",
|
||||
"# For example: 2 destroyers, length 2, one at\n",
|
||||
"# [(1,1),(2,2)] and other at [(2,1),(1,2)]\n",
|
||||
"\n",
|
||||
"def generate_board():\n",
|
||||
" board = create_blank_board()\n",
|
||||
"\n",
|
||||
" for ship in range(len(SHIPS)):\n",
|
||||
" placed = False\n",
|
||||
" coords = []\n",
|
||||
" while not placed:\n",
|
||||
" coords = generate_ship_coordinates(ship)\n",
|
||||
" clear = True\n",
|
||||
" for coord in coords:\n",
|
||||
" if board[coord[0]-1][coord[1]-1] is not None:\n",
|
||||
" clear = False\n",
|
||||
" break\n",
|
||||
" if clear:\n",
|
||||
" placed = True\n",
|
||||
" place_ship(board,coords,ship)\n",
|
||||
" return board\n",
|
||||
"\n",
|
||||
"print_board(generate_board())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 726,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"[(4, 4), (2, 8), (10, 6), (2, 4), (10, 7)]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def generate_shots(number):\n",
|
||||
" shots = []\n",
|
||||
" for i in range(number):\n",
|
||||
" shots.append(random_x_y())\n",
|
||||
" return shots\n",
|
||||
"\n",
|
||||
"shots = generate_shots(5)\n",
|
||||
"print(shots)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user