Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
T
test
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Смирнов Олег
test
Commits
9d2a6016
Commit
9d2a6016
authored
Dec 17, 2024
by
root
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
production debug
parent
ebe4288e
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
96 additions
and
62 deletions
+96
-62
constants.ts
constants.ts
+1
-0
env.local
env.local
+1
-0
next.config.ts
next.config.ts
+1
-0
package.json
package.json
+2
-2
page.tsx
src/app/page.tsx
+28
-10
GameBoard.tsx
src/components/GameBoard.tsx
+0
-1
GameInvite.tsx
src/components/GameInvite.tsx
+3
-1
socket.ts
src/pages/api/socket.ts
+59
-47
game.ts
src/types/game.ts
+1
-1
No files found.
constants.ts
0 → 100644
View file @
9d2a6016
export
const
APP_URL
=
"/games/tictachack"
\ No newline at end of file
env.local
0 → 100644
View file @
9d2a6016
APP_URL=/games/tictachack
\ No newline at end of file
next.config.ts
View file @
9d2a6016
...
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
...
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
const
nextConfig
:
NextConfig
=
{
const
nextConfig
:
NextConfig
=
{
/* config options here */
/* config options here */
basePath
:
'/games/tictachack'
};
};
export
default
nextConfig
;
export
default
nextConfig
;
package.json
View file @
9d2a6016
...
@@ -3,9 +3,9 @@
...
@@ -3,9 +3,9 @@
"version"
:
"0.1.0"
,
"version"
:
"0.1.0"
,
"private"
:
true
,
"private"
:
true
,
"scripts"
:
{
"scripts"
:
{
"dev"
:
"next dev --turbopack"
,
"dev"
:
"next dev --turbopack
-p 3001
"
,
"build"
:
"next build"
,
"build"
:
"next build"
,
"start"
:
"next start"
,
"start"
:
"next start
-p 3001
"
,
"lint"
:
"next lint"
"lint"
:
"next lint"
},
},
"dependencies"
:
{
"dependencies"
:
{
...
...
src/app/page.tsx
View file @
9d2a6016
'use client'
;
'use client'
;
import
{
useEffect
,
useState
}
from
'react'
;
import
{
useEffect
,
useState
,
Suspense
}
from
'react'
;
import
{
useSearchParams
}
from
'next/navigation'
;
import
{
useSearchParams
}
from
'next/navigation'
;
import
{
io
,
Socket
}
from
'socket.io-client'
;
import
{
io
,
Socket
}
from
'socket.io-client'
;
import
GameBoard
from
'../components/GameBoard'
;
import
GameBoard
from
'../components/GameBoard'
;
import
PlayerInfo
from
'../components/PlayerInfo'
;
import
PlayerInfo
from
'../components/PlayerInfo'
;
import
GameInvite
from
'../components/GameInvite'
;
import
GameInvite
from
'../components/GameInvite'
;
import
{
GameState
,
Player
,
GameMove
}
from
'../types/game'
;
import
{
GameState
}
from
'../types/game'
;
import
{
APP_URL
}
from
'../../constants'
;
let
socket
:
Socket
;
let
socket
:
Socket
;
export
default
function
Home
()
{
function
Home
()
{
const
searchParams
=
useSearchParams
();
const
searchParams
=
useSearchParams
();
const
[
roomId
,
setRoomId
]
=
useState
<
string
>
(
''
);
const
[
roomId
,
setRoomId
]
=
useState
<
string
>
(
''
);
const
[
showInvite
,
setShowInvite
]
=
useState
(
false
);
const
[
showInvite
,
setShowInvite
]
=
useState
(
false
);
...
@@ -27,11 +28,12 @@ export default function Home() {
...
@@ -27,11 +28,12 @@ export default function Home() {
const
[
turnTimeLeft
,
setTurnTimeLeft
]
=
useState
<
number
>
(
20000
);
const
[
turnTimeLeft
,
setTurnTimeLeft
]
=
useState
<
number
>
(
20000
);
useEffect
(()
=>
{
useEffect
(()
=>
{
const
roomFromUrl
=
searchParams
.
get
(
'room'
);
if
(
!
socket
)
{
if
(
!
socket
)
{
socket
=
io
({
socket
=
io
({
path
:
'/api/socket'
,
path
:
`
${
APP_URL
}
/api/socket`
,
});
});
socket
.
on
(
'connect'
,
()
=>
{
socket
.
on
(
'connect'
,
()
=>
{
...
@@ -57,9 +59,12 @@ export default function Home() {
...
@@ -57,9 +59,12 @@ export default function Home() {
});
});
}
}
if
(
roomFromUrl
)
{
if
(
searchParams
)
{
socket
.
emit
(
'joinGame'
,
{
roomId
:
roomFromUrl
});
const
roomFromUrl
=
searchParams
.
get
(
'room'
);
setRoomId
(
roomFromUrl
);
if
(
roomFromUrl
)
{
socket
.
emit
(
'joinGame'
,
{
roomId
:
roomFromUrl
});
setRoomId
(
roomFromUrl
);
}
}
}
return
()
=>
{
return
()
=>
{
...
@@ -72,8 +77,9 @@ export default function Home() {
...
@@ -72,8 +77,9 @@ export default function Home() {
useEffect
(()
=>
{
useEffect
(()
=>
{
let
timer
:
NodeJS
.
Timeout
;
let
timer
:
NodeJS
.
Timeout
;
if
(
gameState
.
isYourTurn
&&
gameState
.
turnStartTime
)
{
if
(
gameState
.
isYourTurn
&&
gameState
.
turnStartTime
)
{
const
startTime
=
gameState
.
turnStartTime
;
timer
=
setInterval
(()
=>
{
timer
=
setInterval
(()
=>
{
const
timeLeft
=
gameState
.
turnTimeLimit
-
(
Date
.
now
()
-
gameState
.
turnS
tartTime
);
const
timeLeft
=
gameState
.
turnTimeLimit
-
(
Date
.
now
()
-
s
tartTime
);
setTurnTimeLeft
(
Math
.
max
(
0
,
timeLeft
));
setTurnTimeLeft
(
Math
.
max
(
0
,
timeLeft
));
if
(
timeLeft
<=
0
)
{
if
(
timeLeft
<=
0
)
{
socket
.
emit
(
'turnTimeout'
,
{
roomId
});
socket
.
emit
(
'turnTimeout'
,
{
roomId
});
...
@@ -84,7 +90,7 @@ export default function Home() {
...
@@ -84,7 +90,7 @@ export default function Home() {
return
()
=>
clearInterval
(
timer
);
return
()
=>
clearInterval
(
timer
);
},
[
gameState
.
isYourTurn
,
gameState
.
turnStartTime
,
gameState
.
turnTimeLimit
,
roomId
]);
},
[
gameState
.
isYourTurn
,
gameState
.
turnStartTime
,
gameState
.
turnTimeLimit
,
roomId
]);
const
handleCreateGame
=
()
=>
{
const
handleCreateGame
=
()
=>
{
socket
.
emit
(
'createGame'
);
socket
.
emit
(
'createGame'
);
socket
.
once
(
'gameCreated'
,
({
roomId
,
gameState
}:
{
roomId
:
string
,
gameState
:
GameState
})
=>
{
socket
.
once
(
'gameCreated'
,
({
roomId
,
gameState
}:
{
roomId
:
string
,
gameState
:
GameState
})
=>
{
setRoomId
(
roomId
);
setRoomId
(
roomId
);
...
@@ -130,6 +136,7 @@ export default function Home() {
...
@@ -130,6 +136,7 @@ export default function Home() {
}
}
return
(
return
(
<
Suspense
>
<
div
className=
"relative min-h-screen bg-gray-900 text-white"
>
<
div
className=
"relative min-h-screen bg-gray-900 text-white"
>
{
showInvite
&&
<
GameInvite
roomId=
{
roomId
}
/>
}
{
showInvite
&&
<
GameInvite
roomId=
{
roomId
}
/>
}
...
@@ -200,5 +207,16 @@ export default function Home() {
...
@@ -200,5 +207,16 @@ export default function Home() {
)
}
)
}
</
div
>
</
div
>
</
div
>
</
div
>
</
Suspense
>
);
);
}
}
const
App
=
()
=>
{
return
(
<
Suspense
fallback=
{
<
div
>
Загрузка...
</
div
>
}
>
<
Home
/>
</
Suspense
>
);
};
export
default
App
;
src/components/GameBoard.tsx
View file @
9d2a6016
...
@@ -27,7 +27,6 @@ const GameBoard: React.FC<GameBoardProps> = ({
...
@@ -27,7 +27,6 @@ const GameBoard: React.FC<GameBoardProps> = ({
const
containerRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
containerRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
cellSize
=
60
;
const
cellSize
=
60
;
const
viewportSize
=
800
;
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
containerRef
.
current
)
{
if
(
containerRef
.
current
)
{
...
...
src/components/GameInvite.tsx
View file @
9d2a6016
import
React
from
'react'
;
import
React
from
'react'
;
import
{
APP_URL
}
from
'../../constants'
;
interface
GameInviteProps
{
interface
GameInviteProps
{
roomId
:
string
;
roomId
:
string
;
}
}
const
GameInvite
:
React
.
FC
<
GameInviteProps
>
=
({
roomId
})
=>
{
const
GameInvite
:
React
.
FC
<
GameInviteProps
>
=
({
roomId
})
=>
{
const
gameUrl
=
typeof
window
!==
'undefined'
?
`
${
window
.
location
.
origin
}
?room=
${
roomId
}
`
:
''
;
const
gameUrl
=
typeof
window
!==
'undefined'
?
`
${
window
.
location
.
origin
}
${
APP_URL
}
?room=
${
roomId
}
`
:
''
;
const
shareText
=
`Присоединяйся ко мне в игре!`
;
const
shareText
=
`Присоединяйся ко мне в игре!`
;
...
...
src/pages/api/socket.ts
View file @
9d2a6016
import
{
Server
}
from
'socket.io'
;
import
{
Server
}
from
'socket.io'
;
import
{
Server
as
NetServer
}
from
'http'
;
import
{
Server
as
NetServer
}
from
'http'
;
import
{
NextApiRequest
}
from
'next'
;
import
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
NextApiResponseWithSocket
}
from
'../../types/next'
;
// import { NextApiResponseWithSocket } from '../../types/next';
import
{
GameState
,
GameMove
}
from
'../../types/game'
;
import
{
GameState
,
GameMove
,
CellValue
}
from
'../../types/game'
;
import
{
APP_URL
}
from
'../../../constants'
;
export
type
NextApiResponseWithSocket
=
NextApiResponse
&
{
socket
:
{
server
:
NetServer
&
{
io
:
Server
}
}
}
const
games
=
new
Map
<
string
,
GameState
>
();
const
games
=
new
Map
<
string
,
GameState
>
();
...
@@ -23,7 +34,7 @@ const createNewGame = (playerId: string): [string, GameState] => {
...
@@ -23,7 +34,7 @@ const createNewGame = (playerId: string): [string, GameState] => {
isYourTurn
:
false
,
isYourTurn
:
false
,
status
:
'waiting'
,
status
:
'waiting'
,
turnTimeLimit
:
20000
,
turnTimeLimit
:
20000
,
turnStartTime
:
null
,
turnStartTime
:
undefined
,
players
:
{
players
:
{
attacker
:
{
attacker
:
{
id
:
playerId
,
id
:
playerId
,
...
@@ -54,44 +65,45 @@ const joinGame = (roomId: string, playerId: string): GameState | null => {
...
@@ -54,44 +65,45 @@ const joinGame = (roomId: string, playerId: string): GameState | null => {
return
game
;
return
game
;
};
};
const
startNewRound
=
(
game
:
GameState
,
firstReadyPlayerId
:
string
):
GameState
=>
{
// const startNewRound = (game: GameState, firstReadyPlayerId: string): GameState => {
// Определяем, кто будет атакующим в новой игре (тот, кто первый нажал "Играть снова")
// // Определяем, кто будет атакующим в новой игре (тот, кто первый нажал "Играть снова")
const
oldAttacker
=
game
.
players
.
attacker
!
;
// const oldAttacker = game.players.attacker!;
const
oldDefender
=
game
.
players
.
defender
!
;
// const oldDefender = game.players.defender!;
// Определяем, кто первый нажал кнопку
// // Определяем, кто первый нажал кнопку
const
firstPlayer
=
firstReadyPlayerId
===
oldAttacker
.
id
?
oldAttacker
:
oldDefender
;
// const firstPlayer = firstReadyPlayerId === oldAttacker.id ? oldAttacker : oldDefender;
const
secondPlayer
=
firstReadyPlayerId
===
oldAttacker
.
id
?
oldDefender
:
oldAttacker
;
// const secondPlayer = firstReadyPlayerId === oldAttacker.id ? oldDefender : oldAttacker;
// Сбрасываем состояние игры
// // Сбрасываем состояние игры
const
newGame
:
GameState
=
{
// const newGame: GameState = {
...
game
,
// ...game,
cells
:
{},
// cells: {},
currentPlayer
:
'X'
,
// currentPlayer: 'X',
winner
:
null
,
// winner: null,
status
:
'playing'
,
// status: 'playing',
lastMove
:
null
,
// lastMove: null,
turnStartTime
:
Date
.
now
(),
// turnStartTime: Date.now(),
readyForNewGame
:
{},
// readyForNewGame: {},
// Первый нажавший становится атакующим
// // Первый нажавший становится атакующим
players
:
{
// players: {
attacker
:
{
// attacker: {
...
firstPlayer
,
// ...firstPlayer,
isAttacker
:
true
,
// isAttacker: true,
nickname
:
'Heker'
// nickname: 'Heker'
},
// },
defender
:
{
// defender: {
...
secondPlayer
,
// ...secondPlayer,
isAttacker
:
false
,
// isAttacker: false,
nickname
:
'Beluga'
// nickname: 'Beluga'
}
// }
}
// }
};
// };
return
newGame
;
// return newGame;
};
// };
const
checkWinner
=
(
cells
:
{
[
key
:
string
]:
string
},
lastMove
:
GameMove
):
string
|
null
=>
{
const
checkWinner
=
(
cells
:
{
[
key
:
string
]:
CellValue
}
,
lastMove
:
GameMove
):
CellValue
=>
{
const
directions
=
[
const
directions
=
[
[
0
,
1
],
// horizontal
[
0
,
1
],
// horizontal
[
1
,
0
],
// vertical
[
1
,
0
],
// vertical
...
@@ -126,15 +138,15 @@ const checkWinner = (cells: { [key: string]: string }, lastMove: GameMove): stri
...
@@ -126,15 +138,15 @@ const checkWinner = (cells: { [key: string]: string }, lastMove: GameMove): stri
const
handler
=
async
(
req
:
NextApiRequest
,
res
:
NextApiResponseWithSocket
)
=>
{
const
handler
=
async
(
req
:
NextApiRequest
,
res
:
NextApiResponseWithSocket
)
=>
{
if
(
!
res
.
socket
.
server
.
io
)
{
if
(
!
res
.
socket
.
server
.
io
)
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const
httpServer
:
NetServer
=
res
.
socket
.
server
as
any
;
const
httpServer
:
NetServer
=
res
.
socket
.
server
as
any
;
const
io
=
new
Server
(
httpServer
,
{
const
io
=
new
Server
(
httpServer
,
{
path
:
'/api/socket'
,
path
:
`
${
APP_URL
}
/api/socket`
,
});
});
io
.
on
(
'connection'
,
(
socket
)
=>
{
io
.
on
(
'connection'
,
(
socket
)
=>
{
console
.
log
(
'Client connected:'
,
socket
.
id
);
console
.
log
(
'Client connected:'
,
socket
.
id
);
socket
.
on
(
'createGame'
,
()
=>
{
socket
.
on
(
'createGame'
,
()
=>
{
const
[
roomId
,
gameState
]
=
createNewGame
(
socket
.
id
);
const
[
roomId
,
gameState
]
=
createNewGame
(
socket
.
id
);
socket
.
join
(
roomId
);
socket
.
join
(
roomId
);
socket
.
emit
(
'gameCreated'
,
{
roomId
,
gameState
});
socket
.
emit
(
'gameCreated'
,
{
roomId
,
gameState
});
...
@@ -174,7 +186,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponseWithSocket) => {
...
@@ -174,7 +186,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponseWithSocket) => {
currentPlayer
:
'X'
,
currentPlayer
:
'X'
,
winner
:
null
,
winner
:
null
,
status
:
'playing'
,
status
:
'playing'
,
lastMove
:
null
,
lastMove
:
undefined
,
turnStartTime
:
Date
.
now
()
turnStartTime
:
Date
.
now
()
};
};
...
@@ -230,7 +242,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponseWithSocket) => {
...
@@ -230,7 +242,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponseWithSocket) => {
game
.
cells
[
cellKey
]
=
player
;
game
.
cells
[
cellKey
]
=
player
;
game
.
lastMove
=
{
x
,
y
,
player
};
game
.
lastMove
=
{
x
,
y
,
player
};
const
winner
=
checkWinner
(
game
.
cells
,
{
x
,
y
,
player
});
const
winner
=
checkWinner
(
game
.
cells
,
{
x
,
y
,
player
,
roomId
});
if
(
winner
)
{
if
(
winner
)
{
game
.
winner
=
winner
;
game
.
winner
=
winner
;
game
.
status
=
'finished'
;
game
.
status
=
'finished'
;
...
...
src/types/game.ts
View file @
9d2a6016
...
@@ -43,7 +43,7 @@ export interface GameState {
...
@@ -43,7 +43,7 @@ export interface GameState {
y
:
number
;
y
:
number
;
player
:
'X'
|
'O'
;
player
:
'X'
|
'O'
;
};
};
turnStartTime
?:
number
;
turnStartTime
?:
number
|
undefined
|
null
;
turnTimeLimit
:
number
;
// в миллисекундах
turnTimeLimit
:
number
;
// в миллисекундах
readyForNewGame
?:
{
readyForNewGame
?:
{
[
playerId
:
string
]:
boolean
;
[
playerId
:
string
]:
boolean
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment