рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рднрд╛рдЧ 2: рд╕реНрдЯреЗрдЯрд▓реЗрд╕ рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ

рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА 0: рддреБрд▓рдирд╛ рд╕реЗрд╡реЗрд▓реНрдЯ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛
рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рднрд╛рдЧ 1: рд╕реНрд╡реЗрд▓ рдФрд░ рдХреИрдирд╡рд╕ 2 рдбреА
рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рднрд╛рдЧ 2: рд╕реНрдЯреЗрдЯрд▓реЗрд╕ рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ
рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА, рднрд╛рдЧ 3: рдХрдорд╛рдВрдб рд╕реНрдЯреЛрд░реЗрдЬ рдХреЗ рд╕рд╛рде рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ
рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рднрд╛рдЧ 4: HTTP рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдлреНрд▓рд╛рд╕реНрдХ рдмреИрдХрдПрдВрдб рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд

рдЯрд┐рдХ рдЯреАрдПрд╕реА рдХреЛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рджреНрд╡рд╛рд░рд╛ рд▓реЗрдЦ рдХреА рдирд┐рд░рдВрддрд░рддрд╛ , рднрд╛рдЧ 1 , рдЬрд┐рд╕рдореЗрдВ рд╣рдордиреЗ рд╕реНрд╡реЗрд▓реНрдЯреЗ рдкрд░ рдЗрд╕ рдЧреЗрдо рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рдЗрд╕ рднрд╛рдЧ рдореЗрдВ рд╣рдо рдЦреЗрд▓ рдХреЛ рдЕрдВрдд рддрдХ рдкреВрд░рд╛ рдХрд░реЗрдВрдЧреЗред рдЦреЗрд▓ рдХреЗ рдХрд┐рд╕реА рднреА рдЪрд░рдг рдореЗрдВ рдЕрдирдбреВ / рд░реАрдбреЛ рдЯреАрдореЛрдВ рдХреЛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд░реВрдк рд╕реЗ рдЬреЛрдбрд╝реЗрдВ, рдкреНрд░рддрд┐рджреНрд╡рдВрджреНрд╡реА рдХреЗ рд╕рд╛рде рдмрд╛рд░реА-рдмрд╛рд░реА рд╕реЗ, рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реБрдП, рд╡рд┐рдЬреЗрддрд╛ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░рдирд╛ред


рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ

REPL рдХреЛрдб


рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░, рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ рдЖрджреЗрд╢реЛрдВ рдХреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛ред рдЗрддрд┐рд╣рд╛рд╕ рдХреА рджреБрдХрд╛рди рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдзрдХреНрдХрд╛ рдФрд░ рдлрд┐рд░ рд╕реЗ рддрд░реАрдХреЗред


undo: () => update(h => { h.undo(); return h; }), redo: () => update(h => { h.redo(); return h; }), 

рдЗрддрд┐рд╣рд╛рд╕ рдХреЗ рд╡рд░реНрдЧ рдореЗрдВ рдкреБрд╢ , рд░реАрдбреЛ , рдХреИрдиреБрдВрдбреЛ , рдХреИрдиреЗрдбреЛ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


 canUndo() { return this.current > 0; } canRedo() { return this.current < this.history.length - 1; } undo() { if (this.canUndo()) this.current--; } redo() { if (this.canRedo()) this.current++; } 

рдЗрддрд┐рд╣рд╛рд╕ рд╡рд┐рдзрд┐ рдХреЛ рд╡рд░реНрддрдорд╛рди рд╕реЗ рдЕрдВрддрд┐рдо рддрдХ рд╕рднреА рд░рд╛рдЬреНрдпреЛрдВ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреА рдкреБрд╢ рд╡рд┐рдзрд┐ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИред рдпрджрд┐ рд╣рдо рдХрдИ рдмрд╛рд░ рдкреВрд░реНрд╡рд╡рдд рдЖрджреЗрд╢ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдореЗрдВ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╡рд░реНрддрдорд╛рди рд╕реЗ рдЕрдВрддрд┐рдо рддрдХ рдХреЗ рд╕рднреА рд░рд╛рдЬреНрдп рд╕реНрдЯреЛрд░ рд╕реЗ рд╣рдЯрд╛ рджрд┐рдП рдЬрд╛рдПрдВрдЧреЗ рдФрд░ рдПрдХ рдирдпрд╛ рд░рд╛рдЬреНрдп рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛ред


 push(state) { // remove all redo states if (this.canRedo()) this.history.splice(this.current + 1); // add a new state this.current++; this.history.push(state); } 

рдкреВрд░реНрд╡рд╡рдд рдФрд░ рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ рдмрдЯрди рдХреЛ рдРрдк рдШрдЯрдХ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИред рдпрджрд┐ рдЖрджреЗрд╢реЛрдВ рдХрд╛ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


 <div> {#if $history.canUndo()} <button on:click={history.undo}>Undo</button> {:else} <button disabled>Undo</button> {/if} {#if $history.canRedo()} <button on:click={history.redo}>Redo</button> {:else} <button disabled>Redo</button> {/if} </div> 

рдкрд╛рдареНрдпрдХреНрд░рдо рдХрд╛ рдкрд░рд┐рд╡рд░реНрддрди

REPL рдХреЛрдб


рдорд╛рдЙрд╕ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдПрдХ рдХреНрд░реЙрд╕ рдпрд╛ рдкреИрд░ рдХреА рдЕрдВрдЧреБрд▓реА рдХрд╛ рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдкред


рдХреНрд▓рд┐рдХрд╕реЗрд▓ () рд╡рд┐рдзрд┐ рдХреЛ рдЙрдирдХреЗ рдЗрддрд┐рд╣рд╛рд╕ рднрдВрдбрд╛рд░ рд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╕рднреА рд╡рд┐рдзрд┐ рдХреЛрдб рдХреЛ рдмреЛрд░реНрдб рдШрдЯрдХ рдХреЗ рд╣реИрдВрдбрд▓рдХреНрд▓рд┐рдХ () рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


 function handleClick(event) { let x = Math.trunc((event.offsetX + 0.5) / cellWidth); let y = Math.trunc((event.offsetY + 0.5) / cellHeight); let i = y * width + x; const state = $history.currentState(); const squares = state.squares.slice(); squares[i] = state.xIsNext ? 'X' : 'O'; let newState = { squares: squares, xIsNext: !state.xIsNext, }; history.push(newState); } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдкрд╣рд▓реЗ рдХреА рдЧрдИ рдЧрд▓рддреА рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛; рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЗрд╕ рд╡рд┐рд╢реЗрд╖ рдЧреЗрдо рдХреЗ рддрд░реНрдХ рдкрд░ рдирд┐рд░реНрднрд░ рдереАред рдЕрдм рдпрд╣ рддреНрд░реБрдЯрд┐ рдареАрдХ рд╣реЛ рдЧрдИ рд╣реИ, рдФрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдЕрдиреНрдп рдЦреЗрд▓реЛрдВ рдФрд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рдмрд┐рдирд╛ рдмрджрд▓рд╛рд╡ рдХреЗ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


рдкрд╣рд▓реЗ, рдПрдХ рдЧреЗрдо рд╕реНрдЯреЗрдк рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдХреЗрд╡рд▓ 9 рдорд╛рдиреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рджреНрд╡рд╛рд░рд╛ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЕрдм рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рд╕рд░рдгреА рдФрд░ xIsNext рд╕рдВрдкрддреНрддрд┐ рд╡рд╛рд▓реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИред рдЦреЗрд▓ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдЗрд╕ рд╡рд╕реНрддреБ рдХрд╛ рдкреНрд░рд╛рд░рдВрдн рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


 let state = { squares: Array(9).fill(''), xIsNext: true, }; 

рдФрд░ рдпрд╣ рднреА рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЗрддрд┐рд╣рд╛рд╕ рднрдВрдбрд╛рд░рдг рдЕрдм рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рд╡рд░реНрдгрд┐рдд рд░рд╛рдЬреНрдпреЛрдВ рдХреЛ рджреЗрдЦ рд╕рдХрддрд╛ рд╣реИред


рдЗрддрд┐рд╣рд╛рд╕ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдкрд╣реБрдБрдЪ

REPL рдХреЛрдб


рдЗрддрд┐рд╣рд╛рд╕ рдХреА рджреБрдХрд╛рди рдореЗрдВ, setCurrent (рд╡рд░реНрддрдорд╛рди) рдкрджреНрдзрддрд┐ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛, рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рд╣рдо рдЦреЗрд▓ рдХреА рдЪрдпрдирд┐рдд рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред


 setCurrent(current) { if (current >= 0 && current < this.history.length) this.current = current; } 

 setCurrent: (current) => update(h => { h.setCurrent(current); return h; }), 

рдРрдк рдШрдЯрдХ рдореЗрдВ, рдмрдЯрди рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд╛рд▓ рдХреЗ рдЗрддрд┐рд╣рд╛рд╕ рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдЬреЛрдбрд╝рд╛ред


 <ol> {#each $history.history as value, i} {#if i==0} <li><button on:click={() => history.setCurrent(i)}>Go to game start</button></li> {:else} <li><button on:click={() => history.setCurrent(i)}>Go to move #{i}</button></li> {/if} {/each} </ol> 

рд╡рд┐рдЬреЗрддрд╛ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг, рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛

REPL рдХреЛрдб


рдПрдХ рдЕрд▓рдЧ рд╣реЗрд▓реНрдкрд░реНрд╕.рдЬреЗрдПрд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╡рд┐рдЬреЗрддрд╛ рдХреИрд▓реНрдХреНрдпреБрд▓реЗрдЯрд░ () рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдлрд╝рдВрдХреНрд╢рди:


 export function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; } 

рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдерд┐рддрд┐ рд╡реНрдпреБрддреНрдкрдиреНрди рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ , рдпрд╣рд╛рдБ рдЦреЗрд▓ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ: рд╡рд┐рдЬреЗрддрд╛ рдпрд╛ рдбреНрд░рд╛:


 export const status = derived( history, $history => { if ($history.currentState()) { if (calculateWinner($history.currentState().squares)) return 1; else if ($history.current == 9) return 2; } return 0; } ); 

рдЦреЗрд▓ рдХреА рд╕реНрдерд┐рддрд┐ рдХрд╛ рдЖрдЙрдЯрдкреБрдЯ рдРрдк рдШрдЯрдХ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ:


 <div class="status"> {#if $status === 1} <b>Winner: {!$history.currentState().xIsNext ? 'X' : 'O'}</b> {:else if $status === 2} <b>Draw</b> {:else} Next player: {$history.currentState().xIsNext ? 'X' : 'O'} {/if} </div> 

рдмреЛрд░реНрдб рдШрдЯрдХ рдореЗрдВ, рд╣реИрдВрдбрд▓рдХреНрд▓рд┐рдХ рдХреЗ рд╣реИрдВрдбрд▓ рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд╕реАрдорд╛рдПрдБ рдЬреЛрдбрд╝реА рдЧрдИ рд╣реИрдВ () рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ: рдЦреЗрд▓ рдЦрддреНрдо рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рднреА рднрд░реЗ рд╣реБрдП рд╕реЗрд▓ рдореЗрдВ рдХреНрд▓рд┐рдХ рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИред


 const state = $history.currentState(); if ($status == 1 || state.squares[i]) return; 

рдЦреЗрд▓ рдЦрддреНрдо рд╣реЛ рдЧрдпрд╛ рд╣реИ! рдЕрдЧрд▓реЗ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдХрдорд╛рдВрдб рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрд╕реА рдЦреЗрд▓ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ, рдЕрд░реНрдерд╛рддред рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░рд╛рдЬреНрдпреЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рдкреВрд░реНрд╡рд╡рдд рдХрд░реЗрдВ / рдлрд┐рд░ рд╕реЗ рдХрд░реЗрдВ рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рдеред


рдЧрд┐рдЯрд╣рдм рднрдВрдбрд╛рд░

https://github.com/nomhoi/tic-tac-toe-part2


рд╕реНрдерд╛рдиреАрдп рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдЧреЗрдо рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдирд╛:


 git clone https://github.com/nomhoi/tic-tac-toe-part2.git cd tic-tac-toe-part2 npm install npm run dev 

рд╣рдо рдкрддреЗ рдкрд░ рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЧреЗрдо рд▓реЙрдиреНрдЪ рдХрд░рддреЗ рд╣реИрдВ: http: // localhost: 5000 / ред

Source: https://habr.com/ru/post/hi459630/


All Articles