Commit 07bf1d22 authored by Point 郑海洋's avatar Point 郑海洋 👾

first commit

parents
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
BROWSER=none
ESLINT=1
{
"extends": "eslint-config-umi"
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
/dist
# misc
.DS_Store
# umi
.umi
.umi-production
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
// ref: https://umijs.org/config/
export default {
treeShaking: true,
plugins: [
// ref: https://umijs.org/plugin/umi-plugin-react.html
['umi-plugin-react', {
antd: false,
dva: {
immer: true
},
dynamicImport: false,
title: 'dva-pro',
dll: false,
routes: {
exclude: [
/components\//,
],
},
}],
],
}
{
"private": true,
"scripts": {
"start": "umi dev",
"build": "umi build",
"test": "umi test",
"lint": "eslint --ext .js src mock tests",
"precommit": "lint-staged"
},
"dependencies": {
"dva-logger": "^1.0.0",
"less": "^3.9.0",
"less-loader": "^5.0.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"styled-components": "^4.3.2"
},
"devDependencies": {
"babel-eslint": "^9.0.0",
"eslint": "^5.4.0",
"eslint-config-umi": "^1.4.0",
"eslint-plugin-flowtype": "^2.50.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.11.1",
"husky": "^0.14.3",
"lint-staged": "^7.2.2",
"react-test-renderer": "^16.7.0",
"umi": "^2.7.7",
"umi-plugin-react": "^1.9.10"
},
"lint-staged": {
"*.{js,jsx}": [
"eslint --fix",
"git add"
]
},
"engines": {
"node": ">=8.0.0"
}
}
export const dva = {
config: {
onError(e) {
e.preventDefault();
console.error(e.message);
},
},
plugins: [
require('dva-logger')(),
],
};
.content {
width: 336px;
height: 336px;
margin-top: 5px;
margin-left:5px;
float: left;
}
import styled from 'styled-components';
const Box =styled.div `
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 100px;
height: 100px;
padding: 5px;
text-align: center;
width: 100px;
`
function BoxMaster(props){
// console.log("props",props)
const handelClick =(value)=>{
// console.log("value",value)
// console.log("handelClick")
// 判断游戏是否有胜利者
if(props.winer) return
// 判断是否重复点击
if(!reClick(value)) {
// 更新整体
props.dispatch({
type:'main/updateObjFn',
id:value.value,
flage:value.nowFliage,
datasource:props.datasource
})
// 保存每一步操作
props.dispatch({
type:'main/saveActionFn',
num:props.num,
id:value.value,
flage:value.nowFliage,
list:props.datasource,
actionData:props.actionData
})
}
}
// 是否重复点击
function reClick(value) {
let tempObj= value.datasource.find((item,index)=>{return item.value === value.value})
if(tempObj && tempObj.flage) {
return true
}else{
return false
}
}
return (
<Box onClick={()=>handelClick(props)} >
{props.flage}
</Box>
)
}
export default BoxMaster
html, body, #root {
height: 100%;
}
body {
margin: 0;
}
import BasicLayout from '..';
import renderer from 'react-test-renderer';
describe('Layout: BasicLayout', () => {
it('Render correctly', () => {
const wrapper = renderer.create(<BasicLayout />);
expect(wrapper.root.children.length).toBe(1);
const outerLayer = wrapper.root.children[0];
expect(outerLayer.type).toBe('div');
const title = outerLayer.children[0];
expect(title.type).toBe('h1');
expect(title.children[0]).toBe('Yay! Welcome to umi!');
});
});
.normal {
font-family: Georgia, sans-serif;
text-align: center;
}
.title {
font-size: 2.5rem;
font-weight: normal;
letter-spacing: -1px;
background: darkslateblue;
padding: .6em 0;
color: white;
margin: 0;
}
import styles from './index.css';
function BasicLayout(props) {
return (
<div className={styles.normal}>
<h1 className={styles.title}>Yay! Welcome to umi!</h1>
{props.children}
</div>
);
}
export default BasicLayout;
export default {
namespace: 'main',
state: {
nowFlage:"X",
list: [
{
value:1,
flage:null,
},{
value:2,
flage:null,
},{
value:3,
flage:null,
},{
value:4,
flage:null,
},{
value:5,
flage:null,
},{
value:6,
flage:null,
},{
value:7,
flage:null,
},{
value:8,
flage:null,
},{
value:9,
flage:null,
}],
num:0,
actionData:[],
gameStatus:false,
winer:null
},
reducers: {
updateFlage(state,action) {
return {
...state,
nowFlage:action.flage,
gameStatus:true
}
},
updateSelectOne(state,action) {
return {
...state,
list:action.list
}
},
updateAction(state,action) {
return {
...state,
actionData:action.actionData,
num:action.num
}
},
updayeRenderData(state,action) {
return {
...state,
list:action.renderList,
actionData:action.actionData,
num:action.num,
gameStatus:action.gameStatus,
}
},
updateWiner(state,action) {
return {
...state,
winer:action.winer,
gameStatus:false
}
}
},
effects: {
// 更新对象
*updateObjFn({id,flage,datasource},{call,put,select}) {
// 更新当前点击的对象的标记
let tempArry=JSON.parse(JSON.stringify(datasource))
let index= tempArry.findIndex((item,index)=>{ return item.value === id})
tempArry[index].flage=flage
yield put({
type:"updateSelectOne",
list:tempArry
})
// 更新全局的标记
yield put({
type:'updateFlage',
flage:flage==="X"?"O":"X"
})
},
// 保存每一步的操作
*saveActionFn({num,id,flage,list,actionData},{call,put,select}) {
num = num+1
let tempArry = JSON.parse(JSON.stringify(list)) // 深拷贝
let index = tempArry.findIndex((item,index) => { return item.value === id})
tempArry[index].flage = flage
actionData.push({
key:num,
value:tempArry
})
// console.log("actionData",actionData)
yield put({
type:'updateAction',
num:num,
actionData:actionData
})
},
// 回退操作
*updateRenderDataFn({flage,key,actionData,list},{call,put,select}) {
let tempList=JSON.parse(JSON.stringify(actionData))
let tempData = []
let tempActionData=[]
let num = 0
let gameStatus = true
if(!flage) {
let index = tempList.findIndex((item,index)=>{return item.key === key})
tempData = tempList.find((item,index)=>{return item.key === key}).value
tempActionData = tempList.slice(0,index+1)
num = index+1
}else{
tempData = list.map((item,index)=>{
let temp={}
temp.value = item.value
temp.flage = null
return temp
})
num = 0
gameStatus = false
}
yield put({
type:'updayeRenderData',
renderList:tempData,
actionData:tempActionData,
num:num,
gameStatus:gameStatus,
})
},
// 更新获胜者
*updateWinerFn({winer},{call,put,select}) {
yield put({
type:"updateWiner",
winer:winer
})
}
},
subscriptions: {
},
};
import Index from '..';
import renderer from 'react-test-renderer';
describe('Page: index', () => {
it('Render correctly', () => {
const wrapper = renderer.create(<Index />);
expect(wrapper.root.children.length).toBe(1);
const outerLayer = wrapper.root.children[0];
expect(outerLayer.type).toBe('div');
expect(outerLayer.children.length).toBe(2);
});
});
import styles from './index.less';
import { useEffect } from 'react';
import Box from '@/component/box';
import { connect } from 'dva';
function Main({ dispatch, list,nowFlage,num,actionData,gameStatus,winer }) {
useEffect(()=>{
if(!gameStatus) return
let twoDArry = renderArry(list)
if(!twoDArry) return
let reData = checkWin(twoDArry)
if(reData && reData.status==='win') {
dispatch({
type:"main/updateWinerFn",
winer:reData.winer
})
}
})
// 组装二维数组
function renderArry(dataList) {
var tempArry=[]
let len = dataList.length
let n = 3; //假设每行显示3个
let lineNum = len % 3 === 0 ? len / 3 : Math.floor( (len / 3) + 1 );
for(let i=0;i<lineNum;i++) {
let temp = dataList.slice(i*n, i*n+n);
tempArry.push(temp);
}
return tempArry
}
// 判断输赢
function checkWin(twoDArry) {
// 判断第一行
if(twoDArry[0][0].flage !=null && twoDArry[0][1].flage !=null && twoDArry[0][2].flage !=null && twoDArry[0][0].flage === twoDArry[0][1].flage && twoDArry[0][1].flage === twoDArry[0][2].flage) {
return {status:'win',winer:twoDArry[0][0]}
}
// 判断第二行
if(twoDArry[1][0].flage !=null && twoDArry[1][1].flage !=null && twoDArry[1][2].flage !=null && twoDArry[1][0].flage === twoDArry[1][1].flage && twoDArry[1][1].flage === twoDArry[1][2].flage) {
return {status:'win',winer:twoDArry[1][0]}
}
// 判断第三行
if(twoDArry[2][0].flage !=null && twoDArry[2][1].flage !=null && twoDArry[2][2].flage !=null && twoDArry[2][0].flage === twoDArry[2][1].flage && twoDArry[2][1].flage === twoDArry[2][2].flage) {
return {status:'win',winer:twoDArry[2][0]}
}
// 判断第一列
if(twoDArry[0][0].flage !=null && twoDArry[1][0].flage !=null && twoDArry[2][0].flage !=null && twoDArry[0][0].flage === twoDArry[1][0].flage && twoDArry[1][0].flage === twoDArry[2][0].flage) {
return {status:'win',winer:twoDArry[0][0]}
}
// 判断第二列
if(twoDArry[0][1].flage !=null && twoDArry[1][1].flage !=null && twoDArry[2][1].flage !=null && twoDArry[0][1].flage === twoDArry[1][1].flage && twoDArry[1][1].flage === twoDArry[2][1].flage) {
return {status:'win',winer:twoDArry[0][1]}
}
// 判断第三列
if(twoDArry[0][2].flage !=null && twoDArry[1][2].flage !=null && twoDArry[2][2].flage !=null && twoDArry[0][2].flage === twoDArry[1][2].flage && twoDArry[1][2].flage === twoDArry[2][2].flage) {
return {status:'win',winer:twoDArry[0][2]}
}
// 判断交叉左上角到右下角
if(twoDArry[0][0].flage !=null && twoDArry[1][1].flage !=null && twoDArry[2][2].flage !=null && twoDArry[0][0].flage === twoDArry[1][1].flage && twoDArry[1][1].flage === twoDArry[2][2].flage) {
return {status:'win',winer:twoDArry[0][0]}
}
// 判断交叉右上角到左下角
if(twoDArry[0][2].flage !=null && twoDArry[1][1].flage !=null && twoDArry[2][0].flage !=null && twoDArry[0][2].flage === twoDArry[1][1].flage && twoDArry[1][1].flage === twoDArry[2][0].flage) {
return {status:'win',winer:twoDArry[0][2]}
}
}
function handleChangeData(flage,key,actionData,list) {
dispatch({
type:'main/updateWinerFn',
winer:null
})
dispatch({
type:'main/updateRenderDataFn',
key:key,
actionData:actionData,
flage:flage,
list:list
})
}
return (
<div>
<div className={styles.content}>
{
list.map((item,index)=>{
return (
<Box
key={item.value}
value={item.value}
nowFliage={nowFlage}
dispatch={dispatch}
datasource={list}
flage={item.flage}
num={num}
actionData={actionData}
winer={winer}
/>
)
})
}
</div>
<div className={styles.rightBox}>
<p>Next player: {nowFlage} </p>
{
winer ? <p>Winer is {winer.flage}</p> : ""
}
<ul>
<li>
<button onClick={()=>handleChangeData(true,false,false,list)}> Go to Game Start</button>
</li>
{
actionData.map((item,index)=>{
return (
<li key={item.key} value={item.key} >
<button className={styles.numLi} onClick={()=>handleChangeData(false,item.key,actionData,list)}> Go to move #{item.key}</button>
</li>
)
})
}
</ul>
</div>
</div>
);
}
function mapStateToProps(state) {
const { nowFlage,list,num,actionData,gameStatus,winer } = state.main;
return {
nowFlage,
list,
num,
actionData,
gameStatus,
winer
};
}
export default connect(mapStateToProps)(Main);
@import '~@/assets/global.less';
.rightBox {
width: 400px;
height: auto;
float: left;
li {
list-style: none;
}
.numLi {
height: 35px;
line-height: 35px;
border: 1px solid #999;
}
}
/**
* 不是真实的 webpack 配置,仅为兼容 webstorm 和 intellij idea 代码跳转
* ref: https://github.com/umijs/umi/issues/1109#issuecomment-423380125
*/
module.exports = {
resolve: {
alias: {
'@': require('path').resolve(__dirname, 'src'),
},
extraPostCSSPlugins:['css','less']
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment