From 77c109a9a144a28c903b5f76f2561403ca55521b Mon Sep 17 00:00:00 2001 From: Jeremy Duncan Date: Wed, 22 Oct 2025 13:26:46 -0400 Subject: [PATCH 1/6] codex: modulized js code and updated styling --- battleship.css | 1134 ++++++++++++++++++------------------------ battleship.js | 814 ++---------------------------- index.html | 11 +- src/ai-controller.js | 59 +++ src/board.js | 117 +++++ src/constants.js | 18 + src/game.js | 228 +++++++++ src/ship.js | 24 + src/ui-controller.js | 89 ++++ 9 files changed, 1076 insertions(+), 1418 deletions(-) create mode 100644 src/ai-controller.js create mode 100644 src/board.js create mode 100644 src/constants.js create mode 100644 src/game.js create mode 100644 src/ship.js create mode 100644 src/ui-controller.js diff --git a/battleship.css b/battleship.css index 7e6256e..567c159 100644 --- a/battleship.css +++ b/battleship.css @@ -1,765 +1,623 @@ -body { - color: rgb(112, 134, 190); - background-color: rgb(61, 63, 70); - text-shadow: 2px 1px 1px rgb(0, 0, 0); +:root { + --surface-dark: rgba(6, 15, 36, 0.85); + --surface-card: rgba(13, 26, 53, 0.9); + --surface-panel: rgba(20, 33, 62, 0.8); + --accent-primary: #62f6ff; + --accent-secondary: #ff8ba7; + --accent-tertiary: #8c5bff; + --text-strong: #f5f7ff; + --text-body: #c8cff7; + --text-muted: #7b84b8; + --grid-line: rgba(98, 246, 255, 0.18); + --cell-size: 45px; + --border-radius: 18px; + font-family: "Space Grotesk", "Segoe UI", sans-serif; +} + +*, +*::before, +*::after { + box-sizing: border-box; } -h1 { +body { margin: 0; -} - -.container { + min-height: 100vh; display: flex; - flex-direction: column; - justify-content: space-between; - gap: 10px; - min-height: 900px; - width: 100%; -} - -table { - margin: 0 auto; justify-content: center; - text-align: center; align-items: center; - align-content: center; - align-self: center; + padding: 16px 0; + overflow-x: hidden; + background: radial-gradient( + 125% 125% at 50% 0%, + #283773 0%, + #0c1226 55%, + #05070f 100% + ); + color: var(--text-body); } -header { - text-align: center; +::selection { + background: rgba(98, 246, 255, 0.3); + color: var(--text-strong); } -.message { - text-align: center; +a { + color: var(--accent-primary); + text-decoration: none; } -.game-boards { - justify-content: center; - align-items: center; - gap: 50px; +a:hover { + text-decoration: underline; } -.selection { +.container { + width: min(1080px, 94vw); display: flex; flex-direction: column; - text-align: center; - gap: 5px; -} - -.ship-selection1 { - display: flex; - gap: 4px; -} - -.ship-selection2 { - display: flex; - gap: 4px; -} - -.vertical-selection { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(0, 0, 0); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black + gap: 20px; + padding: 24px 0 28px; } -.vertical-selection:hover { - background-color: rgb(6, 94, 121); +#remove-on-start { + height: 100%; } -.vertical-selection:active { - background-color: rgb(19, 17, 17); -} - -.horizontal-selection { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(2, 2, 2); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black +header { + text-align: center; + padding: 26px 24px; + border-radius: var(--border-radius); + background: linear-gradient( + 135deg, + rgba(98, 246, 255, 0.16), + rgba(140, 91, 255, 0.12) + ), + var(--surface-panel); + backdrop-filter: blur(12px); + box-shadow: 0 32px 60px rgba(0, 0, 0, 0.35); +} + +header h1 { + margin: 0; + font-size: clamp(2.2rem, 3vw, 2.7rem); + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--text-strong); } -.horizontal-selection:hover { - background-color: rgb(6, 94, 121); +header { + font-size: 1rem; + letter-spacing: 0.04em; } -.horizontal-selection:active { - background-color: rgb(19, 17, 17); +.container-main { + display: grid; + gap: 18px; + grid-template-columns: 320px 1fr; + align-items: start; + justify-content: center; } -.battleship { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(4, 4, 4); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black -} - -.destroyer { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(4, 4, 4); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black +.container-main.battle-mode { + grid-template-columns: 1fr; + justify-items: center; } -.destroyer:hover { - background-color: rgb(6, 94, 121); +.container-main.battle-mode .message { + max-width: 560px; + justify-self: center; } -.destroyer:active { - background-color: rgb(19, 17, 17); +.container-main.battle-mode .game-boards { + margin: 0 auto; + justify-content: center; } -.frigate { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(4, 4, 4); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black +.message { + min-height: 40px; + padding: 12px 16px; + border-radius: var(--border-radius); + background: var(--surface-card); + box-shadow: 0 22px 45px rgba(0, 0, 0, 0.25); + display: flex; + align-items: center; + justify-content: center; + font-size: 0.98rem; + letter-spacing: 0.02em; } -.frigate:hover { - background-color: rgb(6, 94, 121); +.message { + grid-column: 1 / -1; } -.frigate:active { - background-color: rgb(19, 17, 17); +.selection { + display: grid; + gap: 12px; + padding: 18px; + border-radius: var(--border-radius); + background: linear-gradient( + 155deg, + rgba(255, 139, 167, 0.22), + rgba(98, 246, 255, 0.08) + ), + var(--surface-card); + backdrop-filter: blur(10px); + box-shadow: 0 24px 45px rgba(0, 0, 0, 0.3); +} + +.selection strong { + color: var(--text-strong); + font-weight: 600; + letter-spacing: 0.04em; +} + +.selection > div:first-child { + text-transform: uppercase; + font-size: 0.95rem; + color: var(--text-muted); + letter-spacing: 0.16em; +} + +.ship-selection1, +.ship-selection2 { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 10px; } -.patrol-coastal { - margin: auto; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(4, 4, 4); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: grey; - box-shadow: 2px 2px 2px 2px black +.vertical-selection, +.horizontal-selection, +.battleship, +.destroyer, +.frigate, +.patrol-coastal, +.start-game { + cursor: pointer; + padding: 14px 16px; + border-radius: 14px; + border: 1px solid rgba(98, 246, 255, 0.35); + background: rgba(13, 26, 53, 0.6); + color: var(--text-strong); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + transition: transform 0.18s ease, box-shadow 0.18s ease, + border-color 0.18s ease, background 0.18s ease; + text-shadow: 0 0 14px rgba(98, 246, 255, 0.35); +} + +.vertical-selection:hover, +.horizontal-selection:hover, +.battleship:hover, +.destroyer:hover, +.frigate:hover, +.patrol-coastal:hover, +.start-game:hover { + transform: translateY(-2px) scale(1.015); + box-shadow: 0 12px 28px rgba(98, 246, 255, 0.25); + border-color: rgba(98, 246, 255, 0.6); } -.patrol-coastal:hover { - background-color: rgb(6, 94, 121); +.vertical-selection:active, +.horizontal-selection:active, +.battleship:active, +.destroyer:active, +.frigate:active, +.patrol-coastal:active, +.start-game:active { + transform: translateY(0); } -.patrol-coastal:active { - background-color: rgb(19, 17, 17); +.start-game { + margin-top: 10px; + background: linear-gradient( + 135deg, + rgba(98, 246, 255, 0.3), + rgba(140, 91, 255, 0.25) + ), + rgba(12, 24, 49, 0.75); + border-color: rgba(255, 255, 255, 0.35); + box-shadow: 0 20px 40px rgba(140, 91, 255, 0.35); } -.start-game { - margin: auto; - margin-top: 20px; - margin-bottom: 20px; - padding-top: 10px; - align-items: center; - justify-content: center; - width: 30%; - height: 25px; - color: white; - text-shadow: 2px 1px 1px rgb(4, 4, 4); - font-weight: bold; - border: 3px solid black; - border-radius: 10px; - background-color: rgb(218, 12, 12); - box-shadow: 2px 2px 2px 2px black +.start-game:hover { + box-shadow: 0 28px 48px rgba(140, 91, 255, 0.4); } .game-boards { display: flex; - text-align: center; -} - -.square { - text-align: center; - background-color: black; - border: 0px solid rgb(103, 1, 1); - padding: 0px; - border-radius: 3px; + gap: 18px; + justify-content: center; + align-items: flex-start; + flex-wrap: nowrap; + position: relative; } -td { - padding: 0px; - width: 50px; - height: 50px; +.player-board, +.computer-board { + flex: 0 0 auto; + padding: 14px 14px 16px; + border-radius: var(--border-radius); + background: linear-gradient( + 155deg, + rgba(98, 246, 255, 0.15), + rgba(13, 26, 53, 0.8) + ), + var(--surface-dark); + backdrop-filter: blur(8px); + box-shadow: 0 28px 48px rgba(0, 0, 0, 0.45); + position: relative; + overflow: hidden; +} + +.player-board::before, +.computer-board::before { + content: ""; + position: absolute; + inset: -40% 40% 35% -35%; + background: radial-gradient( + circle at center, + rgba(98, 246, 255, 0.32), + transparent 60% + ); + opacity: 0.3; + pointer-events: none; } .label { - text-align: center; - text-shadow: 2px 2px 2px black; - width: 5px; - padding: 0px; - margin: 0px; - width: 0px; - height: 0px; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 6px 14px; + margin: 0 auto 12px; + border-radius: 32px; + background: rgba(98, 246, 255, 0.16); + color: var(--accent-primary); + text-transform: uppercase; + font-size: 0.8rem; + letter-spacing: 0.18em; + position: relative; + z-index: 1; } -.player-board { - border: 2px solid rgb(0, 0, 0); - color: rgb(151, 182, 219); - font-weight: bold; - font-size: 15px; - background-color: rgb(67, 96, 60); - border-radius: 5px; - box-shadow: 4px 4px 4px 4px black; +table { + margin: 0 auto; + width: calc(var(--cell-size) * 10 + 9 * 5px); + height: calc(var(--cell-size) * 10 + 9 * 5px); + border-collapse: separate; + border-spacing: 5px; + position: relative; + z-index: 1; } -.computer-board { - border: 2px solid rgb(0, 0, 0); - color: rgb(151, 182, 219); - font-weight: bold; - font-size: 15px; - background-color: rgb(84, 45, 45); - border-radius: 5px; - box-shadow: 4px 4px 4px 4px black +td { + padding: 0; } -footer { - display: flex; - justify-self: space-between; - justify-content: space-evenly; +.square { + width: var(--cell-size); + height: var(--cell-size); + border-radius: 16px; + background: linear-gradient(145deg, rgba(18, 32, 61, 0.95), rgba(9, 14, 27, 0.9)); + border: 1px solid rgba(98, 246, 255, 0.12); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.02), + 0 12px 28px rgba(0, 0, 0, 0.4); + position: relative; + overflow: hidden; + transition: transform 0.15s ease, box-shadow 0.15s ease, + border-color 0.15s ease; } -.copyright { - display: flex; +.square:hover { + transform: translateY(-2px); + box-shadow: 0 18px 32px rgba(0, 0, 0, 0.45); + border-color: rgba(98, 246, 255, 0.3); } -.info-link { - display: flex; +.square span { + display: none; } -.ship { - background-color: white; - width: 50px; - height: 50px; +.ship-select, +.ship-hit, +.ship-miss { + width: 100%; + height: 100%; + position: relative; + border-radius: 14px; + display: block; +} + +.player-board .ship-select { + background: linear-gradient( + 145deg, + rgba(255, 139, 167, 0.4), + rgba(140, 91, 255, 0.35) + ), + rgba(19, 30, 59, 0.9); + border: 1px solid rgba(255, 139, 167, 0.4); + box-shadow: 0 0 18px rgba(140, 91, 255, 0.35); +} + +.player-board .ship-select::before, +.player-board .ship-select::after { + content: ""; + position: absolute; + inset: 12% 18%; + border-radius: 10px; + background: linear-gradient( + 160deg, + rgba(255, 255, 255, 0.25), + rgba(255, 139, 167, 0.25) + ); + box-shadow: inset 0 0 12px rgba(0, 0, 0, 0.35); +} + +.player-board .ship-select::after { + inset: 34% 32%; + border-radius: 8px; + background: linear-gradient( + 160deg, + rgba(255, 139, 167, 0.55), + rgba(255, 255, 255, 0.45) + ); + opacity: 0.65; +} + +.computer-board .ship-select { + background: linear-gradient( + 145deg, + rgba(98, 246, 255, 0.45), + rgba(5, 120, 176, 0.5) + ), + rgba(9, 29, 56, 0.85); + border: 1px solid rgba(98, 246, 255, 0.4); + box-shadow: 0 0 18px rgba(98, 246, 255, 0.35); +} + +.computer-board .ship-select::before, +.computer-board .ship-select::after { + content: ""; + position: absolute; + inset: 14% 20%; + border-radius: 10px; + background: linear-gradient( + 155deg, + rgba(98, 246, 255, 0.45), + rgba(16, 162, 222, 0.6) + ); + box-shadow: inset 0 0 12px rgba(0, 0, 0, 0.35); } -.ship-select { - background-color: rgba(248, 248, 248, 0); - width: 50px; - height: 50px; - border-radius: 15px; - content: url(./images/pin.svg); +.computer-board .ship-select::after { + inset: 36% 34%; + border-radius: 8px; + background: linear-gradient( + 155deg, + rgba(255, 255, 255, 0.45), + rgba(98, 246, 255, 0.6) + ); + opacity: 0.6; } .ship-hit { - width: 50px; - height: 50px; - background-color: rgba(255, 0, 0, 0.268); - content: url(./images/explosion.svg); - border-radius: 15px; - + background: radial-gradient( + circle at center, + rgba(255, 112, 112, 0.6), + rgba(120, 18, 18, 0.65) 55%, + transparent 70% + ), + rgba(37, 15, 25, 0.85); + border: 1px solid rgba(255, 104, 147, 0.4); + box-shadow: 0 0 22px rgba(255, 112, 112, 0.45); + animation: blast 0.4s ease-out; +} + +.ship-hit::after { + content: ""; + position: absolute; + inset: 18%; + background: url("./images/explosion.svg") center/70% no-repeat; + filter: drop-shadow(0 0 8px rgba(255, 164, 102, 0.8)); } .ship-miss { - width: 50px; - height: 50px; - background-color: rgba(115, 187, 236, 0.112); - content: url(./images/splash-1.svg); - border-radius: 15px; -} - -.square:hover { - background-color: white; + background: radial-gradient( + circle at center, + rgba(98, 246, 255, 0.45) 0%, + rgba(10, 61, 104, 0.65) 55%, + transparent 75% + ), + rgba(9, 25, 45, 0.78); + border: 1px solid rgba(98, 246, 255, 0.35); + box-shadow: 0 0 18px rgba(98, 246, 255, 0.32); + animation: ripple 0.55s ease-out; +} + +.ship-miss::after { + content: ""; + position: absolute; + inset: 20%; + background: url("./images/splash-1.svg") center/65% no-repeat; + filter: drop-shadow(0 0 6px rgba(98, 246, 255, 0.45)); +} + +#announce { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + align-content: center; + flex-wrap: nowrap; + flex-direction: column; } -.start-game:hover { - background-color: rgb(6, 94, 121); +.announcement { + position: relative; + display: inline-flex; + flex-direction: column; + align-items: center; + z-index: 1000; + justify-content: center; + gap: 12px; + padding: 32px 42px; + border-radius: var(--border-radius); + font-size: 2.4rem; + letter-spacing: 0.1em; + background: linear-gradient( + 145deg, + rgba(255, 139, 167, 0.28), + rgba(98, 246, 255, 0.22) + ), + rgba(13, 26, 53, 0.92); + color: var(--text-strong); + text-shadow: 0 18px 24px rgba(0, 0, 0, 0.35); + box-shadow: 0 28px 48px rgba(0, 0, 0, 0.45); + animation: pulse 0.8s ease-in-out infinite alternate; + pointer-events: auto; } -.start-game:active { - background-color: rgb(19, 17, 17); +.retry { + margin-top: 14px; + padding: 10px 22px; + border-radius: 999px; + z-index: 1001; + background: rgba(98, 246, 255, 0.18); + border: 1px solid rgba(98, 246, 255, 0.4); + color: var(--accent-primary); + font-size: 0.9rem; + letter-spacing: 0.18em; + text-transform: uppercase; + cursor: pointer; + transition: transform 0.18s ease, box-shadow 0.18s ease; + pointer-events: auto; } -.battleship:hover { - background-color: rgb(6, 94, 121); +.retry:hover { + transform: translateY(-2px); + box-shadow: 0 14px 26px rgba(98, 246, 255, 0.28); } -.battleship:active { - background-color: rgb(19, 17, 17); +.retry:active { + transform: translateY(0); } - -.announcement { - position:absolute; - z-index: 1; - margin-top: -90px; - margin-left: -150px; - border: 5px solid rgb(51, 51, 51); - background-color: rgb(173, 173, 196); - border-radius: 20px; - width: 300px; - height: 140px; - padding-bottom:25px; - font-size: 2.5em; - text-align: center; - align-items: center; +footer { + margin-top: 12px; + display: flex; + flex-wrap: wrap; + gap: 16px; justify-content: center; - animation: shake 1s infinite; - animation-direction: alternate; - animation-timing-function: ease-in-out; - box-shadow: 2px 2px 8px 2px black; -} -.retry { - position:absolute; - z-index: 2; - margin-top: 50px; - margin-left: -90px; - border: 5px solid rgb(51, 51, 51); - background-color: rgb(173, 173, 196); - border-radius: 20px; - width: 150px; - height: 45px; - padding: 10px; - font-size: 2em; - text-align: center; align-items: center; - justify-content: center; - box-shadow: 2px 2px 8px 2px black; -} -.retry:hover { - background-color: rgb(6, 94, 121); + padding: 18px 22px; + border-radius: 16px; + background: rgba(9, 16, 33, 0.6); + backdrop-filter: blur(6px); + font-size: 0.85rem; + letter-spacing: 0.08em; + color: var(--text-muted); } -.retry:active { - background-color: white; -} -@keyframes shake { - 0% { transform: translate(1px, 1px) rotate(0deg); } - 10% { transform: translate(-1px, -2px) rotate(-1deg); } - 20% { transform: translate(-3px, 0px) rotate(1deg); } - 30% { transform: translate(3px, 2px) rotate(0deg); } - 40% { transform: translate(1px, -1px) rotate(1deg); } - 50% { transform: translate(-1px, 2px) rotate(-1deg); } - 60% { transform: translate(-3px, 1px) rotate(0deg); } - 70% { transform: translate(3px, 1px) rotate(-1deg); } - 80% { transform: translate(-1px, -1px) rotate(1deg); } - 90% { transform: translate(1px, 2px) rotate(0deg); } - 100% { transform: translate(1px, -2px) rotate(-1deg); } -} - -/* ==== Responsive CSS Styles ==== */ -@media (max-width: 1130px) { - body { - margin: 2px; - } - - .container { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 10px; - min-height: 400px; - width: 100%; - } - - .game-boards { - height: 100%; - width: 100%; - } - - table { - margin: 0px; - width: 100%; - height: 100%; - } - - .square { - width: 50px; - height: 45px; - } - - .player-board { - border: 1px solid rgb(7, 31, 1); - background-color: rgb(67, 96, 60); - width: 100%; - height: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; - text-align: center; - } - - .computer-board { - border: 1px solid rgb(39, 2, 2); - background-color: rgb(84, 45, 45); - width: 100%; - height: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; - text-align: center; - } - - .battleship { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - } - - .destroyer { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .frigate { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .patrol-coastal { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - } +footer a { + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.12em; +} - .label { - font-size: 15px; - width: 25px; - padding: 0px; - margin: 0px; - width: 0px; - height: 0px; +@keyframes blast { + 0% { + transform: scale(0.7); + opacity: 0.5; } - - td { - padding: 0px; - width: 25px; - height: 25px; + 100% { + transform: scale(1); + opacity: 1; } +} - .ship { - width: 25px; - height: 25px; - margin: auto; +@keyframes ripple { + 0% { + transform: scale(0.6); + opacity: 0.4; } - - .ship-select { - width: 25px; - height: 25px; - margin: auto; + 100% { + transform: scale(1); + opacity: 1; } +} - .ship-hit { - width: 25px; - height: 25px; - margin: auto; - } - - .ship-miss { - width: 25px; - height: 25px; - margin: auto; - +@keyframes pulse { + 0% { + box-shadow: 0 0 0 rgba(98, 246, 255, 0.18); + transform: translateY(-4px); } - - .game-boards { - gap: 0px; + 100% { + box-shadow: 0 0 28px rgba(98, 246, 255, 0.35); + transform: translateY(4px); } } - -@media (max-width: 950px) { - body { - margin: 2px; +@media (max-width: 960px) { + :root { + --cell-size: 32px; } .container { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 10px; - min-height: 400px; - width: 100%; + padding: 24px 0 28px; } - .game-boards { - flex-direction: column; - height: 100%; - width: 100%; - } - - table { - margin: 0px; - width: 100%; - height: 100%; - } - - .square { - width: 50px; - height: 45px; - } - - .player-board { - border: 1px solid rgb(7, 31, 1); - background-color: rgb(67, 96, 60); - width: 100%; - height: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; - text-align: center; + .container-main { + grid-template-columns: 1fr; } - .computer-board { - border: 1px solid rgb(39, 2, 2); - background-color: rgb(84, 45, 45); - width: 100%; - height: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; - text-align: center; - } - - .battleship { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - } - - .destroyer { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .frigate { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .patrol-coastal { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .label { - font-size: 15px; - width: 25px; - padding: 0px; - margin: 0px; - width: 0px; - height: 0px; - } - - td { - padding: 0px; - width: 25px; - height: 25px; - } - - .ship { - width: 25px; - height: 25px; - margin: auto; - } - - .ship-select { - width: 25px; - height: 25px; - margin: auto; + .game-boards { + flex-wrap: wrap; } +} - .ship-hit { - width: 25px; - height: 25px; - margin: auto; +@media (max-width: 768px) { + :root { + --cell-size: 36px; } - .ship-miss { - width: 25px; - height: 25px; - margin: auto; - + header h1 { + font-size: clamp(2.1rem, 6vw, 2.5rem); } - .game-boards { - gap: 0px; + .selection { + padding: 20px; } } - - - - - - - -@media (max-width: 550px) { +@media (max-width: 700px) { body { - margin: 2px; + align-items: flex-start; + padding: 24px 0; } +} - .container { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 10px; - min-height: 400px; - width: 100%; +@media (max-width: 520px) { + :root { + --cell-size: 40px; } - .game-boards { - flex-direction: column; - height: 100%; - width: 100%; + .container { + gap: 20px; } - table { - margin: 0px; - width: 100%; - height: 100%; + .message { + padding: 16px; } - .player-board { - border: 1px solid rgb(7, 31, 1); - background-color: rgb(67, 96, 60); - width: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; - text-align: center; + .ship-selection1, + .ship-selection2 { + grid-template-columns: 1fr; } - .computer-board { - border: 1px solid rgb(39, 2, 2); - background-color: rgb(84, 45, 45); - width: 100%; - font-size: 15px; - justify-content: center; - align-items: center; - align-content: center; + footer { text-align: center; } - - .battleship { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - } - - .destroyer { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .frigate { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .patrol-coastal { - display: flex; - width: 130px; - justify-content: space-between; - padding: 3px 10px 0px 10px; - - } - - .label { - font-size: 15px; - width: 25px; - padding: 0px; - margin: 0px; - width: 0px; - height: 0px; - } - - td { - padding: 0px; - width: 25px; - height: 25px; - } - - .square { - width: 25px; - height: 25px; - } - - .ship { - width: 25px; - height: 25px; - margin: auto; - } - - .ship-select { - width: 25px; - height: 25px; - margin: auto; - } - - .ship-hit { - width: 25px; - height: 25px; - margin: auto; - } - - .ship-miss { - width: 25px; - height: 25px; - margin: auto; - - } - - .game-boards { - gap: 0px; - } -} \ No newline at end of file +} diff --git a/battleship.js b/battleship.js index 27a00d2..f35a76a 100644 --- a/battleship.js +++ b/battleship.js @@ -1,776 +1,38 @@ -var gameStart = false; -var validHit = true; -//AI Switches for smart attacks -var automatedAttackUp = false; -var automatedAttackDown = false; -var automatedAttackLeft = false; -var automatedAttackRight = false; -var initialCpuHit; -var savedAIAttackVector; - -// =========== arrays to represent gameboard==================================== -var gameBoard = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], - [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], - [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], - [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], - [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], - [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], - [70, 71, 72, 73, 74, 75, 76, 77, 78, 79], - [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], - [90, 91, 92, 93, 94, 95, 96, 97, 98, 99], -]; - -var grid = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], -]; - -var cpuBoardSelection = [ - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], -]; - -var playerBoardSelection = [ - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], -]; - -var cpuAttackLog = [ - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], -]; - -var playerAttackLog = [ - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], - ["x", "x", "x", "x", "x", "x", "x", "x", "x", "x"], -]; - -// ================ Randomizer Functions for Computer ========================== -//creates random row number -var randomRow = () => { - row = Math.floor(Math.random() * 10); - return row; -}; -// creates random column number -var randomColumn = () => { - column = Math.floor(Math.random() * 10); - return column; -}; -// Randomly determines if ship will be verticle or horizontal -var randomVert = () => { - random = Math.floor(Math.random() * 2); - if (random == 0) { - return false; - } else { - return true; - } -}; - -//========= Validation Functions =============================================== -// Checks to see if ship can fit on board. -var checkBoard = (ship) => { - for (var i = 0; i < ship.length; i++) { - for (var j = 0; j < gameBoard.length; j++) { - for (var k = 0; k < gameBoard[j].length; k++) { - if (ship[i] == gameBoard[j][k] && cpuBoardSelection[j][k] == 1) { - return false; - } - } - } - } - //if ship fits, return true - return true; -}; - -//checks to see in random numbers are in bounds for ship -var inBounds = (shipLength, row, column, vert) => { - var rightBoundary = 10; - var bottomBoundary = 10; - - if (!vert) { - if (grid[row][column] + shipLength > rightBoundary) { - return false; - } else { - return true; - } - } else { - if (grid[row + shipLength] == undefined) { - return false; - } else { - return true; - } - } -}; - -//================= Ship Creation Functions ==================================== -//creates verticle ship -var createVertShip = (shipLength, row, column) => { - var ship = []; - for (var i = 0; i < shipLength; i++) { - ship.push(gameBoard[row + i][column]); - } - return ship; -}; - -//creates horizontal ship -var createHorizShip = (shipLength, row, column) => { - var ship = []; - for (var i = 0; i < shipLength; i++) { - ship.push(gameBoard[row][column + i]); - } - return ship; -}; - -//Marks Board with 1's to show where ships are to be placed -var markBoard = (ship) => { - for (var i = 0; i < ship.length; i++) { - for (var j = 0; j < gameBoard.length; j++) { - for (var k = 0; k < gameBoard[j].length; k++) { - if (ship[i] == gameBoard[j][k]) { - cpuBoardSelection[j][k] = 1; - } - } - } - } -}; - -//============= CPU Ship building function ===================================== -//Calls other functions to make sure ship can be built -var cpuBuildShip = (shipLength) => { - //builds ship to users specification - var shipAvailable = false; - while (!shipAvailable) { - var isInBounds = false; - while (!isInBounds) { - var row = randomRow(); - var column = randomColumn(); - var vert = randomVert(); - isInBounds = inBounds(shipLength, row, column, vert); - } - var ship = []; - if (!vert) { - ship = createHorizShip(shipLength, row, column); - } else if (vert) { - ship = createVertShip(shipLength, row, column); - } - - //stops loop if ship can be built at location - shipAvailable = checkBoard(ship); - } - //places ships on board - markBoard(ship); - return ship; -}; - -// Displays data of CPU's created ship on webpage -var cpuDisplayShip = (ship) => { - for (var i = 0; i < ship.length; i++) { - document.getElementById("A" + ship[i]).innerHTML = - "
"; - } -}; - -// ========= Player Ship Building Functions ==================================== -// Displays data of CPU's created ship on webpage -var playerDisplayShip = (ship) => { - for (var i = 0; i < ship.length; i++) { - document.getElementById(ship[i]).innerHTML = - "
"; - } -}; - -//Marks Board with 1's to show where ships are to be placed -var markPlayerBoard = (ship) => { - for (var i = 0; i < ship.length; i++) { - for (var j = 0; j < gameBoard.length; j++) { - for (var k = 0; k < gameBoard[j].length; k++) { - if (ship[i] == gameBoard[j][k]) { - playerBoardSelection[j][k] = 1; - } - } - } - } -}; - -// Checks player's board -var checkPlayerBoard = (ship) => { - for (var i = 0; i < ship.length; i++) { - for (var j = 0; j < gameBoard.length; j++) { - for (var k = 0; k < gameBoard[j].length; k++) { - if (ship[i] == gameBoard[j][k] && playerBoardSelection[j][k] == 1) { - return false; - } - } - } - } - //if ship fits, return true - return true; -}; - -// finds row of player click on board -locateBoardRow = (id) => { - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if (id == gameBoard[i][j]) { - console.log("i = " + i); - return i; - } - } - } -}; - -// finds column of player click on board -locateBoardColumn = (id) => { - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if (id == gameBoard[i][j]) { - console.log("j = " + i); - return j; - } - } - } -}; - -// detects if player's ship is completely on the board -var playerInBounds = (shipLength, row, column, vert) => { - var rightBoundary = 10; - var bottomBoundary = 10; - - if (!vert) { - if (grid[row][column] + shipLength > rightBoundary) { - return false; - } else { - return true; - } - } else { - if (grid[row] + shipLength == undefined) { - // Investigate further - return false; - } else { - return true; - } - } -}; - -//========= Player Ship Count Functions ========== -// Sets the limit for amount ships player can have -var playerBattleship = 1; -var playerDestroyer = 2; -var playerFrigate = 1; -var playerCoastalShip = 1; - -// Reduces available number of ships when player places one on board -// Notifies player when all of a ship class has been placed on board. -var checkShipClassAvail = (shipSize) => { - if (shipSize == 5) { - if (playerBattleship > 0) { - playerBattleship--; - document.getElementById("Battleship").innerHTML = " " + playerBattleship; - return true; - } else { - alert("All Battleships placed on board. Select a different ship."); - } - } else if (shipSize == 4) { - if (playerDestroyer > 0) { - playerDestroyer--; - document.getElementById("Destroyer").innerHTML = " " + playerDestroyer; - return true; - } else { - alert("All Destroyers placed on board. Select a different ship."); - } - } else if (shipSize == 3) { - if (playerFrigate > 0) { - playerFrigate--; - document.getElementById("Frigate").innerHTML = " " + playerFrigate; - return true; - } else { - alert("All Frigates placed on board. Select a different ship."); - } - } else if (shipSize == 2) { - if (playerCoastalShip > 0) { - playerCoastalShip--; - document.getElementById("Patrolship").innerHTML = " " + playerCoastalShip; - return true; - } else if (playerCoastalShip == 0 && !gameStart) { - alert( - "All Patrol Coastal Ships placed on board. Select a different ship." - ); - } - } -}; - -// builds player's ship -var playerBuildShip = (shipLength, id) => { - if (shipLength > 0) { - //builds ship to users specification - var shipAvailable = false; - var isInBounds = false; - var ship = []; - - var row = locateBoardRow(id); - var column = locateBoardColumn(id); - - if (!vert) { - ship = createHorizShip(shipLength, row, column); - } else if (vert) { - ship = createVertShip(shipLength, row, column); - } - - //checks to see if ship is in bounds and available to place on board - shipAvailable = checkPlayerBoard(ship); - isInBounds = playerInBounds(shipLength, row, column, vert); - - if (shipAvailable && isInBounds) { - var shipCountGood = checkShipClassAvail(shipLength); - - if (shipCountGood) { - //places ships on logical board - markPlayerBoard(ship); - return ship; - } - } else { - if (!gameStart) { - alert("Ship out of bounds!"); - } - } - } -}; - -var playerHits = 0; -var cpuHits = 0; -// checks player missile strike location for ship presence -// notifies player of direct hit if ship present, changes logical board marker -// at location from 1 to 0, notifies player if he has already fired missile at location. -var checkIfDirectHit = (id) => { - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if (id == gameBoard[i][j] && cpuBoardSelection[i][j] == 1) { - cpuBoardSelection[i][j] = 0; - document.getElementById("A" + id).innerHTML = - "
"; - validHit = true; - return true; - } else if (id == gameBoard[i][j] && cpuBoardSelection[i][j] == 0) { - validHit = false; - } else if ( - id == gameBoard[i][j] && - cpuBoardSelection[i][j] == "x" && - playerAttackLog[i][j] == "x" - ) { - playerAttackLog[i][j] = 0; - document.getElementById("A" + id).innerHTML = - "
"; - validHit = true; - } else if (id == gameBoard[i][j] && playerAttackLog[i][j] == 0) { - validHit = false; - } - } - } -}; - -var checkCpuHits = () => { - if (cpuHits == 18) { - // Notifies player they lost - cpuHits++; - gameStart = false; - document.getElementById("announce").innerHTML = - "
YOU LOSE!
RETRY"; - } -}; - -var attackUp = (hitLocation) => { - checkCpuHits(); - var target = hitLocation - 10; - if (target < 0) { - automatedAttackUp = false; - automatedAttackDown = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == 1 && - cpuAttackLog[i][j] == "x" - ) { - playerBoardSelection[i][j] = 0; - cpuAttackLog[i][j] = 0; - document.getElementById(target).innerHTML = - "
"; - cpuHits++; - savedAIAttackVector = target; - automatedAttackUp = true; - return; - } else if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == "x" - ) { - document.getElementById(target).innerHTML = - "
"; - cpuAttackLog[i][j] = 0; - automatedAttackUp = false; - automatedAttackDown = true; - savedAIAttackVector = initialCpuHit; - } else if (target == gameBoard[i][j] && cpuAttackLog[i][j] == 0) { - automatedAttackUp = false; - automatedAttackDown = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - } - } -}; -var attackDown = (hitLocation) => { - checkCpuHits(); - var target = hitLocation + 10; - if (target > 99) { - automatedAttackDown = false; - automatedAttackLeft = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == 1 && - cpuAttackLog[i][j] == "x" - ) { - playerBoardSelection[i][j] = 0; - cpuAttackLog[i][j] = 0; - document.getElementById(target).innerHTML = - "
"; - cpuHits++; - savedAIAttackVector = target; - automatedAttackDown = true; - return; - } else if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == "x" - ) { - document.getElementById(target).innerHTML = - "
"; - cpuAttackLog[i][j] = 0; - automatedAttackDown = false; - automatedAttackLeft = true; - savedAIAttackVector = initialCpuHit; - } else if (target == gameBoard[i][j] && cpuAttackLog[i][j] == 0) { - automatedAttackDown = false; - automatedAttackLeft = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - } - } -}; -var attackLeft = (hitLocation) => { - checkCpuHits(); - var target = hitLocation - 1; - if (target < 0) { - automatedAttackLeft = false; - automatedAttackRight = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == 1 && - cpuAttackLog[i][j] == "x" - ) { - playerBoardSelection[i][j] = 0; - cpuAttackLog[i][j] = 0; - document.getElementById(target).innerHTML = - "
"; - cpuHits++; - savedAIAttackVector = target; - automatedAttackLeft = true; - return; - } else if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == "x" - ) { - document.getElementById(target).innerHTML = - "
"; - cpuAttackLog[i][j] = 0; - automatedAttackLeft = false; - automatedAttackRight = true; - savedAIAttackVector = initialCpuHit; - } else if (target == gameBoard[i][j] && cpuAttackLog[i][j] == 0) { - automatedAttackLeft = false; - automatedAttackRight = true; - savedAIAttackVector = initialCpuHit; - aiAttackRoutine(savedAIAttackVector); - } - } - } -}; -var attackRight = (hitLocation) => { - checkCpuHits(); - var target = hitLocation + 1; - if (target > 99) { - automatedAttackRight = false; - initialCpuHit = 0; - savedAIAttackVector = 0; - aiAttackRoutine(savedAIAttackVector); - } - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == 1 && - cpuAttackLog[i][j] == "x" - ) { - playerBoardSelection[i][j] = 0; - cpuAttackLog[i][j] = 0; - document.getElementById(target).innerHTML = - "
"; - cpuHits++; - savedAIAttackVector = target; - automatedAttackRight = true; - return; - } else if ( - target == gameBoard[i][j] && - playerBoardSelection[i][j] == "x" - ) { - document.getElementById(target).innerHTML = - "
"; - cpuAttackLog[i][j] = 0; - automatedAttackRight = false; - initialCpuHit = 0; - savedAIAttackVector = 0; - } else if (target == gameBoard[i][j] && cpuAttackLog[i][j] == 0) { - automatedAttackRight = false; - initialCpuHit = 0; - savedAIAttackVector = 0; - aiAttackRoutine(savedAIAttackVector); - } - } - } -}; - -var aiAttackRoutine = (aiAttackVector) => { - savedAIAttackVector = aiAttackVector; - - var aiAttackUp = automatedAttackUp; - var aiAttackDown = automatedAttackDown; - var aiAttackLeft = automatedAttackLeft; - var aiAttackRight = automatedAttackRight; - - if (aiAttackUp) { - attackUp(savedAIAttackVector); - } - if (aiAttackDown) { - attackDown(savedAIAttackVector); - } - if (aiAttackRight) { - attackRight(savedAIAttackVector); - } - if (aiAttackLeft) { - attackLeft(savedAIAttackVector); - } -}; - -// Randomized CPU Attack after Player attacks. -var cpuAttack = () => { - checkCpuHits(); - - var randomizeAttack = true; - while (randomizeAttack) { - var row = randomRow(); - var column = randomColumn(); - if (cpuAttackLog[row][column] == "x") { - randomizeAttack = false; - } - } - - cpuAttackLog[row][column] = 0; - var attackVector = gameBoard[row][column]; - for (var i = 0; i < gameBoard.length; i++) { - for (var j = 0; j < gameBoard[i].length; j++) { - if (attackVector == gameBoard[i][j] && playerBoardSelection[i][j] == 1) { - playerBoardSelection[i][j] = 0; - document.getElementById(attackVector).innerHTML = - "
"; - cpuHits++; - automatedAttackUp = true; - savedAIAttackVector = attackVector; - initialCpuHit = attackVector; - return true; - } else { - document.getElementById(attackVector).innerHTML = - "
"; - } - } - } -}; - -//============== Mouse Click Functions ======================================= -//=============== ATTTAAAAAAACCCCKKKKK!!!!!! =================== - -// when player clicks on CPU board -var clickCpuBoard = (id) => { - if (gameStart) { - var directHit = false; - // PLAYER Attack ==== - directHit = checkIfDirectHit(id); - - if (directHit) { - playerHits += 1; - } - if (playerHits >= 18) { - gameStart = false; - document.getElementById("announce").innerHTML = - "
YOU WIN!
RETRY"; - } - if (validHit) { - // Continues where AI attacks left off if they started - if ( - automatedAttackUp || - automatedAttackDown || - automatedAttackLeft || - automatedAttackRight - ) { - aiAttackRoutine(savedAIAttackVector); - } else { - cpuAttack(); - } - } - } else { - alert("Game has not started"); - } -}; - -// Sets ship size to display when user clicks on ship selection -var shipSize = 0; -var selectShip = (size) => { - shipSize = size; -}; - -// sets ship to Vertical or horizontal based on what user selects -var vert = false; -var turnVertical = () => { - vert = true; -}; - -var turnHorizontal = () => { - vert = false; -}; - -// Keep track of ships placed -var shipCount = 5; - -// reduces ship count by 1 when called -var reduceShipCount = () => { - shipCount--; -}; - -// alerts user all ships have been placed...and prevents more from being placed -var checkShipCount = () => { - if (shipCount <= 0 && !gameStart) { - alert("You have placed all ships. Click on Start Game."); - return false; - } else { - return true; - } -}; - -// Click event that initializes selection functions -var clickTarget = (id) => { - // checks if there are ships to place - var playerSelect = checkShipCount(); - - // if ships can be placed, player can place ship.. - if (playerSelect) { - var playerShip = playerBuildShip(shipSize, id); - } - - //displays ship on board - playerDisplayShip(playerShip); - - // lower ship count by one - reduceShipCount(); -}; - -// ===================== Start Game ============================================ - -// When player selects start, this generates the cpu's ships on the cpu board -var clickStartGame = () => { - if (shipCount <= 0) { - gameStart = true; - - //clear the selection screen - document.getElementById("remove-on-start").innerHTML = ""; - document.getElementById("header").innerHTML = ""; - var elements = document.getElementsByClassName("label"); - for (var i = 0, length = elements.length; i < length; i++) { - elements[i].innerHTML = ""; - } - - //generates the CPU's ships on logical board - var battleShip = cpuBuildShip(5); - var destroyer1 = cpuBuildShip(4); - var destroyer2 = cpuBuildShip(4); - var frigate = cpuBuildShip(3); - var patrolCoastal = cpuBuildShip(2); - - // initializes CPU attacks - - // Uncomment to see location of Computer's ships - // displays ships on visual board - // cpuDisplayShip(battleShip); - // cpuDisplayShip(destroyer1); - // cpuDisplayShip(destroyer2); - // cpuDisplayShip(frigate); - // cpuDisplayShip(patrolCoastal); - } else { - alert("Select your ship location's first"); - } -}; +import { BattleshipGame } from "./src/game.js"; +import { UIController } from "./src/ui-controller.js"; +import { ORIENTATION } from "./src/constants.js"; + +const uiController = new UIController(document); +const game = new BattleshipGame(uiController); + +const yearEl = document.getElementById("current-year"); +if (yearEl) { + yearEl.textContent = new Date().getFullYear(); +} + +const bridge = { + clickTarget(index) { + game.placePlayerShip(Number(index)); + }, + clickCpuBoard(index) { + game.playerAttack(Number(index)); + }, + selectShip(size) { + game.selectShip(Number(size)); + }, + turnVertical() { + game.setOrientation(ORIENTATION.VERTICAL); + }, + turnHorizontal() { + game.setOrientation(ORIENTATION.HORIZONTAL); + }, + clickStartGame() { + game.startGame(); + }, +}; + +Object.entries(bridge).forEach(([key, handler]) => { + window[key] = handler; +}); + +window.battleshipGame = game; diff --git a/index.html b/index.html index f8e5889..a879082 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,10 @@ - + + + + Battleship Game @@ -335,7 +338,7 @@

Battleship