JavaScript (+LWC)ã®ãã¥ã¼ããªã¢ã«: ãªãã¼ã·ãä½ã(2)
æ¦è¦
ä»åãåç´ãªãªãã¼ã·ã®å®è£ ã¨ãã·ã³ãã«ãªç»é¢è¡¨ç¤ºã¾ã§ããã ç»é¢ã¯ãã ãã£ããã®ã§ã¯ãªããåç´ã«æå表示ã®ãã®ãã¤ã¾ã UI ã§ã¯ãªããã²ã¼ã ã®ã«ã¼ã«å®è£ ãåªå ãã¾ãã
åæç¥è
ååã¾ã§ã®ç¥è
ç®æ¬¡
- æ¦è¦
- åæç¥è
- ç®æ¬¡
- ãã£ã¬ã¯ããªæ§é ãå¤æ´ãã
- ãã¸ãã¯ã®å®è£
- ããã¾ã§ã®ã³ã¼ãã¾ã¨ã
ãã£ã¬ã¯ããªæ§é ãå¤æ´ãã
ååã¾ã§ã§ LWC ãè¨å®ãã¾ããã¯ãããexampleããã£ã¬ã¯ããªã£ã¦â¦ã¨æã£ãã®ã¯èªåã ããï¼
ã¨ãããã¨ã§ããããã¾ãå¤æ´ããã
å ·ä½çã«ã¯ãããªæãã«ãªã£ã¦ããã®ã§
- modules
- example
- app
- example
ãããããããã
- modules
- reversi
- app
- reversi
ããèªä½ã¯ç°¡åãªã®ã§ãã¨ãããããã£ã¬ã¯ããªåãå¤æ´ãããã
ããã ãã§ã npm run dev
ã§ãµã¼ããèµ·åããã¨â¦
500 - Error retrieving view for route "example"
ã¨è¨ããã¦ãã¾ãã¾ãã
ãã㯠example/app
ãã¢ããªã±ã¼ã·ã§ã³ã®èµ·åã«ã¼ãã¨ãã¦è¨å®ããã¦ããããã§ããâ¦
ãã®è¨å®ãã¡ã¤ã«ã¯ lwr.config.json
ãã¡ã¤ã«ã§ããããªæãã§æ¸ãæãã¾ãã
{ "lwc": { "modules": [{ "dir": "$rootDir/src/modules" }] }, "routes": [ { "id": "reversi", "path": "/", "rootComponent": "reversi/app" } ] }
ãã®å¾åèµ·åãã¦ã¿ã¦ãã ãããååã¾ã§ã®ç»é¢ãè¦ããã¨æãã¾ãã
ãã¸ãã¯ã®å®è£
ã¾ãã¯ãªãã¼ã·ã®ãã¼ãã表示ããã
MVC ã®èãæ¹ã«ããããã¸ãã¯ã¯ç¬ç«ãã¦è¨è¨ãã¾ãã
ãã®ãããã¾ãã¯ãã¸ãã¯ã¯ã©ã¹ãç¨æãã¾ãã
- modules
- reversi
- app (æ¢åãã£ã¬ã¯ããª)
app.css
app.html
app.js
- logic
logic.js
- app (æ¢åãã£ã¬ã¯ããª)
- reversi
ãªãã¼ã·ã®ç¤é¢ã¯äºæ¬¡å é åã§ç¨æãã¾ãããã
const BOARD_WIDTH = 8; const BOARD_HEIGHT = 8; const BOARD_EMPTY = 0; const BOARD_BLACK = 1; const BOARD_WHITE = 2; class Reversi { board = []; constructor() { this.initBoard(); } initBoard() { // ã·ã³ãã«ã«ãã¼ãã®é«ããå¹ ã§äºæ¬¡å é åãä½ã const root = []; for (let y=0; y<BOARD_HEIGHT; y++) { const row = []; for (let x=0; x<BOARD_WIDTH; x++) { row.push(BOARD_EMPTY); } root.push(row); } // çãä¸ã«åæé 置㮠ç½/é» ãç½®ã const X_CENTER = BOARD_WIDTH / 2; const Y_CENTER = BOARD_HEIGHT / 2; // é å㯠0 ããéå§ãªã®ã§ã4 ã¯ç»é¢å·¦ãã 5 ãã¹ç® root[X_CENTER - 1][Y_CENTER - 1] = BOARD_BLACK; root[X_CENTER][Y_CENTER - 1] = BOARD_WHITE; root[X_CENTER - 1][Y_CENTER] = BOARD_WHITE; root[X_CENTER][Y_CENTER] = BOARD_BLACK; this.board = root; } } export default Reversi;
é ã®ãªãã§ã¤ã¡ã¼ã¸ã§ãã¾ããï¼â¦æ
£ããã¾ã§é£ããã§ãããâ¦
ãããç»é¢ã«è¡¨ç¤ºãã¦ã¿ã¾ãããã次㯠app.js
ãç·¨éãã¾ãã
import { LightningElement } from 'lwc'; import ReversiLogic from 'reversi/logic'; export default class HelloWorldApp extends LightningElement { reversiLogic = new ReversiLogic(); get boardRows() { const rowToStr = (rowArr) => { return rowArr.map(n => { // 1 ãã¹åä½ã§æåã«ç½®ãæãã¾ã return n === 0 ? 'ã' : (n === 1 ? 'â' : 'â'); }).join(' / '); // æå¾ã« ` / ` ã§1è¡åã1æååã«é£çµ }; let key = 0; return this.reversiLogic.board .map(rowToStr) // 1 è¡åä½ãæååå .map(v => { // 1 è¡åä½ã { key: è¡çªå·, value: è¡ã®ä¸èº« } ã«æ´å½¢ return { key: key++, value: v }; }); } }
ç»é¢ã¯è¦ãç®ã«ãã ããããã®ã¾ã¾ã«ã¼ãã§è¡¨ç¤ºãã¾ãã
ããã°ã©ããªãããªãã¿ã® foreach
æã§ããã
<template> <main> <div style="display: inline-block; border: 1px solid #000;"> <template for:each={boardRows} for:item="row"> <div key={row.key}>{row.value}</div> </template> </div> </main> </template>
ç³ãç½®ããããã«ããã
ç³ãè£è¿ãåä½ãã¨ããããã¯èãããç³ãç½®ããããã«ãã¾ãã
ãã¼ãã«ç³ãç½®ããã»ããå©ç¨è
çã«ã¯ããããããã§ãããä»åã¯ãã¸ãã¯åªå
ãªã®ã§â¦ã
ã¾ãã¯ããã¸ãã¯çã«ãç½ã®ã¿ã¼ã³/é»ã®ã¿ã¼ã³ãå®ç¾©ãã¾ãããã
ã¤ãã§ã«ç³ãé
ç½®ãããã¸ãã¯ãã
class Reversi { board = []; isBlackTurn = true; /** * ç³ãç½®ã座æ¨ããããé»ç³ãã©ãã * @param {number} x * @param {number} y * @param {boolean} isBlack * @returns error message */ putStone(x, y, isBlack) { if (this.board.at(y)?.at(x) === null) { // å¤ãåå¾ã§ããªã = ç¤é¢ã®å¤ return 'ãããªæã«ç³ã¯ç½®ããªãï¼'; } if (this.board[y][x] === BOARD_EMPTY) { // ãã¼ãã®æå®åº§æ¨ã空ãªã // å¼æ°ã§ãé»ç³ãï¼ãã§é»ãªãé»ç³ãã§ãªããã°ç½ç³ãè¨å® const putStone = isBlack ? BOARD_BLACK : BOARD_WHITE; // ç³ãç¤é¢ã«é ç½® this.board[y][x] = putStone; // ã¿ã¼ã³ãå¤æ´ãã this.isBlackTurn = !isBlack; return null; } else { // ãã¼ãã®æå®åº§æ¨ã¯ç©ºã§ã¯ãªãã£ã return 'ããã«ã¯æ¢ã«ç³ãããã¾ãã'; } } /* 以ä¸ç¥ */
ç³ãè£è¿ãåä½ã¯ä¸æ¦èãã¾ããã
ãªã®ã§ãã¨ããããã¯ç½®ããã¨ã ãèãã¾ãã
次ã«ãç»é¢ã§é»ã®ã¿ã¼ã³ãç½ã®ã¿ã¼ã³è¡¨ç¤ºãè¡ãã¾ãã
app.js
ã«ä¸è¨ã®ã¡ã½ããã追å ãã¦ã
get isBlackTurn() { return this.reversiLogic.isBlackTurn; }
ç»é¢ä¸ã¯
<template if:true={isBlackTurn}><div>é»ã®ã¿ã¼ã³ã§ãï¼</div></template> <template if:false={isBlackTurn}><div>ç½ã®ã¿ã¼ã³ã§ãï¼</div></template>
次ã¯ç³ãç½®ãã¾ãããã
ç³ã®å®ç¾©ã¯ãã¸ãã¯ã«ããã®ã§ããããå¤ã«åºãã¾ãããã
logic.js
ãä¿®æ£ãã¾ãããã
const BOARD_WIDTH = 8; const BOARD_HEIGHT = 8; const BOARD_EMPTY = 0; const BOARD_BLACK = 1; const BOARD_WHITE = 2; const Constants = { BOARD_WIDTH, BOARD_HEIGHT, BOARD_EMPTY, BOARD_BLACK, BOARD_WHITE }; /* ä¸ç¥ */ export { Constants }; export default Reversi;
export
ã§å®æ°ãªãã¸ã§ã¯ããå¤ããå¼ã¹ãããã«ãã¦ããã¾ãã
ç¶ãã¦ãapp.js
ã§ã¯
import { LightningElement, track } from 'lwc'; import ReversiLogic from 'reversi/logic'; import { Constants } from 'reversi/logic'; // new export default class HelloWorldApp extends LightningElement { reversiLogic = new ReversiLogic(); constants = { // new ç»é¢ã«ç»é¢ãµã¤ãºã渡ãç¨ MAX_WIDTH: Constants.BOARD_WIDTH, MAX_HEIGHT: Constants.BOARD_HEIGHT } errorMessage = null; // new ã¨ã©ã¼ã¡ãã»ã¼ã¸è¡¨ç¤ºç¨ /* ä¸ç¥ */ handleStonePut() { // new ç³ç½®ãæä½ã¤ãã³ã // ä¸æ¦ã¯ç©º } }
ããã¦ãç¾ç¶ã® LWC ã 㨠@track
ã§ä¿®é£¾ããªããã°èªåã§ç»é¢ããªãã¬ãã·ã¥ããªãã®ã§
import { LightningElement, track } from 'lwc'; // track ã追å import ReversiLogic from 'reversi/logic'; import { Constants } from 'reversi/logic'; export default class HelloWorldApp extends LightningElement { reversiLogic = new ReversiLogic(); errorMessage = null; @track board = this.reversiLogic.board; // 追å @track isBlackTurn = this.reversiLogic.isBlackTurn; // 追å constants = { MAX_WIDTH: Constants.BOARD_WIDTH, MAX_HEIGHT: Constants.BOARD_HEIGHT } get boardRows() { const rowToStr = (rowArr) => { return rowArr.map(n => { return n === 0 ? 'ã' : (n === 1 ? 'â' : 'â'); }).join(' / '); }; let key = 0; return this.board.map(rowToStr).map(v => { // ä¿®æ£ return { key: key++, value: v }; }); } // get isBlackTurn() { // ãã® getter ã¯åé¤ãã¾ãã
ããã¦ç»é¢ãå¼ãã¾ãã
ã¨ã©ã¼ãããã°ããã表示ããé¢åã§ã¯ããã¾ãã座æ¨æå®ãæå®ãã¦éä¿¡ãã¿ã³ãæ¼ãããã«ãã¾ãããã
<template if:true={errorMessage}> <div style="background-color: red; padding: .25rem; text-align: center;">{errorMessage}</div> </template> <!-- ããã¾ã§ --> <template if:true={isBlackTurn}><div>é»ã®ã¿ã¼ã³ã§ãï¼</div></template> <template if:false={isBlackTurn}><div>ç½ã®ã¿ã¼ã³ã§ãï¼</div></template> <!-- ãããã追å --> <div><label for="y">縦軸</label><input type="number" name="axis_y" min="1" max={constants.MAX_HEIGHT} id="y"></div> <div><label for="x">横軸</label><input type="number" name="axis_x" min="1" max={constants.MAX_WIDTH} id="x"></div> <button type="button" onclick={handleStonePut}>éä¿¡</button>
ã¤ãã³ãã {é¢æ°å}
ã§Jsã®å¤æ°ãé¢æ°ã HTML ã«è¨å®ï¼ãã¤ã³ãã¨ããã¾ãã以éãã¤ã³ãã¨å¼ç§°ï¼ãã¾ãã
ã§ã¯ããã§ãhandleStonePut
ã®ä¸èº«ãä½ã£ã¦ããã¾ãããã
/** * ç³ãç½®ã座æ¨ããããé»ç³ãã©ãã * @param {number} x * @param {number} y * @param {boolean} isBlack * @returns error message */ putStone(x, y, isBlack) { if (this.board.at(y)?.at(x) === null) { return 'ãããªæã«ç³ã¯ç½®ããªãï¼'; } if (this.board[y][x] === BOARD_EMPTY) { const putStone = isBlack ? BOARD_BLACK : BOARD_WHITE; this.board[y][x] = putStone; this.isBlackTurn = !isBlack; return null; } else { return 'ããã«ã¯æ¢ã«ç³ãããã¾ãã'; } }
ããã¨ãããªæãã§è¡¨ç¤ºã§ããããã«ãªãã¾ãã
ãã£ã¨é»ã®ã¿ã¼ã³ãç¶ãã¦ããããã«è¦ãã¾ããã
åå ã¯ä¸è¨ã§ããã
@track board = this.reversiLogic.board; @track isBlackTurn = this.reversiLogic.isBlackTurn;
board
㯠Array
ã¤ã¾ããªãã¸ã§ã¯ãã§ãããisBlackTurn
㯠boolean
ãªãã§ããã
JavaScript ã®å¤æ°ã¯ããªãã¸ã§ã¯ãã¯åç
§ãã¤ã¾ãã¡ã¢ãªã®ä½å¦ãã«åå¨ãã¦ããå®æ
ã®ã¡ã¢ãªã¢ãã¬ã¹*1ãboolean
ã number
ãªã©ããªããã£ãåã¯å®éã®å¤ãå
¥ã£ã¦ãã¾ãã
ãªã®ã§ãããã§ã¯ä»¥ä¸ã®ãããªè§£éã«ãªãã¾ãã
// ãã®è¡ã¯ this.reversiLogic.board ã®ã¡ã¢ãªã¢ãã¬ã¹ã board ã«å ¥ã£ã¦ãã // ãªã®ã§ãthis.board.length ã¯éæ¥çã« this.reversiLogic.board.length ãæãã @track board = this.reversiLogic.board; // ãã®è¡ã¯ãthis.reversiLogic.isBlackTurn ã®å¤ãã³ãã¼ã㦠isBlackTurn ã«å ¥ãã¦ããã // ãªã®ã§ãisBlackTurn 㨠this.reversiLogic.isBlackTurn ã¯å¥ã®ãã®ã«ãªã£ã¦ããã // this.reversiLogic.isBlackTurn ãã©ããªå¤ã¨ãªã£ã¦ãã¦ãã isBlackTurn ã¯ç¬ç«ãã¦ãããå¤åããªãã£ãã @track isBlackTurn = this.reversiLogic.isBlackTurn;
ã¤ã¾ããã¿ã¼ã³ãå¤ãã£ãããå度è¨å®ãã¦ãããã°è¯ãã®ã§ããã
handleStonePut() { try { const xValue = this.template.querySelector('input[name="axis_x"]').value; const yValue = this.template.querySelector('input[name="axis_y"]').value; this.errorMessage = this.reversiLogic.putStone(xValue - 1, yValue - 1, this.isBlackTurn); this.isBlackTurn = this.reversiLogic.isBlackTurn; // 追å } catch (error) { console.log(error.message); } }
ããã¨
ç³ãã²ã£ããè¿ãã
ã§ã¯ç³ãããããããã®éã®ç³ãã²ã£ããè¿ããã¸ãã¯ãèãã¾ãã
å³ã§ã¯ç½ç³ã®ä¸ã«é»ç³ãç½®ããã®ã§ãä¸æ¹åã§ç³ã®è²ãå¤ããäºãèãã¾ãã
ã«ã¼ã«ã¯ âââ
ãªã©ã®æã¾ããåºéãããã°è²ãç½®ãæããã¨ããå¦çã«ãªãã¾ãã
ããã1ã¾ãã¥ã¤è©ä¾¡ãããªã以ä¸ã®ããã«èãã¾ãã
ç³ãç½®ã座æ¨ï¼currentX
, currentY
ï¼ããä¸ã¸ä¸ã¤ã¥ã¤ä¸ããã以ä¸ããããã®æ¡ä»¶ãæ´ãã¾ã§ç¹°ãè¿ãã¾ãã
- ç³ãç½®ãã座æ¨ï¼èµ·ç¹ï¼ã¯ç¹ã«ãã§ãã¯ããªã
- 次ã®åº§æ¨(ä¸ã¤ä¸)ã確èªããã
- 空ç½ãåºç¾ãã
- ã¤ã¾ãè£è¿ããç³ãåå¨ããªã
- ç¤é¢ã®ç«¯ã¾ã§æ¥ã¦ãã
- ãããè£è¿ããç³ãåå¨ããªã
- æµå¯¾ããç³ããã
- è£è¿ã対象ã®ç³ããªã®ã§ããã«ä¸ããã§ãã¯ãã
- èªåã¨åãè²ã®ç³ããã
- æµå¯¾ããç³ãåå¨ããªããªããè¿ããç³ã¯ãªã
- æµå¯¾ããç³ãï¼ã¤ä»¥ä¸ãããªããç³ãã²ã£ããè¿ã
ãæ¡ä»¶ãç¹°ãè¿ãããåãå¦çãç¹°ãè¿ããã¯èªåãªãåèµ·ãã¾ããã
ã¨ãããã¨ã§ãä¸è¨ãã»ã¨ãã©ãã®ã¾ã¾ã³ã¼ãã£ã³ã°ãã¾ãã
currentX, currentY
ã¯ãã§ãã¯ãã座æ¨vX, vY
次ã«ãã§ãã¯ãã座æ¨ã®ç¸å¯¾ä½ç½®ï¼v
ã¯ãã¯ãã«âæ¹åæ§ï¼putColor
ã¯ç½®ããç³ã®è²depth
ã¯ä½åå ã¾ã§è¦ã«è¡ã£ãã®ãã®å¤
flipStone(currentX, currentY, vX, vY, putColor, depth) { let result = 0; // ç»é¢å¤ã«åºããå¼·å¶çµäº if (currentX < 0 || currentX >= BOARD_WIDTH || currentY < 0 || currentY >= BOARD_HEIGHT) { return 0; } if (depth === 0) { // èµ·ç¹åº§æ¨ã¯è©ä¾¡ããªãï¼putColor ç½®ãã座æ¨ã putColor ã¨ä¸è´ããã®ã¯èªæãªã®ã§ï¼ // 次ã®åº§æ¨ããã§ãã¯ãã result = this.flipStone(currentX + vX, currentY + vY, vX, vY, putColor, depth + 1); } else { // ãã以å¤ã¯è©ä¾¡ãã // ç¾å¨ã®åº§æ¨ã®ãã¹ãåå¾ const current = this.board.at(currentY)?.at(currentX); // ç»é¢ç«¯ â è¿ãç³ã¯ãªã if (current === null) { return 0; } // 空ç½ãåºç¾ â è¿ãç³ã¯ãªã if (current === BOARD_EMPTY) { return 0; } // åãè²ã®ç³ããã if (current === putColor) { return depth - 1; } // ä¸è¨ã©ãã§ããªã â æµå¯¾è²ã®ç³ããã(ãããã¯èµ·ç¹ã§ãã) // 次ã®åº§æ¨ããã§ãã¯ãã result = this.flipStone(currentX + vX, currentY + vY, vX, vY, putColor, depth + 1); if (result > 0) { // è¿ãç³ããã â ç¾å¨ã®åº§æ¨ã®ç³ãç½®ãæã㦠return this.board[currentY][currentX] = putColor; } } return result; }
ãã®å¦çãç³ãç½®ããç¬éã«èµ·åãã¾ãã
putStone(x, y, isBlack) { if (this.board.at(y)?.at(x) === null) { return 'ãããªæã«ç³ã¯ç½®ããªãï¼'; } if (this.board[y][x] === BOARD_EMPTY) { const putStone = isBlack ? BOARD_BLACK : BOARD_WHITE; this.board[y][x] = putStone; let revStones = this.flipStone(x, y, 0, 1, putStone, 0); // ä¸æ¹å revStones += this.flipStone(x, y, 0, -1, putStone, 0); // ä¸æ¹å revStones += this.flipStone(x, y, -1, 0, putStone, 0); // å·¦æ¹å revStones += this.flipStone(x, y, 1, 0, putStone, 0); // å³æ¹å revStones += this.flipStone(x, y, -1, -1, putStone, 0); // å·¦ä¸æ¹å revStones += this.flipStone(x, y, 1, -1, putStone, 0); // å³ä¸æ¹å revStones += this.flipStone(x, y, -1, 1, putStone, 0); // å·¦ä¸æ¹å revStones += this.flipStone(x, y, 1, 1, putStone, 0); // å³ä¸æ¹å console.log(`flips: ${revStones}`); this.isBlackTurn = !isBlack; return null; } else { return 'ããã«ã¯æ¢ã«ç³ãããã¾ãã'; } }
ã¨ããã¨ç³ã®å転åä½ãä½ãã¾ãã
ã¡ãªã¿ã«ãåãæ§ãªã³ã¼ãã沢山ããã®ã¯ç²¾ç¥çã«ãããããªãâ¦
ã®ã§ä¸æ¦ãªãã¡ã¯ã¿ï¼ãªãã¡ã¯ã¿ã¯ã³ã¼ããå§ç¸®ãã¦çãããâ¦ã¨ããã®ã¯ééãã§ãã³ã¼ããæ´çãããã¨ãè¨ãã¾ãããæ¬å½ã¯ãã¹ãã³ã¼ãæ¸ãã¦ãããããã®ã§ããâ¦ï¼
putStone(x, y, isBlack) { if (this.board.at(y)?.at(x) === null) { return 'ãããªæã«ç³ã¯ç½®ããªãï¼'; } if (this.board[y][x] !== BOARD_EMPTY) { return 'ããã«ã¯æ¢ã«ç³ãããã¾ãã'; } const vectors = [ [0, 1], [0, -1], // ä¸, ä¸ [1, 1], [1, -1], // å³ä¸, å³ä¸ [-1, 1], [-1, -1], // å·¦ä¸, å·¦ä¸ [1, 0], [-1, 0] // å³, å·¦ ]; // ç½®ãç³ã®è² const putStone = isBlack ? BOARD_BLACK : BOARD_WHITE; // ç³ãé ç½® this.board[y][x] = putStone; // ç³ãå転æä½ï¼å ¨æ¹åï¼ let revStones = 0; vectors.forEach(v => { revStones += this.flipStone(x, y, v[0], v[1], putStone, 0); }); // ã¿ã¼ã³å¤æ´ this.isBlackTurn = !isBlack; return null; }
ç³ãç½®ããªãäºãéç¥ãã
ãªãã¼ã·ã¯ç³ãè£è¿ããå ´æã«ããç³ãç½®ããã¨ãã§ãã¾ããã
ãªã®ã§ãåæã§è§ã«ç³ãç½®ãã¨ãã£ãæé ã¯åã£ã¦ã¯ãªããªãã®ã§ãã
ã¨ãããã¨ã§ãè£è¿ããç³ããªãã£ãã¨ãã®å¦çãå ¥ãã¾ããããã
// ç³ãå転æä½ï¼å ¨æ¹åï¼ let revStones = 0; vectors.forEach(v => { revStones += this.flipStone(x, y, v[0], v[1], putStone, 0); }); // è£è¿ããç³ãç¡ããªããç³ã¯ç½®ããªã if (revStones === 0) { // 追å åå² this.board[y][x] = BOARD_EMPTY; return 'è£è¿ããç³ãç¡ããããé ç½®ã§ãã¾ããã'; } // ã¿ã¼ã³å¤æ´ this.isBlackTurn = !isBlack; return null;
ã¾ããã©ãã«ãç³ãç½®ããªããªããæçªãã¹ããããããããªãã§ãããï¼
ã¨ãããã¨ã§æçªã¹ãããå¦çãå
¥ãã¾ãã
class Reversi { board = []; isBlackTurn = true; constructor() { this.initBoard(); } skipTurn() { // 追å this.isBlackTurn = !this.isBlackTurn; }
app.js
ã app.html
ã§ã追å ãã¾ãããã
handleSkip() { this.reversiLogic.skipTurn(); this.isBlackTurn = this.reversiLogic.isBlackTurn; }
<div><label for="y">縦軸</label><input type="number" name="axis_y" min="1" max={constants.MAX_HEIGHT} id="y"></div> <div><label for="x">横軸</label><input type="number" name="axis_x" min="1" max={constants.MAX_WIDTH} id="x"></div> <!-- ããããæ¸ãæã --> <div style="text-align: center;"> <button type="button" onclick={handleSkip}>æçªãã¹ããã</button> <button type="button" onclick={handleStonePut}>ç³ãç½®ã</button> </div>
ããã¾ã§è¡ãã°ãã ãã¶ã²ã¼ã ããããªã£ãã®ã§ã¯ï¼
ã¹ãã¼ã¿ã¹è¡¨ç¤º
é»ç³ã¨ç½ç³ã®æ°ãåå¾ã§ããããã«ãã¾ããããã
ã¨ãã£ã¦ããç¤é¢ã®é»/ç½ãæ°ããã ãã§ããã
logic.js
ã«ãã㪠getter ã追å ã
/** * ç¤é¢ã®ç¶æ ãè¿ã */ get summary() { let white = 0; let black = 0; for (let y = 0; y < BOARD_HEIGHT; y++) { for (let x = 0; x < BOARD_WIDTH; x++) { const col = this.board[y][x]; if (col === BOARD_BLACK) { black++; } if (col === BOARD_WHITE) { white++; } } } return { black, white }; }
å
容ã app.js
ã§åãåãã¾ãããã
reversiLogic = new ReversiLogic(); errorMessage = null; @track board = this.reversiLogic.board; @track isBlackTurn = this.reversiLogic.isBlackTurn; @track summary = this.reversiLogic.summary; // 追å get summaryString() { // 追å return `(é»: ${this.summary.black}, ç½: ${this.summary.white})`; } /* ä¸ç¥ */ handleStonePut() { try { const xValue = this.template.querySelector('input[name="axis_x"]').value; const yValue = this.template.querySelector('input[name="axis_y"]').value; this.errorMessage = this.reversiLogic.putStone(xValue - 1, yValue - 1, this.isBlackTurn); this.isBlackTurn = this.reversiLogic.isBlackTurn; this.summary = this.reversiLogic.summary; // 追å } catch (error) { console.log(error.message); } }
ããããããããç»é¢ã«ã表示ãã¾ãã
<div style="text-align: center;"> <template if:true={isBlackTurn}><span>é»ã®ã¿ã¼ã³ã§ãï¼</span></template> <template if:false={isBlackTurn}><span>ç½ã®ã¿ã¼ã³ã§ãï¼</span></template> <span>{summaryString}</span> </div>
ããã¨æçµçã«ãããªæãã«ãªãã¾ãã
ããã¾ã§ã®ã³ã¼ãã¾ã¨ã
logic.js
const BOARD_WIDTH = 8; const BOARD_HEIGHT = 8; const BOARD_EMPTY = 0; const BOARD_BLACK = 1; const BOARD_WHITE = 2; const Constants = { BOARD_WIDTH, BOARD_HEIGHT, BOARD_EMPTY, BOARD_BLACK, BOARD_WHITE }; class Reversi { board = []; isBlackTurn = true; constructor() { this.initBoard(); } /** * ç¤é¢ã®ç¶æ ãè¿ã */ get summary() { let white = 0; let black = 0; for (let y = 0; y < BOARD_HEIGHT; y++) { for (let x = 0; x < BOARD_WIDTH; x++) { const col = this.board[y][x]; if (col === BOARD_BLACK) { black++; } if (col === BOARD_WHITE) { white++; } } } return { black, white }; } /** * æçªãã¹ããããã */ skipTurn() { this.isBlackTurn = !this.isBlackTurn; } /** * ç³ãç½®ã座æ¨ããããé»ç³ãã©ãã * @param {number} x * @param {number} y * @param {boolean} isBlack * @returns error message */ putStone(x, y, isBlack) { if (this.board.at(y)?.at(x) === null) { return 'ãããªæã«ç³ã¯ç½®ããªãï¼'; } if (this.board[y][x] !== BOARD_EMPTY) { return 'ããã«ã¯æ¢ã«ç³ãããã¾ãã'; } const vectors = [ [0, 1], [0, -1], // ä¸, ä¸ [1, 1], [1, -1], // å³ä¸, å³ä¸ [-1, 1], [-1, -1], // å·¦ä¸, å·¦ä¸ [1, 0], [-1, 0] // å³, å·¦ ]; // ç½®ãç³ã®è² const putStone = isBlack ? BOARD_BLACK : BOARD_WHITE; // ç³ãé ç½® this.board[y][x] = putStone; // ç³ãå転æä½ï¼å ¨æ¹åï¼ let revStones = 0; vectors.forEach(v => { revStones += this.flipStone(x, y, v[0], v[1], putStone, 0); }); // è£è¿ããç³ãç¡ããªããç³ã¯ç½®ããªã if (revStones === 0) { this.board[y][x] = BOARD_EMPTY; return 'è£è¿ããç³ãç¡ããããé ç½®ã§ãã¾ããã'; } // ã¿ã¼ã³å¤æ´ this.isBlackTurn = !isBlack; return null; } flipStone(currentX, currentY, vX, vY, putColor, depth) { let result = 0; if (depth === 0) { // èµ·ç¹åº§æ¨ã¯è©ä¾¡ããªãï¼putColor ç½®ãã座æ¨ã putColor ã¨ä¸è´ããã®ã¯èªæãªã®ã§ï¼ // 次ã®åº§æ¨ããã§ãã¯ãã result = this.flipStone(currentX + vX, currentY + vY, vX, vY, putColor, depth + 1); } else { // ãã以å¤ã¯è©ä¾¡ãã // ç¾å¨ã®åº§æ¨ã®ãã¹ãåå¾ const current = this.board.at(currentY)?.at(currentX); // ç»é¢ç«¯ â è¿ãç³ã¯ãªã if (current === null) { return 0; } // 空ç½ãåºç¾ â è¿ãç³ã¯ãªã if (current === BOARD_EMPTY) { return 0; } // åãè²ã®ç³ããã if (current === putColor) { return depth - 1; } // ä¸è¨ã©ãã§ããªã â æµå¯¾è²ã®ç³ããã(ãããã¯èµ·ç¹ã§ãã) // 次ã®åº§æ¨ããã§ãã¯ãã result = this.flipStone(currentX + vX, currentY + vY, vX, vY, putColor, depth + 1); if (result > 0) { // è¿ãç³ããã â ç¾å¨ã®åº§æ¨ã®ç³ãç½®ãæã㦠return this.board[currentY][currentX] = putColor; } } return result; } initBoard() { // ã·ã³ãã«ã«ãã¼ãã®é«ããå¹ ã§äºæ¬¡å é åãä½ã const root = []; for (let y=0; y<BOARD_HEIGHT; y++) { const row = []; for (let x=0; x<BOARD_WIDTH; x++) { row.push(BOARD_EMPTY); } root.push(row); } // çãä¸ã«åæé 置㮠ç½/é» ãç½®ã const X_CENTER = BOARD_WIDTH / 2; const Y_CENTER = BOARD_HEIGHT / 2; // é å㯠0 ããéå§ãªã®ã§ã4 ã¯ç»é¢å·¦ãã 5 ãã¹ç® root[X_CENTER - 1][Y_CENTER - 1] = BOARD_BLACK; root[X_CENTER][Y_CENTER - 1] = BOARD_WHITE; root[X_CENTER - 1][Y_CENTER] = BOARD_WHITE; root[X_CENTER][Y_CENTER] = BOARD_BLACK; this.board = root; } } export { Constants }; export default Reversi;
app.css
main { margin: 30px; display: flex; flex-direction: column; align-items: center; }
app.js
import { LightningElement, track } from 'lwc'; import ReversiLogic from 'reversi/logic'; import { Constants } from 'reversi/logic'; export default class HelloWorldApp extends LightningElement { reversiLogic = new ReversiLogic(); errorMessage = null; @track board = this.reversiLogic.board; @track isBlackTurn = this.reversiLogic.isBlackTurn; @track summary = this.reversiLogic.summary; constants = { MAX_WIDTH: Constants.BOARD_WIDTH, MAX_HEIGHT: Constants.BOARD_HEIGHT } get summaryString() { return `(é»: ${this.summary.black}, ç½: ${this.summary.white})`; } get boardRows() { const rowToStr = (rowArr) => { return rowArr.map(n => { return n === 0 ? 'ã' : (n === 1 ? 'â' : 'â'); }).join(' / '); }; let key = 0; return this.board.map(rowToStr).map(v => { return { key: key++, value: v }; }); } handleSkip() { this.reversiLogic.skipTurn(); this.isBlackTurn = this.reversiLogic.isBlackTurn; } handleStonePut() { try { const xValue = this.template.querySelector('input[name="axis_x"]').value; const yValue = this.template.querySelector('input[name="axis_y"]').value; this.errorMessage = this.reversiLogic.putStone(xValue - 1, yValue - 1, this.isBlackTurn); this.isBlackTurn = this.reversiLogic.isBlackTurn; this.summary = this.reversiLogic.summary; } catch (error) { console.log(error.message); } } }
<template> <main> <div style="display: inline-block; border: 1px solid #000;"> <template for:each={boardRows} for:item="row"> <div key={row.key}>{row.value}</div> </template> </div> <template if:true={errorMessage}> <div style="background-color: red; padding: .25rem; text-align: center;">{errorMessage}</div> </template> <div style="text-align: center;"> <template if:true={isBlackTurn}><span>é»ã®ã¿ã¼ã³ã§ãï¼</span></template> <template if:false={isBlackTurn}><span>ç½ã®ã¿ã¼ã³ã§ãï¼</span></template> <span>{summaryString}</span> </div> <div><label for="y">縦軸</label><input type="number" name="axis_y" min="1" max={constants.MAX_HEIGHT} id="y"></div> <div><label for="x">横軸</label><input type="number" name="axis_x" min="1" max={constants.MAX_WIDTH} id="x"></div> <div style="text-align: center;"> <button type="button" onclick={handleSkip}>æçªãã¹ããã</button> <button type="button" onclick={handleStonePut}>ç³ãç½®ã</button> </div> </main> </template>
Good luck!
*1:å³å¯ã«ã¯ãã£ã¨è¤éã ã£ãããã©ããããã¦ããã¨ãè²ã ãã¾ãã