Skip to content

Commit

Permalink
feat: player name input (#48)
Browse files Browse the repository at this point in the history
* feat: allow player name

feat: style

* fix: typecheck
  • Loading branch information
kenrick95 committed Nov 10, 2023
1 parent 2d6ea2c commit c038e51
Show file tree
Hide file tree
Showing 24 changed files with 670 additions and 483 deletions.
129 changes: 76 additions & 53 deletions browser/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
Expand Down Expand Up @@ -27,7 +27,7 @@ <h1 class="header-title">c4 - Connect Four</h1>
<canvas class="section-canvas"></canvas>
</section>

<dialog class="mode-chooser">
<dialog class="init-screen">
<h1>c4 - Connect Four</h1>
<h2>How to play?</h2>
<p>Connect Four is a two-player game.</p>
Expand All @@ -47,57 +47,80 @@ <h2>How to play?</h2>
>Connect Four article on Wikipedia</a
>.
</p>
<h2>Choose playing mode:</h2>
<form method="dialog" class="mode-chooser-form">
<ul class="mode-chooser-list">
<li>
<label
><input
class="mode-chooser-input"
type="radio"
name="mode"
value="offline-ai"
checked
autofocus
/>
Offline: Human player vs AI player</label
>
</li>
<li>
<label
><input
class="mode-chooser-input"
type="radio"
name="mode"
value="offline-human"
/>
Offline: Human player vs human player</label
>
</li>
<li>
<label
><input
class="mode-chooser-input"
type="radio"
name="mode"
value="ai-vs-ai"
/>
Spectator: AI player vs AI player</label
>
</li>
<li>
<label
><input
class="mode-chooser-input"
type="radio"
name="mode"
value="online-human"
/>
Online: Human player vs human player</label
>
</li>
</ul>
<button class="mode-chooser-submit" type="submit" value="confirm">
<h2>Game Settings</h2>
<form method="dialog" class="game-settings-form">
<div class="game-settings-form-section">
Playing Mode:
<ul class="game-settings-mode-list">
<li>
<label
><input
class="game-settings-mode-input"
type="radio"
name="mode"
value="offline-ai"
checked
autofocus
/>
Offline: Human player vs AI player</label
>
</li>
<li>
<label
><input
class="game-settings-mode-input"
type="radio"
name="mode"
value="offline-human"
/>
Offline: Human player vs human player</label
>
</li>
<li>
<label
><input
class="game-settings-mode-input"
type="radio"
name="mode"
value="ai-vs-ai"
/>
Spectator: AI player vs AI player</label
>
</li>
<li>
<label
><input
class="game-settings-mode-input"
type="radio"
name="mode"
value="online-human"
/>
Online: Human player vs human player</label
>
</li>
</ul>
</div>
<label class="game-settings-player-1-name-label" for="player-1-name">
Player's name:
</label>
<input
type="text"
class="game-settings-player-1-name-input"
value="Player 1"
name="player-1-name"
placeholder="Player 1"
/>
<label class="game-settings-player-2-name-label" for="player-2-name">
Player's name:
</label>
<input
type="text"
class="game-settings-player-2-name-input"
value="Player 2"
name="player-2-name"
placeholder="Player 2"
/>
<button class="game-settings-submit" type="submit" value="confirm">
Start game
</button>
</form>
Expand Down
141 changes: 116 additions & 25 deletions browser/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ document.addEventListener('DOMContentLoaded', () => {
console.error('Canvas element not found')
return
}
const modeDOM = document.querySelector('.mode-chooser') as HTMLDialogElement
if (!modeDOM) {
const initScreenDOM = document.querySelector(
'.init-screen',
) as HTMLDialogElement
if (!initScreenDOM) {
console.error('Mode element not found ')
return
}
Expand All @@ -20,57 +22,146 @@ document.addEventListener('DOMContentLoaded', () => {
const searchParams = new URLSearchParams(location.search)
const connectionMatchId = searchParams.get('matchId')
const backToModeSelector = document.querySelector(
'.statusbox-button-back'
'.statusbox-button-back',
) as HTMLDivElement

const settingsForm = document.querySelector(
'.game-settings-form',
) as HTMLFormElement

if (!settingsForm) {
console.error('.game-settings-form not found ')
return
}

const player1NameLabel = settingsForm.querySelector(
'.game-settings-player-1-name-label',
) as HTMLLabelElement
const player2NameLabel = settingsForm.querySelector(
'.game-settings-player-2-name-label',
) as HTMLLabelElement
const player1NameInput = settingsForm.querySelector(
'.game-settings-player-1-name-input',
) as HTMLInputElement
const player2NameInput = settingsForm.querySelector(
'.game-settings-player-2-name-input',
) as HTMLInputElement

let currentGameHandler:
| {
end: () => void
}
| undefined
| null = null

if (!!connectionMatchId) {
currentGameHandler = Game.initGameOnline2p()
return
}
backToModeSelector?.classList.add('hidden')
modeDOM.showModal()
initScreenDOM.showModal()

const modeChooser = document.querySelector(
'.mode-chooser-form'
) as HTMLFormElement

if (!modeChooser) {
console.error('.mode-chooser-form not found ')
return
}
let chosenMode: string = !!connectionMatchId ? 'online-human' : 'offline-ai'
renderForm()

backToModeSelector?.addEventListener('click', () => {
if (currentGameHandler && currentGameHandler.end) {
currentGameHandler.end()
}
backToModeSelector?.classList.add('hidden')
modeDOM.showModal()
initScreenDOM.showModal()
})

modeDOM.addEventListener('cancel', (ev) => {
initScreenDOM.addEventListener('cancel', (ev) => {
ev.preventDefault()
})

modeDOM.addEventListener('close', (ev) => {
const formData = new FormData(modeChooser)
initGame(formData.get('mode') as string)
initScreenDOM.addEventListener('close', (ev) => {
const formData = new FormData(settingsForm)
const gameMode = formData.get('mode') as string
const firstPlayerName = formData.get('player-1-name') as string | null
const secondPlayerName = formData.get('player-2-name') as string | null
initGame(gameMode, [firstPlayerName, secondPlayerName])
})

settingsForm.addEventListener('input', (ev) => {
const formData = new FormData(settingsForm)
chosenMode = formData.get('mode') as string
renderForm()
})

function initGame(chosenMode: string | null) {
function renderForm() {
if (!!connectionMatchId) {
for (let el of settingsForm.querySelectorAll(
'.game-settings-mode-input',
)) {
const checkboxEl = el as HTMLInputElement
checkboxEl.readOnly = true
if (checkboxEl.value === 'online-human') {
checkboxEl.checked = true
} else {
checkboxEl.checked = false
}
}

player2NameLabel.textContent = `Your name:`
player1NameInput.disabled = true
player2NameInput.disabled = false
player1NameLabel.classList.add('hidden')
player1NameInput.classList.add('hidden')
player2NameLabel.classList.remove('hidden')
player2NameInput.classList.remove('hidden')
} else if (chosenMode === 'offline-human') {
player1NameLabel.textContent = `First player's name:`
player2NameLabel.textContent = `Second player's name:`
player1NameLabel.classList.remove('hidden')
player1NameInput.classList.remove('hidden')
player2NameLabel.classList.remove('hidden')
player2NameInput.classList.remove('hidden')
player1NameInput.disabled = false
player2NameInput.disabled = false
} else if (chosenMode === 'offline-ai') {
player1NameLabel.textContent = `Player's name:`
player2NameLabel.textContent = `Player's name:`
player1NameLabel.classList.remove('hidden')
player1NameInput.classList.remove('hidden')
player2NameLabel.classList.add('hidden')
player2NameInput.classList.add('hidden')
player1NameInput.disabled = false
player2NameInput.disabled = true
} else if (chosenMode === 'online-human') {
player1NameLabel.textContent = `Your name:`
player2NameLabel.textContent = `Other player's name:`
player1NameLabel.classList.remove('hidden')
player1NameInput.classList.remove('hidden')
player2NameLabel.classList.add('hidden')
player2NameInput.classList.add('hidden')
player1NameInput.disabled = false
player2NameInput.disabled = true
} else if (chosenMode === 'ai-vs-ai') {
player1NameLabel.textContent = `Player's name:`
player2NameLabel.textContent = `Player's name:`
player1NameLabel.classList.add('hidden')
player1NameInput.classList.add('hidden')
player2NameLabel.classList.add('hidden')
player2NameInput.classList.add('hidden')
player1NameInput.disabled = true
player2NameInput.disabled = true
}
}

function initGame(chosenMode: string | null, playerNames: (string | null)[]) {
console.log('initGame chosenMode:', chosenMode)
backToModeSelector?.classList.remove('hidden')
if (chosenMode === 'offline-human') {
currentGameHandler = Game.initGameLocal2p()
currentGameHandler = Game.initGameLocal2p(
playerNames[0] || 'Player 1',
playerNames[1] || 'Player 2',
)
} else if (chosenMode === 'offline-ai') {
currentGameHandler = Game.initGameLocalAi()
currentGameHandler = Game.initGameLocalAi(playerNames[0] || 'Player 1')
} else if (chosenMode === 'online-human') {
currentGameHandler = Game.initGameOnline2p()
currentGameHandler = Game.initGameOnline2p(
connectionMatchId
? playerNames[1] || 'Player 2'
: playerNames[0] || 'Player 1',
)
} else if (chosenMode === 'ai-vs-ai') {
currentGameHandler = Game.initGameAiVsAi()
} else {
Expand Down
4 changes: 2 additions & 2 deletions browser/src/game/game-ai-vs-ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export function initGameAiVsAi() {
return
}
const board = new Board(canvas)
const firstPlayer = new PlayerAi(BoardPiece.PLAYER_1)
const secondPlayer = new PlayerAi(BoardPiece.PLAYER_2)
const firstPlayer = new PlayerAi(BoardPiece.PLAYER_1, `AI Player 1`)
const secondPlayer = new PlayerAi(BoardPiece.PLAYER_2, `AI Player 2`)
const game = new GameAiVsAi([firstPlayer, secondPlayer], board)

statusbox?.classList.remove('hidden')
Expand Down
9 changes: 7 additions & 2 deletions browser/src/game/game-local-2p.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { PlayerHuman } from '@kenrick95/c4'
import { GameLocal, initGameLocal } from './game-local'

class GameLocal2p extends GameLocal {}
export function initGameLocal2p() {
return initGameLocal(GameLocal2p, new PlayerHuman(BoardPiece.PLAYER_2))
export function initGameLocal2p(
firstPlayerName: string,
secondPlayerName: string,
) {
const firstPlayer = new PlayerHuman(BoardPiece.PLAYER_1, firstPlayerName)
const secondPlayer = new PlayerHuman(BoardPiece.PLAYER_2, secondPlayerName)
return initGameLocal(GameLocal2p, firstPlayer, secondPlayer)
}
9 changes: 5 additions & 4 deletions browser/src/game/game-local-ai.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { BoardPiece } from '@kenrick95/c4'
import { PlayerAi } from '@kenrick95/c4'
import { BoardPiece, PlayerHuman, PlayerAi } from '@kenrick95/c4'
import { GameLocal, initGameLocal } from './game-local'

class GameLocalAi extends GameLocal {}
export function initGameLocalAi() {
return initGameLocal(GameLocalAi, new PlayerAi(BoardPiece.PLAYER_2))
export function initGameLocalAi(playerName: string) {
const firstPlayer = new PlayerHuman(BoardPiece.PLAYER_1, playerName)
const aiPlayer = new PlayerAi(BoardPiece.PLAYER_2, `AI Player`)
return initGameLocal(GameLocalAi, firstPlayer, aiPlayer)
}
Loading

0 comments on commit c038e51

Please sign in to comment.