html - Checking function for sliding puzzle javascript -
i created sliding puzzle different formats like: 3x3, 3x4, 4x3 , 4x4. when run code can see on right side selection box can choose 4 formats. slidingpuzzle done. but need function checks after every move if puzzle solved , if case should give out line "congrantulations solved it!" or "you won!". idea how make work?
in javascript code can see first function loadfunc() replace every piece blank 1 , functions after select format , change format it. function shiftpuzzlepieces makes can move each piece blank space. function shuffle randomizes every pieces position. if have more question or understanding issues feel free ask in comments. many in advance.
since don't have enough reputation post link images here: http://imgur.com/a/2nmlt . these images placeholders right now.
here jsfiddle: http://jsfiddle.net/cuttingtheaces/vkyxgwo6/19/
as always, there "hacky", easy way this, , there more elegant 1 requires significant changes code.
hacky way
to accomplish fast , dirty possible, go parsing id
-s of pieces check if in correct order, because have handy pattern "position" + it's expected index or "blank"
:
function isfinished() { var puzzleel = document.getelementbyid('slidingpuzzlecontainer').children[0]; // convert live list of child elements regular array var pieces = [].slice.call(puzzleel.children); return pieces .map(function (piece) { return piece.id.substr(8); // strip "position" prefix }) .every(function (id, index, arr) { if (arr.length - 1 == index) { // last peace, check if it's blank return id == "blank"; } // check every piece has index matches expected position return index == parseint(id); }); }
now need check somewhere, , naturally best place after each move, shiftpuzzlepieces()
should updated call isfinished()
function, , show finishing message if returns true
:
function shiftpuzzlepieces(el) { // ... if (isfinished()) { alert("you won!"); } }
and voilĂ : live version.
how implement game
for me, proper way of implementing track current positions of pieces in data structure , check in similar way, without traversing dom or checking node's id-s. also, allow implement react.js application: onclick handler mutate current game's state , render dom.
here how implement game:
/** * provides initial state of game * default size 4x4 */ function initialstate() { return { x: 4, y: 4, started: false, finished: false }; } /** * inits game */ function initgame() { var gamecontainer = document.queryselector("#slidingpuzzlecontainer"); var gamestate = initialstate(); initformatcontrol(gamecontainer, gamestate); initgamecontrols(gamecontainer, gamestate); // kick-off rendering render(gamecontainer, gamestate); } /** * handles clicks on container element */ function initgamecontrols(gamecontainer, gamestate) { gamecontainer.addeventlistener("click", function hanldeclick(event) { if (!gamestate.started || gamestate.finished) { // game didn't started yet or finished, ignore clicks return; } if (event.target.classname.indexof("piece") == -1) { // click somewhere not on piece (like, margins between them) return; } // try move piece somewhere movepiece(gamestate, parseint(event.target.dataset.index)); // check if we're done here checkfinish(gamestate); // render state of game render(gamecontainer, gamestate); event.stoppropagation(); return false; }); } /** * checks whether game finished */ function checkfinish(gamestate) { gamestate.finished = gamestate.pieces.every(function(id, index, arr) { if (arr.length - 1 == index) { // last peace, check if it's blank return id == "blank"; } // check every piece has index matches expected position return index == id; }); } /** * moves target piece around if there's blank somewhere near */ function movepiece(gamestate, targetindex) { if (isblank(targetindex)) { // ignore clicks on "blank" piece return; } var blankpiece = findblankaround(); if (blankpiece == null) { // go :( return; } swap(targetindex, blankpiece); function findblankaround() { var = targetindex - gamestate.x; if (targetindex >= gamestate.x && isblank(up)) { return up; } var down = targetindex + gamestate.x; if (targetindex < ((gamestate.y - 1) * gamestate.x) && isblank(down)) { return down; } var left = targetindex - 1; if ((targetindex % gamestate.x) > 0 && isblank(left)) { return left; } var right = targetindex + 1; if ((targetindex % gamestate.x) < (gamestate.x - 1) && isblank(right)) { return right; } } function isblank(index) { return gamestate.pieces[index] == "blank"; } function swap(i1, i2) { var t = gamestate.pieces[i1]; gamestate.pieces[i1] = gamestate.pieces[i2]; gamestate.pieces[i2] = t; } } /** * handles form selecting , starting game */ function initformatcontrol(gamecontainer, state) { var formatcontainer = document.queryselector("#formatcontainer"); var formatselect = formatcontainer.queryselector("select"); var formatapply = formatcontainer.queryselector("button"); formatselect.addeventlistener("change", function(event) { formatapply.disabled = false; }); formatcontainer.addeventlistener("submit", function(event) { var rawvalue = event.target.format.value; var value = rawvalue.split("x"); // update state state.x = parseint(value[0], 10); state.y = parseint(value[1], 10); state.started = true; state.pieces = generatepuzzle(state.x * state.y); // render game render(gamecontainer, state); event.preventdefault(); return false; }); } /** * renders game's state container element */ function render(container, state) { var numberofpieces = state.x * state.y; updateclass(container, state.x, state.y); clear(container); var containerhtml = ""; if (!state.started) { (var = 0; < numberofpieces; i++) { containerhtml += renderpiece("", i) + "\n"; } } else if (state.finished) { containerhtml = "<div class='congratulation'><h2 >you won!</h2><p>press 'play!' start again.</p></div>"; } else { containerhtml = state.pieces.map(renderpiece).join("\n"); } container.innerhtml = containerhtml; function renderpiece(id, index) { return "<div class='piece' data-index='" + index + "'>" + id + "</div>"; } function updateclass(container, x, y) { container.classname = "slidingpuzzlecontainer" + x + "x" + y; } function clear(container) { container.innerhtml = ""; } } /** * generates shuffled array of id-s ready rendered */ function generatepuzzle(n) { var pieces = ["blank"]; (var = 0; < n - 1; i++) { pieces.push(i); } return shufflearray(pieces); function shufflearray(array) { (var = array.length - 1; > 0; i--) { var j = math.floor(math.random() * (i + 1)); var temp = array[i]; array[i] = array[j]; array[j] = temp; } return array; } }
body { font-family: "lucida grande", "lucida sans unicode", verdana, helvetica, arial, sans-serif; font-size: 12px; color: #000; } #formatcontainer { position: absolute; top: 50px; left: 500px; } #formatcontainer label { display: inline-block; max-width: 100%; margin-bottom: 5px; } #formatcontainer select { display: block; width: 100%; margin-top: 10px; margin-bottom: 10px; } #formatcontainer button { display: inline-block; width: 100%; } .piece { width: 96px; height: 96px; margin: 1px; float: left; border: 1px solid black; } .slidingpuzzlecontainer3x3, .slidingpuzzlecontainer3x4, .slidingpuzzlecontainer4x3, .slidingpuzzlecontainer4x4 { position: absolute; top: 50px; left: 50px; border: 10px solid black; } .slidingpuzzlecontainer3x3 { width: 300px; height: 300px; } .slidingpuzzlecontainer3x4 { width: 300px; height: 400px; } .slidingpuzzlecontainer4x3 { width: 400px; height: 300px; } .slidingpuzzlecontainer4x4 { width: 400px; height: 400px; } .congratulation { margin: 10px; } }
<body onload="initgame();"> <div id="slidingpuzzlecontainer"></div> <form id="formatcontainer"> <label for="format">select format:</label> <select name="format" id="format" size="1"> <option value="" selected="true" disabled="true"></option> <option value="3x3">format 3 x 3</option> <option value="3x4">format 3 x 4</option> <option value="4x3">format 4 x 3</option> <option value="4x4">format 4 x 4</option> </select> <button type="submit" disabled="true">play!</button> </form> </body>
here have initgame()
function starts everything. when called create initial state of game (we have default size , state properties care there), add listeners on controls , call render()
function current state.
initgamecontrols()
sets listener clicks on field 1) call movepiece()
try move clicked piece on blank spot if former somewhere around, 2) check if after move game finished checkfinish()
, 3) call render()
updated state.
now render()
pretty simple function: gets state , updates dom on page accordingly.
utility function initformatcontrol()
handles clicks , updates on form field size selection, , when 'play!' button pressed generate initial order of pieces on field , call render()
new state.
the main benefit of approach functions decoupled 1 another: can tweak logic finding blank space around target piece, allow, example, swap pieces adjacent ids, , functions rendering, initialization , click handling stay same.
Comments
Post a Comment