Skip to content

Commit 38dd2a9

Browse files
author
linyisonger
committed
fix #22 啊? 写完了嘛
1 parent ac8fcbd commit 38dd2a9

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

103.黑白棋.html

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<link rel="stylesheet" href="./assets/global.css">
9+
<style>
10+
body {
11+
display: flex;
12+
align-items: center;
13+
justify-content: center;
14+
height: 100vh;
15+
}
16+
17+
.reversi-board {
18+
width: 100vmin;
19+
height: 100vmin;
20+
background-color: #059a14;
21+
padding: 20px;
22+
position: relative;
23+
box-sizing: border-box;
24+
}
25+
26+
.reversi-board .grid {
27+
position: absolute;
28+
border: 1px solid #000;
29+
box-sizing: border-box;
30+
display: flex;
31+
align-items: center;
32+
justify-content: center;
33+
}
34+
35+
.reversi-board .grid.allowSelect {
36+
position: absolute;
37+
left: 0;
38+
right: 0;
39+
bottom: 0;
40+
top: 0;
41+
border: 2px solid #f0f;
42+
}
43+
44+
.reversi-board .piece {
45+
width: 90%;
46+
height: 90%;
47+
border-radius: 50%;
48+
}
49+
50+
.reversi-board .piece.W {
51+
background: #fff;
52+
}
53+
54+
.reversi-board .piece.B {
55+
background: #000;
56+
}
57+
58+
.reversi-board .game-over {
59+
position: absolute;
60+
left: 0;
61+
top: 0;
62+
right: 0;
63+
bottom: 0;
64+
background-color: rgba(255, 255, 255, .8);
65+
display: flex;
66+
justify-content: center;
67+
align-items: center;
68+
flex-direction: column;
69+
}
70+
71+
.reversi-board .game-over .title {
72+
font-size: 40px;
73+
font-weight: bold;
74+
color: #fdad19;
75+
}
76+
77+
.reversi-board .game-over .subtitle {
78+
font-size: 20px;
79+
margin-top: 10px;
80+
}
81+
82+
.reversi-board .game-over .maintitle {
83+
font-size: 22px;
84+
margin-top: 20px;
85+
}
86+
</style>
87+
</head>
88+
89+
<body>
90+
<div class="reversi-board"></div>
91+
<script type="module">
92+
// String To V2
93+
function strToV2(str) {
94+
let x = +str.split('-')?.[0]
95+
let y = +str.split('-')?.[1]
96+
return { x, y }
97+
}
98+
// V2 To String
99+
function v2ToStr(x, y) {
100+
return `${x}-${y}`
101+
}
102+
103+
let reversiBoardDOM = document.querySelector(".reversi-board")
104+
let sideLength = (reversiBoardDOM.clientWidth - 40) / 8 // 边长
105+
let operatePlayer = 'B'; // 操作的颜色
106+
let lastPos = [] // 操作点位
107+
let reversiBoard = new Proxy({}, {
108+
get(obj, prop) {
109+
return obj[prop];
110+
},
111+
set(obj, prop, val) {
112+
let pos = prop // 位置
113+
let lastPiece = obj[prop] // 上次的棋子
114+
let { x, y } = strToV2(prop)
115+
let color = val
116+
let gridDOM = reversiBoardDOM.querySelector(`.grid[data-x="${x}"][data-y="${y}"]`)
117+
obj[prop] = val // 落子
118+
119+
if (!lastPiece) { // 为空落子
120+
// 旗子元素
121+
let pieceDOM = document.createElement('div')
122+
pieceDOM.classList.add('piece')
123+
pieceDOM.classList.add(color)
124+
gridDOM.appendChild(pieceDOM)
125+
}
126+
else {
127+
let pieceDOM = gridDOM.querySelector('.piece')
128+
pieceDOM.classList.remove('W')
129+
pieceDOM.classList.remove('B')
130+
pieceDOM.classList.add(color)
131+
}
132+
133+
return true
134+
}
135+
})
136+
// 初始化棋盘
137+
for (let y = 0; y < 8; y++) {
138+
for (let x = 0; x < 8; x++) {
139+
let gridDOM = document.createElement("div")
140+
gridDOM.classList.add('grid')
141+
gridDOM.style.top = sideLength * y + 20 + 'px'
142+
gridDOM.style.left = sideLength * x + 20 + 'px'
143+
gridDOM.style.width = sideLength + 'px';
144+
gridDOM.style.height = sideLength + 'px';
145+
gridDOM.setAttribute('data-x', x)
146+
gridDOM.setAttribute('data-y', y)
147+
gridDOM.addEventListener("click", (e) => {
148+
if (e.target.classList.contains("allowSelect")) { // 允许选择
149+
let x = e.target.getAttribute('data-x')
150+
let y = e.target.getAttribute('data-y')
151+
let allowSelectPos = lastPos.filter(op => op[op.length - 1] == v2ToStr(x, y))
152+
allowSelectPos.forEach((arr) => {
153+
arr.forEach(key => {
154+
reversiBoard[key] = operatePlayer;
155+
})
156+
})
157+
reversiBoardDOM.querySelectorAll('.allowSelect').forEach(dom => dom.classList.remove('allowSelect'))
158+
operatePlayer = 'W';
159+
nextPlayerOperate()
160+
}
161+
})
162+
reversiBoardDOM.appendChild(gridDOM)
163+
}
164+
}
165+
166+
167+
// 初始化棋子
168+
reversiBoard['3-3'] = 'W'
169+
reversiBoard['4-3'] = 'B'
170+
reversiBoard['3-4'] = 'B'
171+
reversiBoard['4-4'] = 'W'
172+
173+
174+
// 加载可以操作的点位
175+
function nextPlayerOperate() {
176+
showReversiBoard();
177+
let pos = []
178+
for (const key in reversiBoard) {
179+
if (reversiBoard[key] === operatePlayer) {
180+
let { x, y } = strToV2(key)
181+
pos.push(...find8Direction(x, y))
182+
}
183+
}
184+
185+
if (pos.length === 0) {
186+
if (lastPos.length === 0) {
187+
console.log('游戏结束');
188+
showGameOver()
189+
return
190+
}
191+
}
192+
else if (operatePlayer === "B") { // 玩家提供可操作的点位
193+
// 渲染到页面
194+
let allowSelect = pos.map(a => a[a.length - 1])
195+
allowSelect.forEach((key) => {
196+
let { x, y } = strToV2(key)
197+
reversiBoardDOM.querySelector(`.grid[data-x="${x}"][data-y="${y}"]`).classList.add('allowSelect')
198+
})
199+
lastPos = pos;
200+
return;
201+
}
202+
else if (operatePlayer === 'W') { // 机器人
203+
let allowSelect = pos.sort((a, b) => a.length - b.length);
204+
let selected = allowSelect[allowSelect.length - 1]
205+
let key = selected[selected.length - 1]
206+
allowSelect.filter(arr => arr[arr.length - 1] === key).forEach(arr => {
207+
arr.forEach(key => {
208+
reversiBoard[key] = operatePlayer;
209+
})
210+
})
211+
}
212+
operatePlayer = operatePlayer == "B" ? "W" : "B"
213+
lastPos = pos;
214+
nextPlayerOperate();
215+
}
216+
217+
// 查询一个方向可以操作点位
218+
function find1Direction(sx, sy, dx, dy) {
219+
let pos = []
220+
let cx = sx + dx;
221+
let cy = sy + dy;
222+
while (-1 < cx && cx < 8 && -1 < cy && cy < 8) {
223+
let key = v2ToStr(cx, cy)
224+
if (!reversiBoard[key]) return pos.length ? pos.concat(key) : []
225+
else if (reversiBoard[key] === operatePlayer) return []
226+
else pos.push(key)
227+
cx += dx
228+
cy += dy
229+
}
230+
return []
231+
}
232+
233+
// 查询八个方向可以操作点位
234+
function find8Direction(cx, cy) {
235+
let sx = cx;
236+
let sy = cy;
237+
let dt = find1Direction(sx, sy, 0, -1);
238+
let db = find1Direction(sx, sy, 0, 1);
239+
let dl = find1Direction(sx, sy, -1, 0);
240+
let dr = find1Direction(sx, sy, 1, 0);
241+
let dtl = find1Direction(sx, sy, -1, -1);
242+
let dtr = find1Direction(sx, sy, 1, -1);
243+
let dbl = find1Direction(sx, sy, -1, 1);
244+
let dbr = find1Direction(sx, sy, 1, 1);
245+
return [
246+
dt, db, dl, dr, dtl, dtr, dbl, dbr
247+
].filter(a => a.length)
248+
}
249+
250+
// 展示游戏结束
251+
function showGameOver() {
252+
let gameOverDOM = document.createElement("div")
253+
let gameOverTitleDOM = document.createElement("div")
254+
let gameOverSubTitleDOM = document.createElement("div")
255+
let gameOverMainTitleDOM = document.createElement("div")
256+
257+
let pieceList = Object.values(reversiBoard)
258+
let blackCount = pieceList.filter(p => p === "B").length
259+
let whiteCount = pieceList.filter(p => p === "W").length
260+
261+
gameOverDOM.classList.add('game-over')
262+
gameOverTitleDOM.classList.add('title')
263+
gameOverSubTitleDOM.classList.add('subtitle')
264+
gameOverMainTitleDOM.classList.add('maintitle')
265+
266+
gameOverTitleDOM.textContent = '游戏结束'
267+
gameOverSubTitleDOM.textContent = `黑 ${blackCount} vs 白 ${whiteCount}`
268+
gameOverMainTitleDOM.textContent = `${blackCount > whiteCount ? '真棒🎉,胜利啦~' : '失败啦,不要气馁哦~'}`
269+
270+
gameOverDOM.appendChild(gameOverTitleDOM)
271+
gameOverDOM.appendChild(gameOverSubTitleDOM)
272+
gameOverDOM.appendChild(gameOverMainTitleDOM)
273+
reversiBoardDOM.appendChild(gameOverDOM)
274+
}
275+
276+
// 展示棋盘图
277+
function showReversiBoard() {
278+
let str = ``;
279+
for (let y = 0; y < 8; y++) {
280+
for (let x = 0; x < 8; x++) {
281+
let key = v2ToStr(x, y)
282+
str += reversiBoard[key] ? reversiBoard[key] == "W" ? '⚪' : '⚫' : '🈳'
283+
}
284+
str += '\n'
285+
}
286+
console.log(str);
287+
}
288+
289+
nextPlayerOperate()
290+
</script>
291+
292+
293+
294+
</body>
295+
296+
</html>

examples.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,6 @@
100100
100.曲面八分屏.html
101101
101.基金收益计算.html
102102
102.镜面滑屏.html
103+
103.黑白棋.html
103104
blog.html
104105
index.html

0 commit comments

Comments
 (0)