wuheng пре 1 година
родитељ
комит
194ee656eb

+ 15 - 0
.vscode/launch.json

@@ -0,0 +1,15 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "command": "npm start",
+            "name": "Run npm start",
+            "request": "launch",
+            "type": "node-terminal"
+        }
+
+    ]
+}

+ 1 - 0
package-lock.json

@@ -11,6 +11,7 @@
         "@testing-library/jest-dom": "^5.16.5",
         "@testing-library/react": "^13.4.0",
         "@testing-library/user-event": "^13.5.0",
+        "lodash": "^4.17.21",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-scripts": "5.0.1",

+ 1 - 0
package.json

@@ -6,6 +6,7 @@
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",
+    "lodash": "^4.17.21",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-scripts": "5.0.1",

+ 60 - 4
src/App.js

@@ -1,10 +1,66 @@
+import { useEffect, useState } from 'react'
 import './App.css';
 import Checkerboard from './views/Checkerboard'
-
+import RoomList from './views/RoomList'
+import Login from './views/Login';
+import RevMsgContext from './provider/RevMsgContext'
+import GlobalSocketContext from './provider/GlobalSocketContext'
+import RevRoomContext from './provider/RevRoomContext'
+import { ROOM, HALL } from './Constant'
 function App() {
-  return (<>
-    <Checkerboard />
-  </>
+  const [pageState, updatePageState] = useState(0)
+  const [roomList, updateRoomList] = useState("")
+  const [roomData, updateRoomData] = useState("")
+  const [socket, setSocket] = useState(null)
+  const [userName, setUsername] = useState("")
+  useEffect(()=>{
+    if ( userName === "" ) return;
+    const socket = new WebSocket(`ws://127.0.0.1:8080/game/${userName}`) 
+    socket.onopen = ()=>{
+      socket.send(JSON.stringify( {instruct: HALL} ))
+    }
+    socket.onerror = ( error )=>{
+      console.log( error )
+    }
+    socket.onmessage = (msg)=>{
+      const revMsg = JSON.parse(msg.data)
+      switch ( revMsg.instruct ) {
+        case HALL: updateRoomList(revMsg); return updatePageState(1)
+        case ROOM: updateRoomData(revMsg); return updatePageState(2)
+        default: return updatePageState(0)
+      }
+      
+    }
+    socket.onclose = (e)=>{
+      console.log(e)
+    }
+    setSocket(socket)
+  }, [userName])
+  
+  return (
+    
+      <GlobalSocketContext.Provider value={socket}>
+        
+        {
+          (()=>{
+            if ( pageState === 0 ) {
+              return <Login setUsername={setUsername} />
+            } else if ( pageState === 1 ) {
+              return(
+                <RevMsgContext.Provider value={roomList}>
+                  <RoomList />
+                </RevMsgContext.Provider>
+              )
+            } else if ( pageState === 2 ) {
+              return (
+                  <RevRoomContext.Provider value={roomData} >
+                    <Checkerboard />
+                  </RevRoomContext.Provider>
+              )
+            }
+          })()
+        }
+      </GlobalSocketContext.Provider>
   );
 }
 

+ 3 - 0
src/Constant.js

@@ -0,0 +1,3 @@
+const ROOM = "room"
+const HALL = "hall"
+export  { ROOM, HALL }

BIN
src/assets/left.png


BIN
src/assets/right.png


+ 58 - 0
src/component/Navigation.css

@@ -0,0 +1,58 @@
+.body{
+    position: absolute;
+    transform: translate(-50%,-50%);
+    top: 50%;
+    left: 50%;
+    width: 30rem;
+    height: 30rem;
+}
+.back-hall{
+    position:absolute;
+    top: -3rem;
+    left: 0rem;
+}
+.back-hall button {
+    height: 2rem;
+    width: 6rem;
+}
+.nav-grid{
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    grid-template-rows: 4rem;
+    position: relative;
+    bottom: 2rem;
+    border: 1px solid black;
+}
+/* .nav-item{
+    border: 0.01rem solid red;
+} */
+.beginGame{
+    width: 8rem;
+    margin: 0 auto;
+    display: inherit;
+    margin-top: 1rem;
+    height: 2rem;
+    border-radius: 5%;
+}
+.avatar{
+    height: 100%;
+    width: 4rem;
+}
+.right-avatar{
+    float: right;
+}
+.user-text{
+    width: 5.9rem;
+    display: inline-block;
+    font-size: .8rem;
+    text-align: center;
+    line-height: 1.2rem;
+    overflow: hidden;
+}
+.text-box{
+    width: 5.9rem;
+    height: 100%;
+    display: inline-block;
+    vertical-align:top;
+    padding-top: .5rem;
+}

+ 65 - 0
src/component/Navigation.js

@@ -0,0 +1,65 @@
+import { useContext } from 'react';
+import './Navigation.css'
+import _ from 'lodash'
+import { HALL } from '../Constant';
+import tableData from '../views/CheckerboardData'
+import GlobalSocketContext from '../provider/GlobalSocketContext';
+const tableDataTemplate = _.cloneDeep(tableData)
+const Navigation = function ({updateTable, gameStatus, status}) {
+    const socket = useContext(GlobalSocketContext)
+    const beginGame = () => {
+        const tableDataInit = _.cloneDeep(tableDataTemplate)
+        updateTable(tableDataInit)
+        gameStatus(1)
+    }
+    const backHall = () =>{
+        socket.send(JSON.stringify({
+            instruct: HALL
+        }))
+    }
+    return (
+        <>
+            <div className='nav-grid'>
+                <div className='back-hall'>
+                    <button onClick={backHall}>返回大厅</button>
+                </div>
+                <div className='nav-item'>
+                    <img className='avatar' alt='' src={require("../assets/left.png")} />
+                    <div className='text-box'>
+                        <span className='user-text'>{(() => {
+                            switch (status) {
+                                case 0: return '未开始'
+                                case 1: return '请黑方落子'
+                                case 2: return '请白方落子'
+                                default: return '未知!'
+                            }
+                        })()}</span>
+                        <span className='user-text'>张三</span>
+                    </div>
+                </div>
+                <div className='nav-item'>
+                    <button onClick={beginGame}
+                        disabled={status === 0 ? false : true}
+                        className='beginGame'>{(() => {
+                            return status === 0 ? '开始游戏' : '游戏进行中'
+                        })()} </button>
+                </div>
+                <div className='nav-item'>
+                    <img className='avatar right-avatar' alt='' src={require("../assets/right.png")} />
+                    <div className='text-box'>
+                        <span className='user-text'>{(() => {
+                            switch (status) {
+                                case 0: return '未开始'
+                                case 1: return '请黑方落子'
+                                case 2: return '请白方落子'
+                                default: return '未知情况'
+                            }
+                        })()}</span>
+                        <span className='user-text'>李四</span>
+                    </div>
+                </div>
+            </div>
+        </>
+    )
+}
+export default Navigation

+ 3 - 0
src/provider/GlobalSocketContext.js

@@ -0,0 +1,3 @@
+import { createContext } from 'react'
+const GlobalSocketContext = createContext()
+export default GlobalSocketContext

+ 3 - 0
src/provider/RevMsgContext.js

@@ -0,0 +1,3 @@
+import { createContext } from 'react'
+const RevMsgContext = createContext()
+export default RevMsgContext

+ 3 - 0
src/provider/RevRoomContext.js

@@ -0,0 +1,3 @@
+import { createContext } from 'react'
+const RevRoomContext = createContext()
+export default RevRoomContext

+ 5 - 7
src/views/Checkerboard.css

@@ -1,13 +1,10 @@
 .checkerboard{
     position: relative;
 }
-.center{
-    position: absolute;
-    transform: translate(-50%,-50%);
-    top: 50%;
-    left: 50%;
-    width: 30rem;
-    height: 30rem;
+@media screen and (max-width: 414px) {
+    html {
+        font-size: 10px;
+    }
 }
 .black{
     background-image: url('/src/assets/point.png');
@@ -41,6 +38,7 @@
     border: 0.01rem solid rgba(0, 0, 0, 0);
     width: 2rem;
     height: 2rem;
+    /* border: 1px solid red; */
 }
 .bj-item{
     border: 0.01rem solid black;

+ 194 - 65
src/views/Checkerboard.js

@@ -1,89 +1,218 @@
 import { useState } from 'react'
 import './Checkerboard.css'
 import tableData from './CheckerboardData'
+import Navigation from '../component/Navigation'
 const bgline = [
-  ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"],
   ["x", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"],
+  ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"]
 ];
+const constant = {a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14}
 const Checkerboard = function () {
   const [table, updateTable] = useState(tableData)
-  const [userFlag, setUserFlag] = useState(0)
+  const [userStatus, setGameStatus] = useState(0)
   const goBangTouchEvent = function (x, y, value) {
+    if ( userStatus === 0 ) {
+      console.log( "棋盘未开始呢!!" )
+      return
+    }
     if (value === 0) {
-      table[x][y] = userFlag
+      table[x][y] = userStatus
       updateTable({ ...table })
-      switch (userFlag) {
-        case 1: setUserFlag(2); break;
-        case 2: setUserFlag(1); break;
-        default: setUserFlag(0)
+      switch (userStatus) {
+        case 1: setGameStatus(2); break;
+        case 2: setGameStatus(1); break;
+        default: setGameStatus(0)
+      }
+      if ( userStatus !== 0 ) {
+        win(x, y, table)
       }
     } else {
       console.log("此处已经落子了")
     }
   }
+  const win = function(x, y, table){
+    //横向
+    if( getXValue(x, y, table) ) {
+      console.log( userStatus === 1 ? "黑方赢了" : "白方赢了" )
+      setGameStatus(0)
+    }
+    //纵向
+    if( getYValue(x, y, table) ) {
+      console.log( userStatus === 1 ? "黑方赢了" : "白方赢了" )
+      setGameStatus(0)
+    }
+    //斜向
+    if ( getXyValue(x, y, table) ) {
+      console.log( userStatus === 1 ? "黑方赢了" : "白方赢了" )
+      setGameStatus(0)
+    }
+  }
+  const getXValue = function(x, y, table){
+    //向左遍历
+    let n = 0
+    for (let i = y; i < table[x].length; i++) {
+      if (table[x][i] === userStatus) {
+        n++;
+      } else if (table[x][i] === 0){
+        break
+      } else {
+        n=0
+      }
+    }
+    if ( n >= 5 ) return true
+    //向右遍历
+    n = 0
+    for (let i = y; i > 0; i--) {
+      if (table[x][i] === userStatus) {
+        n++;
+      } else if (table[x][i] === 0){
+        break
+      } else {
+        n=0
+      }
+    }
+    if ( n >= 5 ) return true
+    return false
+  }
+  const getYValue = function(x, y, table){
+    //从点击点向上遍历
+    let n = 0
+    const rTable = Object.keys(table).reverse();
+    for (const key in rTable) {
+      if ( constant[rTable[key]] <=  constant[x] ) {
+        if ( table[rTable[key]][y] === userStatus ) {
+          n++
+        } else if ( table[rTable[key]][y] === 0 ) {
+          break
+        } else {
+          n=0
+        }
+      }
+    }
+    if ( n >= 5 ) return true
+    //从点击点向下遍历
+    n=0
+    for (const key in table) {
+      if (Object.hasOwnProperty.call(table, key)) {
+        if ( constant[key] >=  constant[x] ) {
+          if ( table[key][y] === userStatus ) {
+            n++
+          } else if ( table[key][y] === 0 ) {
+            break
+          } else {
+            n=0
+          }
+        }
+      }
+    }
+    if ( n >= 5 ) return true
+    return false
+  }
+  const getXyValue = function(x, y, table){
+    //向左上角遍历
+    let n = 0 , flag = false, k = y+1
+    const tableKey = Object.keys(table).reverse();
+    for (let i = 0; i < 14; i++) {
+      if ( tableKey[i] === x ) {
+        flag = true
+      }
+      if ( flag === false ) continue
+      k--
+      if ( table[tableKey[i]][k] === userStatus ) {
+        n++
+      } else if (table[tableKey[i]][k] === 0) {
+        break;
+      } else {
+        n=0
+      }
+    }
+    if ( n >= 5 ) return true
+    
+    //向左下角遍历
+    n = 0 ;  k = y-1; flag = false; 
+    const rTableKey = Object.keys(table)
+    for (let i = 0; i < table[x].length; i++ ) {
+      if ( rTableKey[i] === x ) {
+        flag = true
+      }
+      if ( flag === false ) continue
+      k++
+      if ( table[rTableKey[i]][k] === userStatus ) {
+        n++
+      } else if (table[rTableKey[i]][k] === 0) {
+        break;
+      } else {
+        n=0
+      }
+    }
+    if ( n >= 5 ) return true
+    return false
+  }
   return (
-    <div className='center'>
-      <div className='checkerboard'>
-        <div className='board' >
-          {Object.keys(table).map((x) => {
-            return (
-              <div key={x} className='board-grid'>
-                {table[x].map((value, y) => {
-                  return (
-                    <div
-                      onClick={() => {
-                        goBangTouchEvent(x, y, value)
-                      }}
-                      onTouchEnd={()=>{
-                        goBangTouchEvent(x, y, value)
-                      }}
-                      className={(() => {
-                        switch (value) {
-                          case 0: return 'board-item'
-                          case 1: return 'black board-item'
-                          case 2: return 'white board-item'
-                          default: return 'board-item'
-                        }
-                      })()}
-                      key={y}
-                    //style={{border:'1px solid red'}}
-                    >
-                    </div>
-                  )
-                })}
-              </div>
-            )
-          })}
-        </div>
-        <div className='bj' >
-          {(() => {
-            const ret = bgline[0].map((x) => {
+    <div className='body'>
+      <Navigation updateTable={updateTable} gameStatus={setGameStatus} status={userStatus} />
+      <div className='center'>
+        <div className='checkerboard'>
+          <div className='board' >
+            {Object.keys(table).map((x) => {
               return (
-                <div key={x} className='bj-grid'>
-                  {
-                    bgline[1].map((y) => {
-                      return (
-                        <div key={y} className={(() => {
-                          let ret = 'bj-item'
-                          if (x === '14') {
-                            ret += ' bj-bottom'
-                          }
-                          if (y === 'n') {
-                            ret += ' bj-right'
+                <div key={x} className='board-grid'>
+                  {table[x].map((value, y) => {
+                    return (
+                      <div
+                        onClick={() => {
+                          goBangTouchEvent(x, y, value)
+                        }}
+                        onTouchEnd={() => {
+                          goBangTouchEvent(x, y, value)
+                        }}
+                        className={(() => {
+                          switch (value) {
+                            case 0: return 'board-item'
+                            case 1: return 'black board-item'
+                            case 2: return 'white board-item'
+                            default: return 'board-item'
                           }
-                          return ret
-                        })()}>
-                          {x === '0' && y !== 'x' ? <span className='xline'>{y}</span> : ''}
-                          {y === 'x' && x !== '0' ? <span className='yline'>{x}</span> : ''}
-                        </div>
-                      )
-                    })
-                  }
+                        })()}
+                        key={y}
+                      >
+                      </div>
+                    )
+                  })}
                 </div>
               )
-            })
-            return ret
-          })()}
+            })}
+          </div>
+          <div className='bj' >
+            {(() => {
+              const ret = bgline[0].map((x) => {
+                return (
+                  <div key={x} className='bj-grid'>
+                    {
+                      bgline[1].map((y) => {
+                        return (
+                          <div key={y} className={(() => {
+                            let ret = 'bj-item'
+                            if (x === 'n') {
+                              ret += ' bj-bottom'
+                            }
+                            if (y === '14') {
+                              ret += ' bj-right'
+                            }
+                            return ret
+                          })()}>
+                            {x === 'x' && y !== '0' ? <span className='xline'>{y}</span> : ''}
+                            {y === '0' && x !== 'x' ? <span className='yline'>{x}</span> : ''}
+                          </div>
+                        )
+                      })
+                    }
+                  </div>
+                )
+              })
+              return ret
+            })()}
+          </div>
         </div>
       </div>
     </div>

+ 1 - 0
src/views/Login.css

@@ -0,0 +1 @@
+

+ 17 - 0
src/views/Login.js

@@ -0,0 +1,17 @@
+import { useState } from "react"
+
+const Login = function({setUsername}){
+    const [username, updateUsername] = useState("")
+    return (<>
+        <div>
+            <input onChange={(e)=>{
+                console.log(e.target.value)
+                updateUsername(e.target.value)
+            }} />
+            <button onClick={()=>{
+                setUsername(username)
+            }} >设置用户名</button>
+        </div>
+    </>)
+}
+export default Login

+ 36 - 0
src/views/RoomList.css

@@ -0,0 +1,36 @@
+
+.list{
+    position: absolute;
+    transform: translate(-50%,-50%);
+    top: 50%;
+    left: 50%;
+    width: 30rem;
+    display: flex;
+    flex-wrap: wrap;
+}
+.room-list{
+    width: 9rem;
+    margin-top: 1rem;
+}
+.room-list-item{
+    border:1px solid black;
+    margin-left: 1rem;
+    padding: 1rem;
+}
+.room-list-title{
+    display: inline-block;
+    padding-left: 1rem;
+    font-size: .8rem;
+    padding-top: .8rem;
+    padding-bottom: .5rem;
+}
+
+@media screen and (max-width:414px) and (min-width:375px)  {
+    .list{
+            width: 36rem;
+        }
+    .room-list{
+        width: 12rem;
+        margin-top: 1rem;
+    }
+}

+ 73 - 0
src/views/RoomList.js

@@ -0,0 +1,73 @@
+import { useContext } from 'react'
+import './RoomList.css'
+import { ROOM } from '../Constant';
+import RevMsgContext from '../provider/RevMsgContext';
+import GlobalSocketContext from '../provider/GlobalSocketContext';
+const enuString = {
+    0 :'空位',
+    1 :'落座',
+    2 :'下棋中',
+}
+const RoomList = function () {
+    const roomList = useContext(RevMsgContext)
+    const socket = useContext(GlobalSocketContext)
+    const comeIn = function(item){
+        socket.send(JSON.stringify({
+            instruct: ROOM,
+            roomId: item.roomId
+        }))
+    }
+    return (
+        <>
+            <div className='list'>
+                {(() => {
+                    if ( roomList ) {
+                        return roomList.data.map((item) => {
+                            return (<div onClick={()=>{
+                                comeIn(item)
+                            }} key={item.roomId} className='room-list'>
+                                <div className='room-list-item'>
+                                    <span className='room-list-title'>黑方: {(()=>{
+                                        if ( item.backState !== 0 ) {
+                                            return item.backUsername
+                                        } else {
+                                            return enuString[item.backState]
+                                        }
+                                    })()}</span>
+                                    <span className='room-list-title'>白方: {(()=>{
+                                        if ( item.whiteState !== 0 ) {
+                                            return item.whiteUsername
+                                        } else {
+                                            return enuString[item.whiteState]
+                                        }
+                                    })()}</span>
+                                    <span className='room-list-title'>状态: {(()=>{
+                                        if ( item.backState === 2 && item.whiteState === 2 ) {
+                                            return "博弈中..."
+                                        } else if (item.backState === 0 && item.whiteState === 0 ) {
+                                            return "未开始"
+                                        } else if (item.backState === 1 && item.whiteState === 1 ) {
+                                            return "已就位"
+                                        } else if (item.backState === 0 && item.whiteState === 1 ) {
+                                            return "二缺一"
+                                        } else if (item.backState === 2 && item.whiteState !== 2 ) {
+                                            return "待开始"
+                                        } else if (item.backState !== 2 && item.whiteState === 2 ) {
+                                            return "待开始"
+                                        } else if (item.backState === 0 && item.whiteState === 1 ) {
+                                            return "二缺一"
+                                        } else {
+                                            return "未知"
+                                        }
+                                    })()}</span>
+                                </div>
+                            </div> )
+
+                        })
+                    }
+                })()}
+            </div>
+        </>
+    )
+}
+export default RoomList