8 Replies - 601 Views - Last Post: 15 January 2013 - 01:25 PM

#1 njgmoorman  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 65
  • Joined: 02-October 12

Very strange issue with table duplicating image

Posted 15 January 2013 - 05:58 AM

I know that title was most likely confusing, so let me clarify. I've got a table with random cells containing images that are set not to display until their container cell is clicked. All that works but when the cell is clicked, the top row does something really strange and hard to explain. I've included all three files so you can see for yourself.

JS:

var i, winloss, hw, mines, tdCounter, trCounter, tdClass;
// radios = document.getElementById("form").childNodes;
//table = document.getElementById("game");
var difficulty = "";
var table;
i=0;
winloss="";
tdCounter = 0;
var imgs = [];
function askNewGame() {
	alert("You " + winloss +" To play again, choose a difficulty.");
}
//var div = document.getElementById("div2");
function makeGame(hw, mines, tdClass) {
	table = document.createElement("table");
	table.id = "game";
	document.getElementById("div2").appendChild(table);
	for (trCounter=0;trCounter<hw;trCounter++) {
		var tr = table.insertRow(trCounter);
		tr.id = ("row" + trCounter.toString());
		for (tdCounter=0;tdCounter<hw;tdCounter++) {
			var td = document.getElementById(("row" + trCounter.toString())).insertCell(tdCounter);
			td.className = tdClass;
			td.innerHTML = "<strong></strong>";
			//document.getElementById("row" + trCounter.toString()).appendChild(td);
		}
	}
	genMines();
	/*if (tableChildren) {
		tableChildren = table.childNodes;
	}
	else {
		var tableChildren = table.childNodes;
	}*/
}

function newGame(difficulty) {
	switch (difficulty) {
		case 1:
		hw=5;
		mines=5;
		tdClass = "beginner";
		break;
		
		case 2:
		hw=7;
		mines=20;
		tdClass = "easy";
		break;
		
		case 3:
		hw=10;
		mines=25;
		tdClass = "medium";
		break;
		
		case 4:
		hw=20;
		mines=100;
		tdClass = "hard";
		break;
		
		case 5:
		hw=30;
		mines=450;
		tdClass = "expert";
		break;
	}
	makeGame(hw, mines, tdClass);
}
function gameOver() {
	winloss = "Lost.";
	for (var e=0;e<imgs.length;e++) {
		if (imgs[e].hasAttribute("style")) {
			/*var bomb = document.createElement("img");
			bomb.setAttribute("src", "mine.png");
			tds[e].appendChild(bomb);*/
			//tds[e].innerHTML = "<img src='mine.png' />";
			imgs[e].removeAttribute("style");
		}
	}
	askNewGame();
}

function clearTable() {
	if (table) {
		/*if (table.childNodes !== undefined) {
			if (tableChildren) {
				tableChildren = table.childNodes;
			}
			else {
				var tableChildren = table.childNodes;
			}
			for (i=0;i<tableChildren.length;i++) {
				table.removeChild(tableChildren[i]);
			}
		}*/
		table.parentNode.removeChild(table);
	}
}

function genMines() {
	var tds = table.getElementsByTagName("td");
	var mineCount;
	for (mineCount=0;mineCount<=mines;mineCount++) {
		var index = Math.floor(Math.random()*((hw*hw)-1) + 0);
		tds[index].onclick = function() {
			gameOver();
		};
		var bomb = document.createElement("img");
		bomb.style.display = "none";
		bomb.setAttribute("src", "mine.png");
		tds[index].appendChild(bomb);
		//tds[index].onclick = gameOver;
		//tds[index].className = (tdClass + " mined");
	}
	imgs = table.getElementsByTagName("img");
}
/*function aC() {
	if (allChildren) {
		allChildren = table.childNodes;
	}
	else {
		var allChildren = [];
	}
}*/


HTML:

<!DOCTYPE HTML>
<html>
<head>
	<meta charset="utf-8">
	<title>Minesweeper</title>
	<script src="minesweeper.js" type="text/javascript"></script>
	<link rel="stylesheet" href="minesweeper.css" type="text/css" />
</head>
<body>
	<div>
		<form id="form">
			<input type="radio" name="radio" value="1" onclick="clearTable();newGame(1);" /><label> - BEGINNER</label>
			<input type="radio" name="radio" value="2" onclick="clearTable();newGame(2);" /><label> - EASY</label>
			<input type="radio" name="radio" value="3" onclick="clearTable();newGame(3);" /><label> - MEDIUM</label>
			<input type="radio" name="radio" value="4" onclick="clearTable();newGame(4);" /><label> - HARD</label>
			<input type="radio" name="radio" value="5" onclick="clearTable();newGame(5);" /><label> - EXPERT</label>
		</form>
	</div>
	<div id="div2">
		<strong>Minesweeper</strong>
		<!--<table id="game">
		</table>-->
	</div>
</body>
</html>


CSS:

td {
	border: 3px solid #555;
}

.beginner {
	width: 100px;
	height: 100px;
}

.easy {
	width: 71px;
	height: 71px;
}

.medium {
	width: 50px;
	height: 50px;
}

.hard {
	width: 25px;
	height: 25px;
}

.expert {
	width: 16px;
	height: 16px;
}

.beginner img {
	width: 95px;
	height: 95px;
}

.easy img {
	width: 68px;
	height: 68px;
}

.medium img {
	width: 47px;
	height: 47px;
}

.hard img {
	width: 20px;
	height: 20px;
}

.expert img {
	width: 12px;
	height: 12px;
}

.mined {
	
}


Is This A Good Question/Topic? 0
  • +

Replies To: Very strange issue with table duplicating image

#2 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3326
  • View blog
  • Posts: 11,250
  • Joined: 12-December 12

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 06:43 AM

I can't see anything specific to the first row(?), but some boxes often include more than one mine. This is because when you generate the random number you need to check whether the cell already contains a mine. If so, try a new random number.

Also, you are creating one more mine than you originally requested. Use < rather than <=

for (mineCount=0; mineCount < mines; mineCount++) {

BTW You should avoid the use of getAttribute, setAttribute, removeAttribute. You can set properties of elements directly:

some_element.src = "someimage.png";

I suspect that you can achieve what you need by changing class-names. That is, one class will have a background image, and the other won't.

This post has been edited by andrewsw: 15 January 2013 - 06:48 AM

Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3326
  • View blog
  • Posts: 11,250
  • Joined: 12-December 12

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 06:51 AM

Perhaps something like:

.mine_yes {
    background-image: url('mine.png');
}
.mine_no {
    background-image: none;
}


but this is just a suggestion :) as I appreciate it would involve a re-write :dontgetit:

This post has been edited by andrewsw: 15 January 2013 - 06:54 AM

Was This Post Helpful? 0
  • +
  • -

#4 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3515
  • View blog
  • Posts: 10,142
  • Joined: 08-June 10

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 07:15 AM

you should check the mine count in the table. then it will become obvious.

recommended reading!


(raise a note if I should tell my opinions about th code)

This post has been edited by Dormilich: 15 January 2013 - 07:19 AM

Was This Post Helpful? 0
  • +
  • -

#5 njgmoorman  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 65
  • Joined: 02-October 12

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 08:52 AM

I get what I did wrong but I can't seem to figure out how to get it to generate the random number for the index and never repeat it again. I would just use splice(); but unfortunately getElementsByTagName returns a pesky little nodeList. Can someone write a function that returns a random number and never repeats it again? Please make sure it uses Math.random();
Was This Post Helpful? 0
  • +
  • -

#6 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3515
  • View blog
  • Posts: 10,142
  • Joined: 08-June 10

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 09:06 AM

why would you want to operate on the NodeList? it suffices to know the index numbers which range from 0 to length-1.

and filling an array with non-repeating numbers should be a programming task no too difficult.
Was This Post Helpful? 0
  • +
  • -

#7 njgmoorman  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 65
  • Joined: 02-October 12

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 09:15 AM

I'm encountering a completely different, stranger problem now. For some reason, the game only works on one difficulty, beginner. I have changed a few things so that the nodeList is and array. Also, the error firebug throws when I try other difficulties says mineTDS[index] is undefined. It doesn't throw that on beginner and it throws it on
mineTDS[index].onclick = function() {

Here's the full genMines function. You shouldn't need the other code.
function genMines() {
	var tds = table.getElementsByTagName("td");
	var mineTDS = [];
	for(i=0, n; n = tds[i]; i++) {
		mineTDS.push(n);
	}
	var mineCount;
	for (mineCount=0;mineCount<mines;mineCount++) {
		var index = Math.floor(Math.random()*((hw*hw)-1) + 0);
		mineTDS[index].onclick = function() {
			gameOver();
		};
		var bomb = document.createElement("img");
		bomb.style.display = "none";
		bomb.setAttribute("src", "mine.png");
		mineTDS[index].appendChild(bomb);
		mineTDS.splice(index, 1);
		//tds[index].onclick = gameOver;
		//tds[index].className = (tdClass + " mined");
	}
	imgs = table.getElementsByTagName("img");
}

Was This Post Helpful? 0
  • +
  • -

#8 Dormilich  Icon User is online

  • 痛覚残留
  • member icon

Reputation: 3515
  • View blog
  • Posts: 10,142
  • Joined: 08-June 10

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 09:20 AM

since mineTDS gets successively smaller, the probability of index being outside of the available index range increases. at some point you get an undefined offset.

my recommendation is to solely work on the indexes, not on the list of elements itself.

PS.
mineTDS[index].onclick = gameOver;

This post has been edited by Dormilich: 15 January 2013 - 09:22 AM

Was This Post Helpful? 0
  • +
  • -

#9 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3326
  • View blog
  • Posts: 11,250
  • Joined: 12-December 12

Re: Very strange issue with table duplicating image

Posted 15 January 2013 - 01:25 PM

I obviously have too much time on my hands.. but I'll post my version here for study purposes!

<!DOCTYPE html>
<html>
<head>
<title>Mine Sweeper</title>
<style type="text/css">
    label, input {
        display: inline-block;
    }
    
    #minefield {
        border: 2px solid black;
    }
    td {
        border: 2px solid blue;
        width: 30px; height: 30px;
    }
    .mine_clear {
        background: url('images/checktick.png') center center no-repeat;
    }
    .mine_no {
        background: none;
    }
    .mine_yes {
        background: url('images/checkcross.png') center center no-repeat;
    }
</style>
</head>
<body>
<h1>Mine Sweeper</h1>
<p>
<label for="lvlB">Beginner</label>
<input type="radio" id="lvlB" name="level" value="B" checked>
<label for="lvlI">Intermediate</label>
<input type="radio" id="lvlI" name="level" value="I">
<label for="lvlA">Advanced</label>
<input type="radio" id="lvlA" name="level" value="A">
</p>
<button id="bNewGame">New Game</button>
<label>Cheat? <input type="checkbox" id="ckbCheat"> (on next game)</label>

<table id="minefield" summary="Mine sweeper game">
    <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
    <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
    <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
    <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
    <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
</table>

<script type="text/javascript">

var theMines = [];      // store location of live mines

var addEvent = function (elem, eventType, func) {
    if ( elem.addEventListener )
        addEvent = function (elem, eventType, func) {
            elem.addEventListener(eventType, func, false);
        };
    else if ( elem.attachEvent )
        addEvent = function (elem, eventType, func) {
            elem.attachEvent('on' + eventType, func);
        };
    addEvent(elem, eventType, func);
};
var removeEvent = function (elem, eventType, func) {
    if ( elem.removeEventListener )
        removeEvent = function (elem, eventType, func) {
            elem.removeEventListener(eventType, func, false);
        };
    else if ( elem.detachEvent )
        removeEvent = function (elem, eventType, func) {
            elem.detachEvent('on' + eventType, func);
        };
    removeEvent(elem, eventType, func);
};
var delegateEvent = function (elem, childElems, eventType, func, args) {
    elem.dlgEvent = function (e) {
        var evt = e || window.event;
        var elem = evt.target || evt.srcElement;
        if ( elem.nodeName.toLowerCase() == childElems.toLowerCase() ) {
            func(elem, args);
        }
    };
    addEvent(elem, eventType, elem.dlgEvent);
};

function checkMine(theCell, args) {
    var mineField =  document.getElementById(args.fieldname);
    var squareSize = args.square, celli;
    var theSquares = mineField.getElementsByTagName('td');
    var theRow = theCell.parentNode;
    
    if ( theRow.nodeName == 'TR') {
        celli = (squareSize * theRow.rowIndex) + theCell.cellIndex;
        if (theMines.indexOf(celli) >= 0) {
            theSquares[celli].className = 'mine_yes';
            alert('You lose, sucker!');
            showMines(mineField);
        } else {
            if (theSquares[celli].className != 'mine_clear') {
                // make sure they are not clicking the same
                // box more than once!
                args.blanks--;
            }
            theSquares[celli].className = 'mine_clear';
            if (!args.blanks) {
                alert('You win!');
                showMines(mineField);
            }
        }
    }
}

function showMines(mineField) {
    removeEvent(mineField, 'click', mineField.dlgEvent);
    var theSquares = mineField.getElementsByTagName('td');
    var squLen = theSquares.length;
    for (var i=0; i < squLen; i++) {
        if (theMines.indexOf(i) >= 0) {
            theSquares[i].className = 'mine_yes';
        } else {
            theSquares[i].className = 'mine_clear';
        }
    }
}

function newGame(fieldname) {
    var mineField = document.getElementById(fieldname);
    if (mineField.dlgEvent) {
        try {
            removeEvent(mineField, 'click', mineField.dlgEvent);
        } catch (err) {
            // do nothing
        }
    }
    var levels = document.getElementsByName('level');
    var levelsLen = levels.length;
    var ran, i, squSize, mines;
    
    theMines = [];      // empty the array
    
    for (i=0; i < levelsLen; i++) {
        if (levels[i].checked) {
            switch (levels[i].value) {
                case "B":
                    squSize = 5;
                    mines = 5;
                    break;
                case "I":
                    squSize = 8;
                    mines = 30;
                    break;
                case "A":
                default:
                    squSize = 10;
                    mines = 50;
                    break;
            }
            break;
        }
    }
    var theSquares = mineField.getElementsByTagName('td');
    var squLen = theSquares.length;
    if (squLen != (squSize * squSize)) {
        newTable(mineField, squSize);
        theSquares = mineField.getElementsByTagName('td');
        squLen = theSquares.length;
    }
    for (i=0; i < squLen; i++) {
        theSquares[i].className = 'mine_no';
        // remove previous cheat-squares
        theSquares[i].style.backgroundColor = '';
    }
    for (i=0; i < mines; i++) {
        ran = Math.floor(Math.random()*(squSize * squSize));
        while (theMines.indexOf(ran) >= 0) {
            // already a mine, keep trying..
            ran = Math.floor(Math.random()*(squSize * squSize));
        }
        theMines.push(ran);     // game == [23, 6, 12, 3, 1], for example.
        theSquares[ran].style.backgroundColor =
            document.getElementById('ckbCheat').checked ? 'blue' : '';
    }
    delegateEvent(mineField, 'td', 'click', checkMine,
            { fieldname: 'minefield', square: squSize,
            blanks: ((squSize * squSize) - mines) } );
}

function newTable(mineField, size) {
    mineField.innerHTML = "";    // remove all cells
    var i = 0, j = 0, newRow, newCell;
    for (; i < size; i++) {
        newRow = mineField.insertRow(-1);
        for (j=0; j < size; j++) {
            newCell = newRow.insertCell(-1);
            newCell.className = 'mine_no';
        }
    }
}

function init() {
    var btnGo = document.getElementById('bNewGame');
    addEvent(btnGo, 'click', function (e) {
        newGame('minefield');
    });
    newGame('minefield');
}

addEvent(window, 'load', init);
</script>
</body>
</html>


It requires two small images, as indicated in the CSS. It's a functional, rather than OOP, version.

Added: Just remembered that the real MineSweeper clears mines in the vicinity. I shall leave this as an exercise :)/>

This post has been edited by andrewsw: 15 January 2013 - 02:11 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1