Init
This commit is contained in:
commit
93efc42517
15 changed files with 9959 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules
|
13
build/asset-manifest.json
Normal file
13
build/asset-manifest.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.f4938759.css",
|
||||
"main.js": "/static/js/main.ee416b6e.js",
|
||||
"index.html": "/index.html",
|
||||
"main.f4938759.css.map": "/static/css/main.f4938759.css.map",
|
||||
"main.ee416b6e.js.map": "/static/js/main.ee416b6e.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.f4938759.css",
|
||||
"static/js/main.ee416b6e.js"
|
||||
]
|
||||
}
|
1
build/index.html
Normal file
1
build/index.html
Normal file
|
@ -0,0 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document</title><script defer="defer" src="/static/js/main.ee416b6e.js"></script><link href="/static/css/main.f4938759.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
|
4
build/static/css/main.f4938759.css
Normal file
4
build/static/css/main.f4938759.css
Normal file
File diff suppressed because one or more lines are too long
1
build/static/css/main.f4938759.css.map
Normal file
1
build/static/css/main.f4938759.css.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"static/css/main.f4938759.css","mappings":"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","sources":["styles.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n* {\n box-sizing: border-box;\n}\n\nbody {\n font-family: sans-serif;\n margin: 20px;\n padding: 0;\n}\n\nh1 {\n margin-top: 0;\n font-size: 22px;\n}\n\nh2 {\n margin-top: 0;\n font-size: 20px;\n}\n\nh3 {\n margin-top: 0;\n font-size: 18px;\n}\n\nh4 {\n margin-top: 0;\n font-size: 16px;\n}\n\nh5 {\n margin-top: 0;\n font-size: 14px;\n}\n\nh6 {\n margin-top: 0;\n font-size: 12px;\n}\n\ncode {\n font-size: 1.2em;\n}\n\nul {\n padding-inline-start: 20px;\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody {\n font-family: sans-serif;\n margin: 20px;\n padding: 0;\n}\n\n.square {\n border: 1px solid #999;\n float: left;\n font-size: 24px;\n font-weight: bold;\n line-height: 34px;\n height: 34px;\n margin-right: -1px;\n margin-top: -1px;\n padding: 0;\n text-align: center;\n width: 34px;\n}\n\n.board-row:after {\n clear: both;\n content: '';\n display: table;\n}\n\n.status {\n margin-bottom: 10px;\n}\n.game {\n display: flex;\n flex-direction: row;\n}\n\n.game-info {\n margin-left: 20px;\n}\n\n.arrow {\n font-size: '20px';\n padding: '10px';\n cursor: 'pointer';\n}"],"names":[],"sourceRoot":""}
|
3
build/static/js/main.ee416b6e.js
Normal file
3
build/static/js/main.ee416b6e.js
Normal file
File diff suppressed because one or more lines are too long
39
build/static/js/main.ee416b6e.js.LICENSE.txt
Normal file
39
build/static/js/main.ee416b6e.js.LICENSE.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
1
build/static/js/main.ee416b6e.js.map
Normal file
1
build/static/js/main.ee416b6e.js.map
Normal file
File diff suppressed because one or more lines are too long
31
package.json
Normal file
31
package.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "react.dev",
|
||||
"version": "0.0.0",
|
||||
"main": "/src/index.js",
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-scripts": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tailwindcss": "^3.4.15"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
11
public/index.html
Normal file
11
public/index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
168
src/App.js
Normal file
168
src/App.js
Normal file
|
@ -0,0 +1,168 @@
|
|||
import { useState } from "react";
|
||||
|
||||
function Square({ row, column, value, clickHandler }) {
|
||||
let buttonClass = ""
|
||||
switch (value){
|
||||
case "X":
|
||||
buttonClass = "square bg-amber-200 "
|
||||
break;
|
||||
case "O":
|
||||
buttonClass = "square bg-violet-300"
|
||||
break;
|
||||
default:
|
||||
buttonClass = "square bg-white"
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<button
|
||||
className={buttonClass}
|
||||
onClick={() => clickHandler(row, column)}
|
||||
>
|
||||
{value}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function SquareRow({ rowId, rows, clickHandler }) {
|
||||
const items =
|
||||
rows.map((ele, index) =>
|
||||
<Square
|
||||
key={index}
|
||||
row={rowId}
|
||||
column={index}
|
||||
value={ele}
|
||||
clickHandler={clickHandler}
|
||||
/>
|
||||
);
|
||||
|
||||
return <>{items}</>;
|
||||
}
|
||||
|
||||
export default function Map({ mapSize }) {
|
||||
// Config Here
|
||||
const ticTacToeMaxMapSize = 6
|
||||
|
||||
if (mapSize == undefined) {
|
||||
mapSize = 3;
|
||||
}
|
||||
const [map, setMap] = useState(
|
||||
Array(mapSize).fill(null)
|
||||
.map(() => Array(mapSize).fill(null))
|
||||
);
|
||||
const [currentMove, setCurrentMove] = useState(0);
|
||||
const xIsNext = currentMove % 2 == 0;
|
||||
const [winner, setWinner] = useState(null);
|
||||
const [history, setHistory] = useState([Array(mapSize).fill(null)
|
||||
.map(() => Array(mapSize).fill(null))])
|
||||
|
||||
function updateMap(nextMap) {
|
||||
setHistory([...history, nextMap])
|
||||
setMap(nextMap)
|
||||
}
|
||||
|
||||
function handleClick(row, column) {
|
||||
if (map[row][column] != null || winner != null) {
|
||||
return
|
||||
}
|
||||
const nextMap = map.map(row => [...row]);
|
||||
if (xIsNext) {
|
||||
nextMap[row][column] = 'X'
|
||||
} else {
|
||||
nextMap[row][column] = 'O'
|
||||
}
|
||||
updateMap(nextMap)
|
||||
setCurrentMove(currentMove + 1)
|
||||
if (calculateWinner(row, column,nextMap)) {
|
||||
setWinner(nextMap[row][column])
|
||||
}
|
||||
}
|
||||
|
||||
function calculateWinner(row, column,map) {
|
||||
const who = map[row][column]; // 当前玩家标记
|
||||
const winNeed = mapSize > ticTacToeMaxMapSize ? 5 : mapSize; // 棋盘大小(>5五子棋)
|
||||
|
||||
// 横向检查
|
||||
let horizontal = 1;
|
||||
for (let hLeft = column - 1; hLeft >= 0; hLeft--) {
|
||||
if (map[row][hLeft] !== who) break;
|
||||
horizontal++;
|
||||
}
|
||||
for (let hRight = column + 1; hRight < mapSize; hRight++) {
|
||||
if (map[row][hRight] !== who) break;
|
||||
horizontal++;
|
||||
}
|
||||
if (horizontal >= winNeed) return true;
|
||||
|
||||
// 纵向检查
|
||||
let vertical = 1;
|
||||
for (let vUp = row - 1; vUp >= 0; vUp--) {
|
||||
if (map[vUp][column] !== who) break;
|
||||
vertical++;
|
||||
}
|
||||
for (let vDown = row + 1; vDown < mapSize; vDown++) {
|
||||
if (map[vDown][column] !== who) break;
|
||||
vertical++;
|
||||
}
|
||||
if (vertical >= winNeed) return true;
|
||||
|
||||
// 主对角线 (左上到右下)
|
||||
let mainDiagonal = 1;
|
||||
for (let dUp = 1; row - dUp >= 0 && column - dUp >= 0; dUp++) {
|
||||
if (map[row - dUp][column - dUp] !== who) break;
|
||||
mainDiagonal++;
|
||||
}
|
||||
for (let dDown = 1; row + dDown < mapSize && column + dDown < mapSize; dDown++) {
|
||||
if (map[row + dDown][column + dDown] !== who) break;
|
||||
mainDiagonal++;
|
||||
}
|
||||
if (mainDiagonal >= winNeed) return true;
|
||||
|
||||
// 副对角线 (右上到左下)
|
||||
let antiDiagonal = 1;
|
||||
for (let dUp = 1; row - dUp >= 0 && column + dUp < mapSize; dUp++) {
|
||||
if (map[row - dUp][column + dUp] !== who) break;
|
||||
antiDiagonal++;
|
||||
}
|
||||
for (let dDown = 1; row + dDown < mapSize && column - dDown >= 0; dDown++) {
|
||||
if (map[row + dDown][column - dDown] !== who) break;
|
||||
antiDiagonal++;
|
||||
}
|
||||
if (antiDiagonal >= winNeed) return true;
|
||||
|
||||
// 如果没有满足条件,返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
const mapEle = map.map((ele, index) => (
|
||||
<div key={`row-${index}`} className="board-row"> {/* Unique key for each row */}
|
||||
<SquareRow rowId={index} rows={ele} clickHandler={handleClick} />
|
||||
</div>
|
||||
));
|
||||
|
||||
function handleLeftClick() {
|
||||
if (currentMove > 0) {
|
||||
setMap(history[currentMove - 1]);
|
||||
setCurrentMove(currentMove - 1);
|
||||
setHistory(history.slice(0, -1));
|
||||
setWinner(null);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-xl bg-sky-50 shadow-xl table items-center space-y-2 container mx-auto content-center">
|
||||
<p className="font-sans text-2xl text-center ">{mapSize > ticTacToeMaxMapSize ? "五子棋" : "井字棋"}模式</p>
|
||||
<p className="text-xl text-center ">现在是 {xIsNext ? "X" : "O"} 移动</p>
|
||||
<div className="flex flex-row justify-center items-center">
|
||||
<div className="board" >
|
||||
{mapEle}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-center items-center">
|
||||
<button className="bg-cyan-50 shadow-md rounded-md text-lg" onClick={handleLeftClick}>
|
||||
←回到上一个
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-xl text-center">{winner != null ? winner + "赢了" : ""} </p>
|
||||
</div>
|
||||
);
|
||||
}
|
12
src/index.js
Normal file
12
src/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React, { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./styles.css";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
const root = createRoot(document.getElementById("root"));
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<App mapSize={8}/>
|
||||
</StrictMode>
|
||||
);
|
99
src/styles.css
Normal file
99
src/styles.css
Normal file
|
@ -0,0 +1,99 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
margin: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin-top: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
margin: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.square {
|
||||
border: 1px solid #999;
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
line-height: 34px;
|
||||
height: 34px;
|
||||
margin-right: -1px;
|
||||
margin-top: -1px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 34px;
|
||||
}
|
||||
|
||||
.board-row:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.game {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.game-info {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: '20px';
|
||||
padding: '10px';
|
||||
cursor: 'pointer';
|
||||
}
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
Loading…
Reference in a new issue