console
const Game = {
restart() {
this.reset()
const level = this.config.level
const positionParam = (1 / (level - 1)) * 100
const imgUrl = (this.config.imgUrl = `https://h5games-dom.oss-cn-hangzhou.aliyuncs.com/puzzle/${~~(
Math.random() * 5
)}.png`)
const backgroundImg = document.querySelector("#background-img")
backgroundImg.src = imgUrl
const styleSheet = (this.config.imgCutStyle = document.styleSheets[0])
let firstRule = styleSheet.rules[0]
if (firstRule.selectorText === ".custom") styleSheet.deleteRule(0)
let scale = (1 / this.config.level) * 100 + "%"
styleSheet.insertRule(
`.custom {
width: ${scale};
height: ${scale};
background: url(${imgUrl}) no-repeat;
background-size: ${this.config.level * 100}%; }`,
0
)
backgroundImg.onload = () => {
for (let i = 0, j = Math.pow(this.config.level, 2); i < j; i++) {
this.config.cutImgsCountArray.push(i)
}
let cutImgsStr = ""
this.getInitialSort()
this.config.cutImgsCountArray.forEach((num, index) => {
this.config.trueTransforms.push(
`translate(${(index % level) * 100}%, ${
(~~(index / level) % level) * 100
}%)`
)
const transform = `transform: translate(${
(num % level) * 100
}%, ${(~~(num / level) % level) * 100}%);`
const backgroundPosition = `background-position: ${
(index % level) * positionParam
}% ${(~~(index / level) % level) * positionParam}%;`
cutImgsStr += `<button class="cut-img custom" data-index=${index} onclick="Game.click(event)" style="${
transform + backgroundPosition
}"></button>`
})
document.querySelector("#cut-imgs").innerHTML = cutImgsStr
this.instance.cutImgs = document.querySelectorAll(".cut-img")
}
},
click(e) {
const index = e.target.dataset.index
if (this.tool.currentIndex === -1) {
this.getCutImg(index).classList.add("selected")
this.tool.currentIndex = index
return
}
const oldCutImg = this.getCutImg(this.tool.currentIndex)
if (this.tool.currentIndex === index) {
this.getCutImg(index).classList.remove("selected")
this.tool.currentIndex = -1
} else {
const newCutImg = this.getCutImg(index)
const [a, b] = [
newCutImg.style.transform,
oldCutImg.style.transform,
]
oldCutImg.style.transform = a
newCutImg.style.transform = b
this.tool.currentIndex = -1
setTimeout(() => {
download.style.display = "none"
oldCutImg.classList.remove("selected")
newCutImg.classList.remove("selected")
if (this.checkNoWin()) console.log("NoWin")
else {
download.style.display = "block"
alert("win")
}
}, 500)
}
},
getCutImg(index) {
return this.instance.cutImgs[index]
},
getInitialSort() {
const cal = (arr) => {
let length = arr.length
let reverse = 0
for (let i = 0; i < length - 1; i++) {
let n = arr[i]
for (let j = i + 1; j < length; j++) {
let m = arr[j]
if (n > m) reverse += 1
}
}
return reverse
}
const randomSort = (a, b) => (Math.random() > 0.5 ? -1 : 1)
while (1) {
if (cal(this.config.cutImgsCountArray.sort(randomSort)) % 2 === 0)
return
}
},
checkNoWin() {
let cutImgs = this.instance.cutImgs
let trueTransforms = this.config.trueTransforms
for (let i = 0, j = this.instance.cutImgs.length; i < j; i++) {
if (cutImgs[i].style.transform !== trueTransforms[i]) return true
}
},
reset() {
let resetParam = this.resetParam
this.config = this.deepCopy(resetParam.config)
this.instance = this.deepCopy(resetParam.instance)
this.tool = this.deepCopy(resetParam.tool)
download.style.display = "none"
},
deepCopy(obj) {
return JSON.parse(JSON.stringify(obj))
},
openImage() {
window.open(this.config.imgUrl)
},
resetParam: {
config: {
level: 3,
cutImgsCountArray: [],
trueTransforms: [],
imgCutStyle: {},
imgUrl: "",
},
instance: {
cutImgs: [],
},
tool: {
currentIndex: -1,
},
},
}
Game.restart()
<header>
<button onclick="Game.restart()">重新开始</button>
<button id="download" onclick="Game.openImage()">新标签打开图片</button>
</header>
<main>
<section class="game-area">
<img id="background-img" src="#" alt="backgroundImg" />
<div id="cut-imgs"></div>
</section>
</main>
.cut-img {
position: absolute;
top: 0;
left: 0;
border: 0;
padding: 0;
transition: transform 0.3s linear;
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
header,
main,
footer {
width: 50%;
}
header {
display: flex;
justify-content: space-between;
}
main {
position: relative;
height: auto;
}
.game-area {
position: relative;
height: auto;
}
#background-img {
max-width: 100%;
max-height: 100%;
vertical-align: top;
opacity: 0;
}
#cut-imgs {
position: absolute;
top: 0;
left: 0;
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
button:focus {
outline: none;
}
.selected {
border: 1px solid blue;
}
#download {
display: none;
}