안녕하세요!
이제 3목 7x7 마지막입니다!
다음은 아마 오목 버전으로 보여드릴 수 있을 거 같습니다(희망을 가지며 ㅎ..)
이번 버전에서는 앞으로 원래 사용하는 오목판(19x19) 등 자유롭게 오목판을 변경할 수 있도록 새로운 function을 만들었습니다(노가다로 이제 안해도 숫자만 바꾸면 판이 바뀌어요!)
그리고 endIf가 붙는 조건문에서 조건을 조금 수정하였습니다.
한가지 아쉬운게 있다면 이제 변수를 한가지만 받아서 그 변수로 다른 변수의 값들을 다 바꾸어 주고 싶은데 그 방법을 찾고 있는 중입니다...(React를 잘 아신다면 도와주시면 감사하겠습니다)
/* 7x7 3목 버전 수정 상황
1. 7x7이 아니더라도 자유롭게 오목판 변경 하기 위해서 for문 추가
2. 가로 , 세로 항목 중 endIf 조건문 수정
*/
function Square({ value, onClick, backgroundColor }) {
return (
<button
className="square"
onClick={onClick}
style={{backgroundColor}}>
{value}
</button>
);
}
class Board extends React.Component {
renderSquare(i) {
const isWinningIndex = this.props.winningIndex && this.props.winningIndex.indexOf(i) !== -1
return (
<Square
key={`button-${i}`}
value={this.props.squares[i]}
onClick={() => this.props.onClick(i)}
backgroundColor={isWinningIndex && "deepskyblue"}
/>
);
}
render() {
const boardRows = [];
for(let i = 0, len = Math.sqrt(this.props.squares.length); i < len; i++) {
const innerCols = [];
for(let j = 0; j < len; j++) {
innerCols.push(this.renderSquare((i * len) + j));
}
boardRows.push(
<div className="board-row" key={`row-${i}`}>
{innerCols}
</div>
);
}
return (
<div>
{boardRows}
</div>
);
}
}
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
history: [{
squares: Array(49).fill(null),
}],
stepNumber: 0,
xTurn: true,
};
}
handleClick(i) {
const history = this.state.history.slice(0, this.state.stepNumber + 1);
const current = history[history.length-1];
const squares = current.squares.slice();
if (declareWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xTurn ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares
}]),
stepNumber: history.length,
xTurn: !this.state.xTurn,
});
}
jumpTo(step) {
this.setState({
history: [{
squares: Array(49).fill(null),
}],
stepNumber: step,
xTurn: (step%2) === 0,
});
}
render() {
const history = this.state.history;
const current = history[history.length - 1];
const moves = history.map((step, move) => {
if (move === 0) {
return (
<div key={move}>
<button onClick={() => this.jumpTo(move)}>{"Reset Game"}</button>
</div>
);
} else {
return null;
}
});
let status;
if (declareWinner(current.squares) === 49) {
status = 'Tie Game! Reset?';
} else if (declareWinner(current.squares) != null) {
status = 'Winner: ' + declareWinner(current.squares) + ' ...Play Again?';
} else {
status = 'Your turn: ' + (this.state.xTurn ? 'X' : 'O');
}
return (
<div className="game">
<div className="game-board">
<Board
squares = {current.squares}
onClick={i => this.handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{moves}</ol>
</div>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
function declareWinner(squares) {
/* 가로 , 세로 로직 구현 위한 변수 선언 */
/* 1. 오목판 변경시 변경 해야 하는 값들 */
// 오목판 갯수
const intaglio = 49;
// 한 줄의 끝 값으로 더이상 승리하는 경우의 수가 나오지 않을 때 종료하는 변수.
var end = -4;
// 종료하는 조건의 값(해당하는 가로 첫 줄의 끝값)
var endIf = 5;
// 종료하는 조건의 값 - endIfSub ,, endIf가 1+ 하면같이 1+ 해야함.
var endIfSub = 3;
// 가로 , 세로 전체 줄 수
var totalLine = 7;
// 3목으로 한 줄당 이길 경우의 수 (가로, 세로)
var winNumberOfCases = 5;
/* 2. 오목판 변경해도 변경 x */
// 3목 전체조건 담는 배열
const samMok = [];
// 가로 , 세로 로직에 저장할 배열.
var liness = [];
var count = 0;
// lines 통한 새로운 배열 출력(전체 배열)
const lines = new Array();
// 오목판 전체 갯수 출력
for(let x = 0; x < intaglio; x++) {
samMok.push(x);
}
// 가로 3목 로직
// for문 1번째 : 가로 5번
for(let k = 0; k < totalLine; k++) {
// 3목 가로 1줄당 3목이 될 경우의수 3번이므로 3번 반복
for(let z = 0; z <= winNumberOfCases; z++) {
// 3목판 전체에 대한 카운트
for(let j = count; j < intaglio; j++) {
// samMok에 저장된 값 나누어서 배열에 저장
liness = samMok.slice(j,j+3);
lines.push(liness);
// 가로 한줄의 값이 (ex - 4,9,14) 등 끝날때 마다 한줄의 반복문 종료 조건문
if((end % endIf == 0)){
// 다음줄의 초기 값은 원래 초기값의 +1 된 값이 되어야 함으로 아래 조건이 됨(초기값 0 다음은 1이 와야함으로)
count+=(endIf - endIfSub);
break;
}
break;
}
count+=1;
end+=1;
}
}
// 세로 3목 로직
// 수정 x
var height = 0;
var heightval = [];
//세로 줄 표현(0,5,10,15,20 ....)
for(let y=0; y<totalLine; y++) {
for(let z=0; z<totalLine; z++) {
// heightval 에 값 넣기.
heightval.push(height);
height+=totalLine;
if(height >= intaglio) {
break;
}
}
//새로운 세로줄 시작 할 때 초기값 설정 공식 : (height = (height % 제일 밑 가로줄 마지막 첫 숫자 입력) - (전체 가로 / 세로 줄 -1)
//(전체 가로 / 세로 줄 -1) 하는 이유 : 위에서 height+=totalLine 을 더한 값이 있기때문에 빼주는 작업을 함.
height=(height%42) - (totalLine-1);
}
// 세로줄 초기값 설정.
count = 0;
end = -4;
endIf = 5;
endIfSub = 3;
// for문 1번째 : 세로 5번
for(let w = 0; w < totalLine; w++) {
// 3목 세로 1줄당 3목이 될 경우의수 3번이므로 3번 반복
for(let e = 0; e <= winNumberOfCases; e++) {
// 3목판 전체에 대한 카운트
for(let r = count; r < intaglio; r++) {
// samMok에 저장된 값 나누어서 배열에 저장
liness = heightval.slice(r,r+3);
lines.push(liness);
// 세로 한줄의 값이 끝날때 마다 한줄의 반복문 종료 조건문
if((end % endIf == 0)){
// 다음줄의 초기 값은 원래 초기값의 +1 된 값이 되어야 함으로 아래 조건이 됨(초기값 0 다음은 1이 와야함으로)
count+=(endIf - endIfSub);
break;
}
break;
}
count+=1;
end+=1;
}
}
/* 대각선 로직 구현 위한 변수 선언 */
/* 1. 오목판 변경시 변경 해야 하는 값들 */
// crossCount의 증감 숫자.
var crossCountPlus = 7;
// 대각선(/) 증감 숫자
var leftCross = 8;
// 대각선(\) 증감 숫자
var rightCross = 6;
/* 2. 오목판 변경해도 변경 x */
// 대각선 배열의 숫자를 빼기 위해 선언한 a,b,c
var a = 0;
var b = 0;
var c = 0;
// 대각선 count 수.
var crossCount = 0;
var crossLines = [];
// 가로 한 줄당 3목이 될 수 있는 대각선의 수. (수정 x)
var crossLope = totalLine - 2;
// 대각선(\) 로직 -leftCross
// 각각의 배열의 숫자를 slice로 구현하기 힘들기 때문에 따로 배열을 출력하여 다시 배열에 주입하였음
// 배열의 다음 값이 6만큼 증가 하므로 아래와 같이 구현.
// 첫번째 for는 승리하는 숫자인 가로 숫자가 연속으로 3번 있기 때문에 3번 루프를 걸어둠(ex - 0,5,10 / 5,10,15 / 10,15,20)
for(let x = 0; x < crossLope; x++) {
for(let y = 0; y < crossLope; y++) {
a = samMok.indexOf((y) + (crossCount));
b = samMok.indexOf((y) + (leftCross*1) + (crossCount));
c = samMok.indexOf((y) + (leftCross*2) + (crossCount));
lines.push([a,b,c]);
}
crossCount+=crossCountPlus;
}
// crossCount 초기값 설정
crossCount = 0;
// 대각선(/) 로직 - rightCross
// 각각의 배열의 숫자를 slice로 구현하기 힘들기 때문에 따로 배열을 출력하여 다시 배열에 주입하였음.
// 배열의 다음 값이 4만큼 증가 하므로 아래와 같이 구현.
// 첫번째 for는 승리하는 숫자인 가로 숫자가 연속으로 3번 있기 때문에 3번 루프를 걸어둠(ex - 2,3,4 / 7,8,9 / 12,13,14)
for(let x = 0; x < crossLope; x++) {
// y 초기값 2로 설정한 이유 : 5x5 오목판에서 3목 승리하는 조건이 [2,6,10] 이므로 가장 낮은 값인 2를 주었음.
for(let y = 2; y < crossLope + 2 ; y++) {
a = samMok.indexOf((y) + (crossCount));
b = samMok.indexOf((y) + (rightCross*1) + (crossCount));
c = samMok.indexOf((y) + (rightCross*2) + (crossCount));
lines.push([a,b,c]);
}
crossCount+=crossCountPlus;
}
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];
}
}
for (let i = 0; i < intaglio; i++) {
if (squares[i] === null) {
return null;
}
}
return intaglio; //In the case of a tie, return intaglio
}
상당히 긴 로직이지만 여러분들은 더 잘하시니 더 짧고 획기적인 방법으로 오목을 구현하실 수 있을거라 생각이 듭니다.
오늘도 수고 많으셨습니다!
'프로그래밍언어 > React' 카테고리의 다른 글
[React 도전기] 6x6 3목(오목 변형) (0) | 2021.06.21 |
---|---|
[React 도전기] 5x5 3목(오목 변형 버전) (0) | 2021.06.19 |
[React 도전기] 5x5 Tic Tac Toe(변형) (0) | 2021.06.17 |
[React 도전기] Tic Tac Toe (0) | 2021.06.16 |
[React 도전기] React 시작! (0) | 2021.06.11 |