사용자:Bd3076/대규모 실험실/8
< 사용자:Bd3076 | 대규모 실험실
/** 2048 plugin * 제작자: Bd3076 * 용도: 2048 MP에 사용될 플러그인 */ var api = MediaWikiAPI(); // 보드판 생성 var board = new Array(new Array(4), new Array(4), new Array(4), new Array(4)); for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ board[i][j] = 0; } } // 점수 생성 var myScore = 0; var maxScore = localStorage.getItem('maxScore'); if(maxScore === null) maxScore = 0; // 캔버스 구문 document.getElementById('gameArea').innerHTML = '<canvas id="cvs" width="800" height="600"></canvas>'; var canvas = document.getElementById('cvs'); var ctx = canvas.getContext('2d'); ctx.textAlign = "center"; ctx.textBaseline = "middle"; // 비어있는 칸이 있는지 판별하는 함수 var emptyExist = function(){ for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ if(!board[i][j]) return true; } } return false; }; // 비어있는 칸 중 하나를 랜덤으로 고르는 함수 var randomEmpty = function(){ var emptyArray = new Array(0); // 비어 있는 칸들의 목록 for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ if(!board[i][j]) emptyArray.push([i, j]); } } if(emptyArray.length === 0){ console.log("error: no empty slots"); return null; } return emptyArray[Math.floor(Math.random() * emptyArray.length)]; }; // 보드판의 상태를 캔버스에 그리는 함수 var drawBoard = function(){ // 숫자에 따른 색 var numberColor = ["#CDC1B4", "#EEE4DA", "#EDE0C8", "#F2B179", "#F59563", "#F67C5F", "#F6523B", // ~64 "#EDCF72", "#EDCC61", "#EDC850", "#EDC53F", "#EDC22E", "#EBB914", "#D3A612", // ~8192 "#BC9410", "#BC9410", "#BC9410", "#BC9410"]; // 보드판의 개형 그리기 ctx.fillStyle = "#BBADA0"; ctx.beginPath(); ctx.moveTo(0, 10); ctx.lineTo(0, 590); ctx.arc(10, 590, 10, Math.PI/2, Math.PI); ctx.lineTo(10, 600); ctx.lineTo(790, 600); ctx.arc(790, 590, 10, 0, Math.PI/2); ctx.lineTo(800, 590); ctx.lineTo(800, 10); ctx.arc(790, 10, 10, Math.PI*3/2, Math.PI*2); ctx.lineTo(790, 0); ctx.lineTo(10, 0); ctx.arc(10, 10, 10, Math.PI, Math.PI*3/2); ctx.closePath(); ctx.fill(); // 각 칸 그리기 for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ // 외형 그리기 var startX = 16 + 146*i; var startY = 16 + 146*j; ctx.fillStyle = numberColor[board[i][j] === 0 ? 0 : Math.round(Math.log2(board[i][j]))]; ctx.beginPath(); ctx.moveTo(startX, startY+4); ctx.lineTo(startX, startY+126); ctx.arc(startX+4, startY+126, 4, Math.PI/2, Math.PI); ctx.lineTo(startX+4, startY+130); ctx.lineTo(startX+126, startY+130); ctx.arc(startX+126, startY+126, 4, 0, Math.PI/2); ctx.lineTo(startX+130, startY+126); ctx.lineTo(startX+130, startY+4); ctx.arc(startX+126, startY+4, 4, Math.PI*3/2, Math.PI*2); ctx.lineTo(startX+126, startY); ctx.lineTo(startX+4, startY); ctx.arc(startX+4, startY+4, 4, Math.PI, Math.PI*3/2); ctx.closePath(); ctx.fill(); // 텍스트 그리기 if(board[i][j] !== 0){ var numberLength = board[i][j].toString().length; var fontSize = numberLength == 1 ? 80 : 160 / numberLength; ctx.fillStyle = "#776E65"; ctx.font = "bold " + fontSize + "px sans-serif"; console.log("bold " + fontSize + "px sans-serif"); ctx.fillText(board[i][j], startX+65, startY+65); } } } // 점수 그리기 ctx.fillStyle = "#f2ddaf"; ctx.font = "bold 30px sans-serif"; ctx.fillText("YOUR SCORE", 697, 33); ctx.fillStyle = "#EEE4DA"; ctx.beginPath(); ctx.moveTo(610, 76); ctx.lineTo(610, 140); ctx.arc(620, 140, 10, Math.PI/2, Math.PI); ctx.lineTo(620, 150); ctx.lineTo(774, 150); ctx.arc(774, 140, 10, 0, Math.PI/2); ctx.lineTo(784, 140); ctx.lineTo(784, 76); ctx.arc(774, 76, 10, Math.PI*3/2, Math.PI*2); ctx.lineTo(774, 66); ctx.lineTo(620, 66); ctx.arc(620, 76, 10, Math.PI, Math.PI*3/2); ctx.closePath(); ctx.fill(); ctx.fillStyle = "#776E65"; ctx.font = "bold 60px sans-serif"; ctx.fillText(myScore, 697, 108); // 최고점수 그리기 ctx.fillStyle = "#f2ddaf"; ctx.font = "bold 30px sans-serif"; ctx.fillText("MAX SCORE", 697, 33+180); ctx.fillStyle = "#EEE4DA"; ctx.beginPath(); ctx.moveTo(610, 76+180); ctx.lineTo(610, 140+180); ctx.arc(620, 140+180, 10, Math.PI/2, Math.PI); ctx.lineTo(620, 150+180); ctx.lineTo(774, 150+180); ctx.arc(774, 140+180, 10, 0, Math.PI/2); ctx.lineTo(784, 140+180); ctx.lineTo(784, 76+180); ctx.arc(774, 76+180, 10, Math.PI*3/2, Math.PI*2); ctx.lineTo(774, 66+180); ctx.lineTo(620, 66+180); ctx.arc(620, 76+180, 10, Math.PI, Math.PI*3/2); ctx.closePath(); ctx.fill(); ctx.fillStyle = "#776E65"; ctx.font = "bold 60px sans-serif"; ctx.fillText(maxScore, 697, 108+180); }; // 키보드 입력을 받아 판을 이동시키고, 새로운 숫자를 만들거나 게임 오버시키는 함수 $("#left").click(function(){ gameRunner({keyCode: 37})}); $("#up").click(function(){ gameRunner({keyCode: 38})}); $("#right").click(function(){ gameRunner({keyCode: 39})}); $("#down").click(function(){ gameRunner({keyCode: 40})}); var gameRunner = function(e){ var ek = e.keyCode; var cnt; var moved = 0; var added = new Array(new Array(4), new Array(4), new Array(4), new Array(4)); for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ added[i][j] = 0; } } console.log(ek); // 판 움직이기 if(37 <= ek && ek <= 40) e.preventDefault(); switch(ek){ case 37: for(var j=0; j<4; j++){ cnt = 0; for(var i=0; i<4; i++){ if(i>0 && board[i][j] !== 0 && board[i-1][j] === 0){ board[cnt++][j] = board[i][j]; board[i][j] = 0; moved = 1; if(cnt > 1 && board[cnt-1][j] == board[cnt-2][j] && !added[cnt-2][j]){ board[cnt-2][j] *= 2; board[cnt-1][j] = 0; cnt--; added[cnt-1][j] = 1; myScore += board[cnt-1][j]; } } else if(board[i][j] !== 0){ cnt++; if(cnt > 1 && board[cnt-1][j] == board[cnt-2][j] && !added[cnt-2][j]){ moved = 1; board[cnt-2][j] *= 2; board[cnt-1][j] = 0; cnt--; added[cnt-1][j] = 1; myScore += board[cnt-1][j]; } } } } if(!moved) return; break; case 38: for(var i=0; i<4; i++){ cnt = 0; for(var j=0; j<4; j++){ if(j>0 && board[i][j] !== 0 && board[i][j-1] === 0){ board[i][cnt++] = board[i][j]; board[i][j] = 0; moved = 1; if(cnt > 1 && board[i][cnt-1] == board[i][cnt-2] && !added[i][cnt-2]){ board[i][cnt-2] *= 2; board[i][cnt-1] = 0; cnt--; added[i][cnt-1] = 1; myScore += board[i][cnt-1]; } } else if(board[i][j] !== 0){ cnt++; if(cnt > 1 && board[i][cnt-1] == board[i][cnt-2] && !added[i][cnt-2]){ moved = 1; board[i][cnt-2] *= 2; board[i][cnt-1] = 0; cnt--; added[i][cnt-1] = 1; myScore += board[i][cnt-1]; } } } } if(!moved) return; break; case 39: for(var j=0; j<4; j++){ cnt = 0; for(var i=3; i>=0; i--){ if(i<3 && board[i][j] !== 0 && board[i+1][j] === 0){ board[3-(cnt++)][j] = board[i][j]; board[i][j] = 0; moved = 1; if(cnt > 1 && board[3-(cnt-1)][j] == board[3-(cnt-2)][j] && !added[3-(cnt-2)][j]){ board[3-(cnt-2)][j] *= 2; board[3-(cnt-1)][j] = 0; cnt--; added[3-(cnt-1)][j] = 1; myScore += board[3-(cnt-1)][j]; } } else if(board[i][j] !== 0){ cnt++; if(cnt > 1 && board[3-(cnt-1)][j] == board[3-(cnt-2)][j] && !added[3-(cnt-2)][j]){ moved = 1; board[3-(cnt-2)][j] *= 2; board[3-(cnt-1)][j] = 0; cnt--; added[3-(cnt-1)][j] = 1; myScore += board[3-(cnt-1)][j]; } } } } if(!moved) return; break; case 40: for(var i=0; i<4; i++){ cnt = 0; for(var j=3; j>=0; j--){ if(j<3 && board[i][j] !== 0 && board[i][j+1] === 0){ board[i][3-(cnt++)] = board[i][j]; board[i][j] = 0; moved = 1; if(cnt > 1 && board[i][3-(cnt-1)] == board[i][3-(cnt-2)] && !added[i][3-(cnt-2)]){ board[i][3-(cnt-2)] *= 2; board[i][3-(cnt-1)] = 0; cnt--; added[i][3-(cnt-1)] = 1; myScore += board[i][3-(cnt-1)]; } } else if(board[i][j] !== 0){ cnt++; if(cnt > 1 && board[i][3-(cnt-1)] == board[i][3-(cnt-2)] && !added[i][3-(cnt-2)]){ moved = 1; board[i][3-(cnt-2)] *= 2; board[i][3-(cnt-1)] = 0; cnt--; added[i][3-(cnt-1)] = 1; myScore += board[i][3-(cnt-1)]; } } } } if(!moved) return; break; default: return; } // 숫자 추가 var aNum = (Math.random() < 0.875) ? 2 : 4; var re = randomEmpty(); board[re[0]][re[1]] = aNum; // 최고점수 갱신 if(maxScore < myScore){ maxScore = myScore; localStorage.setItem('maxScore', maxScore); } drawBoard(); // 게임 오버 감지 for(var i=0; i<4; i++){ for(var j=0; j<4; j++){ if(board[i][j] === 0) return; } } for(var i=0; i<4; i++){ for(var j=0; j<3; j++){ if(board[i][j] == board[i][j+1]) return; } } for(var i=0; i<3; i++){ for(var j=0; j<4; j++){ if(board[i][j] == board[i+1][j]) return; } } window.onkeydown = undefined; setTimeout(gameOver, 2000); }; function gameOver(){ ctx.fillStyle = "rgba(187, 171, 160, 0.2)"; ctx.fillRect(0, 0, 800, 600); ctx.fillStyle = "black"; ctx.font = "bold 100px sans-serif"; ctx.fillText("Game Over", 300, 300); ctx.font = "bold 20px sans-serif"; ctx.fillText("다시 시작하려면 새로고침하세요", 300, 450); var username = mw.config.get('wgUserName'); if(username === null){ ctx.fillText("랭킹에 결과를 등록하기 위해서는 로그인이 필요합니다", 300, 500); } else{ updateRanking(); ctx.fillText("랭킹은 게임 토론 메뉴에서 확인 가능합니다", 300, 500); } return; } function scoreData(){ var score; var name; var time; } var bigger = function(a, b){ if(a.score != b.score) return a.score > b.score; return a.time < b.time; } function updateRanking(){ var username = mw.config.get('wgUserName'); var rankingDoc = api.getDocument("2048 MP/Ranking"); var json = JSON.parse(rankingDoc); var myData = new scoreData(); myData.score = myScore; myData.name = mw.config.get('wgUserName'); myData.time = Date.now(); var rnum = undefined; // 랭킹 구조 // json[data]: 구조체 데이터 // json[rank]: 각 사람별 등수 for(var i=json['data'].length-1; i>=0; i--){ if(bigger(myData, json['data'][i])){ json['data'][i+1] = json['data'][i]; if(json['rank'][json['data'][i].name] === undefined || json['rank'][json['data'][i].name] == i){ json['rank'][json['data'][i].name] = i+1; } json['data'][i] = null; } else{ json['data'][i+1] = myData; rnum = i+2; break; } } if(rnum === undefined){ json['data'][0] = myData; rnum = 1; } if(!(json['rank'][myData.name] === undefined && json['rank'][myData.name] < rnum)){ json['rank'][myData.name] = rnum; } console.log(json); api.changeDocument('2048 MP/ranking', '랭킹 갱신', JSON.stringify(json), 1, 1); } // 초기 보드판 상태: 2 또는 4가 총 2개 나오고, 4가 나올 확률은 각각 1/8 var sNum1 = (Math.random() < 0.875) ? 2 : 4; var sNum2 = (Math.random() < 0.875) ? 2 : 4; var re1 = randomEmpty(); board[re1[0]][re1[1]] = sNum1; var re2 = randomEmpty(); board[re2[0]][re2[1]] = sNum2; // 판 그리기 drawBoard(); window.onkeydown = gameRunner;
로딩 중입니다...