Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: Array.reverse() - Blocks my Script

  1. #1
    Join Date
    Jul 2006
    Posts
    497
    Thanks
    8
    Thanked 70 Times in 70 Posts

    Default Array.reverse() - Blocks my Script

    I'm making a simple Mancala application (using Firefox - IE6 only shows the holes at the ends) and reversing an array strangely causes the entire script to fail. I must reverse the array because Hole 1 is reacting to a click on 6, Hole 4 to a click on 3, etc. Here's the code (saved as mancala.js), with a comment next to the line where I toggle ".reverse()" to produce the error.

    Code:
    // JavaScript Document
    var current = 0;
    var players = new Array(2);
    function Player(n){
    	this.hasTurn = false;
    	this.mancala = document.getElementById("p" + n);
    	this.holes = document.getElementsByName("p" + n);// <-line in question
    	this.turn = function(){
    		this.hasTurn = true;
    		this.mancala.style.backgroundColor = "red";
    		for(i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "red";
    	}
    	this.grab = function(n){
    		var where;
    		stones = this.holes[n - 1].innerHTML;
    		for(this.holes[n - 1].innerHTML = 0; stone > 0; stones--){
    			where = (stones - n) &#37; 13;
    			this.get(where).innerHTML++;
    		}
    		if(where != 0){
    			this.hasTurn = false;
    			this.mancala.style.backgroundColor = "white";
    			for(i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "white";
    			change();
    		}
    	}
    	this.get = function(n){
    		n = n % 13;
    		switch(n){
    			case 0:
    				return this.mancala;
    			default:
    				alert('uncaught: get(' + n + ')');
    		}
    	}
    }
    function change(){
    	if(current == 1) player[current = 0].turn();
    	else player[current = 1].turn();
    }
    function next(){
    	return current == 1 ? player[0] : player[1];
    }
    function init(s){
    	players[0] = new Player(1);
    	players[1] = new Player(2);
    	for(i1 = 0; i1 < 2; i1++){
    		players[i1].mancala.innerHTML = 0;
    		for(i2 = 0; i2 < players[i1].holes.length; i2++) players[i1].holes[i2].innerHTML = s;
    	}
    	players[0].turn();
    }
    And my page:
    HTML Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    		<link rel="stylesheet" type="text/css" href="mancala.css"/>
    		<title>Mancala</title>
    		<script type="text/javascript" src="mancala.js"></script>
    	</head>
    	<body onLoad="init(4)">
    		<table border="1" bordercolor="#000000" width="100%" height="100%">
    			<tr>
    				<td class="mancala" id="p2" rowspan="2"></td>
    				<td class="hole" name="p2" id="2-1" onClick="players[1].grab(1)"></td>
    				<td class="hole" name="p2" id="2-2" onClick="players[1].grab(2)"></td>
    				<td class="hole" name="p2" id="2-3" onClick="players[1].grab(3)"></td>
    				<td class="hole" name="p2" id="2-4" onClick="players[1].grab(4)"></td>
    				<td class="hole" name="p2" id="2-5" onClick="players[1].grab(5)"></td>
    				<td class="hole" name="p2" id="2-6" onClick="players[1].grab(6)"></td>
    				<td class="mancala" id="p1" rowspan="2"></td>
    			</tr>
    			<tr>
    				<td class="hole" name="p1" id="1-6" onClick="players[0].grab(6)"></td>
    				<td class="hole" name="p1" id="1-5" onClick="players[0].grab(5)"></td>
    				<td class="hole" name="p1" id="1-4" onClick="players[0].grab(4)"></td>
    				<td class="hole" name="p1" id="1-3" onClick="players[0].grab(3)"></td>
    				<td class="hole" name="p1" id="1-2" onClick="players[0].grab(2)"></td>
    				<td class="hole" name="p1" id="1-1" onClick="players[0].grab(1)"></td>
    			</tr>
    		</table>
    	</body>
    </html>
    EDIT: The question: How can I use reverse() while avoiding the failure?
    Last edited by Jesdisciple; 08-11-2007 at 11:39 PM.

  2. #2
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    You've made the common mistake of thinking that DOM methods return arrays. They don't. That's not an array, it's a collection, and as such it doesn't have a lot of the methods arrays have. However, they can still be used with those methods; you just have to call them manually:
    Code:
            this.holes = Array.prototype.reverse.call(document.getElementsByName("p" + n));
    As for the rest of your script and page:
    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    This DOCTYPE has been unnecessary for a good decade or so. Use Strict.
    Code:
                    <link rel="stylesheet" type="text/css" href="mancala.css"/>
    This XML-style ending syntax doesn't mean what you think it means in HTML, and what it does mean few browsers support.
    Code:
    <table border="1" bordercolor="#000000" width="100&#37;" height="100%">
    Avoid this presentational markup -- there's no reason not to use CSS.
    Code:
                            <tr>
                                    <td class="mancala" id="p2" rowspan="2"></td>
                                    <td class="hole" name="p2" id="2-1" onClick="players[1].grab(1)"></td>
                                    <td class="hole" name="p2" id="2-2" onClick="players[1].grab(2)"></td>
                                    <td class="hole" name="p2" id="2-3" onClick="players[1].grab(3)"></td>
    <!-- &c. -->
    Since the game depends on Javascript, it would be neater to have Javascript generate the necessary markup. Also, IDs may not begin with a number.
    Code:
            this.turn = function(){
    This results in the function being recreated each time a new instance is created, needlessly. Use prototypes:
    Code:
    Player.prototype.turn = function() {
    Code:
                    for(i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "red";
    By omitting the var keyword, you've unwittingly made i public. You really do not want i to be public, since every man and his dog names their index variable i, and if someone else makes the same mistake and you start overwriting one another's index variables you're going to have a hell of a time debugging it. Personally I find it easiest to keep track of my index variables by declaring them at the top of the function, C-style, to avoid accidentally globalising them (with a missing var) or redefining them (with a superfluous var), but this is a matter of taste.
    Code:
                    stones = this.holes[n - 1].innerHTML;
    There's no reason to use innerHTML here. Avoid it where possible, since it's non-standard, misrepresents the DOM, and has side effects that people often don't anticipate. Using DOM methods in this case is an equally simple endeavour.
    Code:
    function change(){
            if(current == 1) player[current = 0].turn();
            else player[current = 1].turn();
    }
    function next(){
            return current == 1 ? player[0] : player[1];
    }
    It would make more sense to store these on the Player function:
    Code:
    Player.change = function() {
      /* ... */
    };
    
    Player.next = function() {
      /* ... */
    };
    The players array looks as though it would make sense in there as well -- avoid globals wherever possible, especially ones with generic names like "players" and "current." Since current seems to be used nowhere else, you could put it in a closure around these two functions:
    Code:
    (function() {
      var current = 0;
    
      Player.change = function() {
        /* ... */
      };
    
      Player.next = function() {
        /* ... */
      };
    })();
    Last edited by Twey; 08-12-2007 at 03:50 AM.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  3. #3
    Join Date
    Jul 2006
    Posts
    497
    Thanks
    8
    Thanked 70 Times in 70 Posts

    Default

    Quote Originally Posted by Twey View Post
    You've made the common mistake of thinking that DOM methods return arrays. They don't. That's not an array, it's a collection, and as such it doesn't have a lot of the methods arrays have. However, they can still be used with those methods; you just have to call them manually:
    Code:
            this.holes = Array.prototype.reverse.call(document.getElementsByName("p" + n));
    I actually didn't know Javascript had collections... I'm guessing they're different from those in Java?

    Quote Originally Posted by Twey View Post
    Code:
                    <link rel="stylesheet" type="text/css" href="mancala.css"/>
    This XML-style ending syntax doesn't mean what you think it means in HTML, and what it does mean few browsers support.
    I think I missed your point. Do you have an alternative? (My high school Webmastering teacher used link.)

    Quote Originally Posted by Twey View Post
    Code:
    <table border="1" bordercolor="#000000" width="100%" height="100%">
    Avoid this presentational markup -- there's no reason not to use CSS.
    I added the following to my CSS and now have no border:
    Code:
    table{
    	border-width: 1px;
    	border-color: #000000;
    	width: 100%;
    }
    Quote Originally Posted by Twey View Post
    Code:
                            <tr>
                                    <td class="mancala" id="p2" rowspan="2"></td>
                                    <td class="hole" name="p2" id="2-1" onClick="players[1].grab(1)"></td>
                                    <td class="hole" name="p2" id="2-2" onClick="players[1].grab(2)"></td>
                                    <td class="hole" name="p2" id="2-3" onClick="players[1].grab(3)"></td>
    <!-- &c. -->
    Since the game depends on Javascript, it would be neater to have Javascript generate the necessary markup. Also, IDs may not begin with a number.
    For now, I'm just trying to get the mechanics to work. (And those IDs have been working fine, I actually use them to determine when to flip my "collection".)

    Quote Originally Posted by Twey View Post
    Code:
            this.turn = function(){
    This results in the function being recreated each time a new instance is created, needlessly. Use prototypes:
    Code:
    Player.prototype.turn = function() {
    Prototypes? Interesting and simple enough, but they're new to me.

    Quote Originally Posted by Twey View Post
    Code:
                    stones = this.holes[n - 1].innerHTML;
    There's no reason to use innerHTML here. Avoid it where possible, since it's non-standard, misrepresents the DOM, and has side effects that people often don't anticipate. Using DOM methods in this case is an equally simple endeavour.
    ??? What (W3C) DOM methods do you mean?

    Quote Originally Posted by Twey View Post
    Code:
    function change(){
            if(current == 1) player[current = 0].turn();
            else player[current = 1].turn();
    }
    function next(){
            return current == 1 ? player[0] : player[1];
    }
    It would make more sense to store these on the Player function:
    Code:
    Player.change = function() {
      /* ... */
    };
    
    Player.next = function() {
      /* ... */
    };
    The players array looks as though it would make sense in there as well -- avoid globals wherever possible, especially ones with generic names like "players" and "current." Since current seems to be used nowhere else, you could put it in a closure around these two functions:
    Code:
    (function() {
      var current = 0;
    
      Player.change = function() {
        /* ... */
      };
    
      Player.next = function() {
        /* ... */
      };
    })();
    What-huh? What's wrong with globals? And generics? The usefulness of current and players is in their "globality"; they're essentially static and (I think) I want them that way. (In the JS below, I've changed "current" for "number" and added the "index" property to Player.)

    Here's my Javascript:
    Code:
    // JavaScript Document
    var number = 0;
    var players = new Array(2);
    function Player(n){
    	this.index = ++number;
    	this.hasTurn = false;
    	this.mancala = document.getElementById("p" + n);
    	this.holes = document.getElementsByName("p" + n);
    	if(this.holes[0].id != (n + '-' + 1)){
    		alert(this.holes[0].id);
    		this.holes = Array.prototype.reverse.call(document.getElementsByName("p" + n));
    	}
    }
    Player.prototype.turn = function(){
    	this.hasTurn = true;
    	this.mancala.style.backgroundColor = "red";
    	for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "red";
    }
    Player.prototype.grab = function(n){
    	var where;
    	stones = this.holes[n - 1].innerHTML;
    	if(!this.hasTurn || stones == 0) return;
    	for(this.holes[n - 1].innerHTML = 0; stones > 0; stones--){
    		where = (stones - n) % 13;
    		this.drop(where);
    	}
    	if(where != 0){
    		this.hasTurn = false;
    		this.mancala.style.backgroundColor = "white";
    		for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "white";
    		change();
    	}
    }
    Player.prototype.drop = function(n){
    	n = n % 13;
    	switch(n){
    		case -6: case -5: case -4: case -3: case -2: case -1:
    			next().holes[7 + n].innerHTML++;
    			break;
    		case 0:
    			this.mancala.innerHTML++;
    			break;
    		case 1: case 2: case 3: case 4: case 5: case 6:
    			this.holes[n - 1].innerHTML++;
    			break;
    		default:
    			alert('uncaught: drop(' + n + ')');
    	}
    }
    Player.prototype.change = function(){
    	this.hasTurn = false;
    	next().turn();
    }
    Player.prototype.next = function(){
    	return player[this.index == 1 ? 0 : 1];
    }
    function init(s){
    	players[0] = new Player(1);
    	players[1] = new Player(2);
    	for(var i1 = 0; i1 < 2; i1++){
    		players[i1].mancala.innerHTML = 0;
    		for(var i2 = 0; i2 < players[i1].holes.length; i2++) players[i1].holes[i2].innerHTML = s;
    	}
    	players[0].turn();
    }
    And my HTML:
    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    		<link rel="stylesheet" type="text/css" href="mancala.css"/>
    		<title>Mancala</title>
    		<script type="text/javascript" src="mancala.js"></script>
    	</head>
    	<body onLoad="init(4)">
    		<table>
    			<tr>
    				<td class="mancala" id="p2" rowspan="2"></td>
    				<td class="hole" name="p2" id="2-1" onClick="players[1].grab(1)"></td>
    				<td class="hole" name="p2" id="2-2" onClick="players[1].grab(2)"></td>
    				<td class="hole" name="p2" id="2-3" onClick="players[1].grab(3)"></td>
    				<td class="hole" name="p2" id="2-4" onClick="players[1].grab(4)"></td>
    				<td class="hole" name="p2" id="2-5" onClick="players[1].grab(5)"></td>
    				<td class="hole" name="p2" id="2-6" onClick="players[1].grab(6)"></td>
    				<td class="mancala" id="p1" rowspan="2"></td>
    			</tr>
    			<tr>
    				<td class="hole" name="p1" id="1-6" onClick="players[0].grab(6)"></td>
    				<td class="hole" name="p1" id="1-5" onClick="players[0].grab(5)"></td>
    				<td class="hole" name="p1" id="1-4" onClick="players[0].grab(4)"></td>
    				<td class="hole" name="p1" id="1-3" onClick="players[0].grab(3)"></td>
    				<td class="hole" name="p1" id="1-2" onClick="players[0].grab(2)"></td>
    				<td class="hole" name="p1" id="1-1" onClick="players[0].grab(1)"></td>
    			</tr>
    		</table>
    	</body>
    </html>
    And my CSS:
    Code:
    /* CSS Document */
    table{
    	border-width: 1px;
    	border-color: #000000;
    	width: 100%;
    }
    td.hole{
    	height: 100px;
    	text-align: center;
    }
    td.mancala{
    	width: 100px;
    	text-align: center;
    }

  4. #4
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    I actually didn't know Javascript had collections... I'm guessing they're different from those in Java?
    Yes. In ECMAScript terms, "collection" is basically any object that functions like an array but isn't actually an array.
    I think I missed your point. Do you have an alternative? (My high school Webmastering teacher used link.)
    Not for <link>. I was talking about the XML-style self-closing syntax (/>) you've used for the element.
    I added the following to my CSS and now have no border:
    You forgot to specify a border-style. You can combine these properties:
    Code:
    border: 1px solid black;
    For now, I'm just trying to get the mechanics to work. (And those IDs have been working fine, I actually use them to determine when to flip my "collection".)
    They shouldn't, and probably won't in some browsers. Firefox tends to dislike invalid IDs, for a start.
    Prototypes? Interesting and simple enough, but they're new to me.
    Definitely worth getting to know. Prototypes are the basis of all OO in ECMAScript.
    What-huh? What's wrong with globals? And generics? The usefulness of current and players is in their "globality"; they're essentially static and (I think) I want them that way.
    If you added them directly to Player (not to its prototype), they would still be "static" as Java uses the term. They just wouldn't be sitting in the global namespace where they're likely to conflict with other scripts (and besides, they look messy). You'd access them as, e.g., Player.players. Java forces this methodology on you. init() is another dreadfully generically-named function that you really don't want in the global namespace.
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    If you're looking to support IE, then don't use XHTML. If you're not, make sure it's being sent with the correct content type header, application/xhtml+xml.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  5. #5
    Join Date
    Jul 2006
    Posts
    497
    Thanks
    8
    Thanked 70 Times in 70 Posts

    Default

    Quote Originally Posted by Twey View Post
    Yes. In ECMAScript terms, "collection" is basically any object that functions like an array but isn't actually an array.
    *scratches head* It seems they'd make all of 'em arrays. Oh, well.

    Quote Originally Posted by Twey View Post
    Not for <link>. I was talking about the XML-style self-closing syntax (/>) you've used for the element.
    Oh. I was told (W3Schools?) that carried over to XHTML, which is being adopted as standard.

    Quote Originally Posted by Twey View Post
    You forgot to specify a border-style. You can combine these properties:
    Code:
    border: 1px solid black;
    I forget which property goes where and can't read my code except by referencing W3Schools (not for this combo, but many others).

    They shouldn't, and probably won't in some browsers. Firefox tends to dislike invalid IDs, for a start.
    That's strange. I have it alerting the first collection element's ID in the constructor when the collection needs to be flipped, and FF does fine with it.

    Quote Originally Posted by Twey View Post
    Definitely worth getting to know. Prototypes are the basis of all OO in ECMAScript.
    That's very interesting. I'd wondered how JS was OOP. *reads* It's long but worth it, so far.

    Quote Originally Posted by Twey View Post
    If you added them directly to Player (not to its prototype), they would still be "static" as Java uses the term. They just wouldn't be sitting in the global namespace where they're likely to conflict with other scripts (and besides, they look messy). You'd access them as, e.g., Player.players. Java forces this methodology on you. init() is another dreadfully generically-named function that you really don't want in the global namespace.
    My JS complies.

    Quote Originally Posted by Twey View Post
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    If you're looking to support IE, then don't use XHTML. If you're not, make sure it's being sent with the correct content type header, application/xhtml+xml.
    The original DOCTYPE:
    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    is from my Dreamweaver 2004. You told me to use strict, and I only know (actually reference from W3Schools) the XHTML DOCTYPEs, but not what 'application/xhtml+xml' is.

    Using the following codes, clicking has no effect, not even the finnicky one I was wrestling with earlier. :\

    mancala.js:
    Code:
    // JavaScript Document
    function Player(n){
    	this.index = ++Player.number;
    	this.hasTurn = false;
    	this.mancala = document.getElementById("p" + n);
    	this.holes = document.getElementsByName("p" + n);
    	if(this.holes[0].id != (n + '-' + 1)){
    		alert(this.holes[0].id);
    		this.holes = Array.prototype.reverse.call(document.getElementsByName("p" + n));
    	}
    }
    Player.number = 0;
    Player.players = new Array(2);
    Player.prototype.turn = function(){
    	this.hasTurn = true;
    	this.mancala.style.backgroundColor = "red";
    	for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "red";
    }
    Player.prototype.grab = function(n){
    	var where;
    	stones = this.holes[n - 1].innerHTML;
    	if(!this.hasTurn || stones == 0) return;
    	for(this.holes[n - 1].innerHTML = 0; stones > 0; stones--){
    		where = (stones - n) % 13;
    		this.drop(where);
    	}
    	if(where != 0){
    		this.hasTurn = false;
    		this.mancala.style.backgroundColor = "white";
    		for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = "white";
    		change();
    	}
    }
    Player.prototype.drop = function(n){
    	n = n % 13;
    	switch(n){
    		case -6: case -5: case -4: case -3: case -2: case -1:
    			next().holes[7 + n].innerHTML++;
    			break;
    		case 0:
    			this.mancala.innerHTML++;
    			break;
    		case 1: case 2: case 3: case 4: case 5: case 6:
    			this.holes[n - 1].innerHTML++;
    			break;
    		default:
    			alert('uncaught: drop(' + n + ')');
    	}
    }
    Player.prototype.change = function(){
    	this.hasTurn = false;
    	next().turn();
    }
    Player.prototype.next = function(){
    	return Player.players[this.index == 1 ? 0 : 1];
    }
    Player.init = function(s){
    	Player.players[0] = new Player(1);
    	Player.players[1] = new Player(2);
    	for(var i1 = 0; i1 < 2; i1++){
    		Player.players[i1].mancala.innerHTML = 0;
    		for(var i2 = 0; i2 < Player.players[i1].holes.length; i2++) Player.players[i1].holes[i2].innerHTML = s;
    	}
    	Player.players[0].turn();
    }
    mancala.css:
    Code:
    /* CSS Document */
    table{
    	border: 1px solid black;
    	width: 100%;
    }
    td{
    	border: 1px solid black;
    }
    td.hole{
    	height: 100px;
    	text-align: center;
    }
    td.mancala{
    	width: 100px;
    	text-align: center;
    }
    td.minihole{
    	height: 50px;
    	text-align: center;
    }
    td.minimancala{
    	height: 50px;
    	text-align: center;
    }
    mancala.html:
    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    		<link rel="stylesheet" type="text/css" href="mancala.css">
    		<title>Mancala</title>
    		<script type="text/javascript" src="mancala.js"></script>
    	</head>
    	<body onLoad="Player.init(4)">
    		<table>
    			<tr>
    				<td class="mancala" id="p2" rowspan="2"></td>
    				<td class="hole" name="p2" id="2-1" onClick="players[1].grab(1)"></td>
    				<td class="hole" name="p2" id="2-2" onClick="players[1].grab(2)"></td>
    				<td class="hole" name="p2" id="2-3" onClick="players[1].grab(3)"></td>
    				<td class="hole" name="p2" id="2-4" onClick="players[1].grab(4)"></td>
    				<td class="hole" name="p2" id="2-5" onClick="players[1].grab(5)"></td>
    				<td class="hole" name="p2" id="2-6" onClick="players[1].grab(6)"></td>
    				<td class="mancala" id="p1" rowspan="2"></td>
    			</tr>
    			<tr>
    				<td class="hole" name="p1" id="1-6" onClick="players[0].grab(6)"></td>
    				<td class="hole" name="p1" id="1-5" onClick="players[0].grab(5)"></td>
    				<td class="hole" name="p1" id="1-4" onClick="players[0].grab(4)"></td>
    				<td class="hole" name="p1" id="1-3" onClick="players[0].grab(3)"></td>
    				<td class="hole" name="p1" id="1-2" onClick="players[0].grab(2)"></td>
    				<td class="hole" name="p1" id="1-1" onClick="players[0].grab(1)"></td>
    			</tr>
    		</table>
    	</body>
    </html>

  6. #6
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    *scratches head* It seems they'd make all of 'em arrays. Oh, well.
    DOM collections have some special abilities. For example, if you destroy an element, the element is automatically removed from all DOM collections you may have stored that contain it (causing no end of confusion to newbies with loops that destroy elements).
    Oh. I was told (W3Schools?) that carried over to XHTML, which is being adopted as standard.
    It doesn't "carry over" to XHTML. It's primarily an XHTML construct. In SGML (of which HTML is technically a profile) it has a very different meaning: it's a "short tag" construct that no HTML parsers (of which I know) actually support, but <br /> should, by the rules of this construct, be rendered the same as <br>&gt;. Also beware XHTML. It does look to have a reasonable chance of becoming the next big markup language for the Web (HTML5 is still in the running, though), but IE doesn't yet support it. Until IE does get support, you should steer clear of it for general-purpose applications (i.e. anything that might be accessed with IE). W3Schools has a fairly bad reputation for mixing good information in with bad. It's not a bad reference overall, but take it with a pinch of salt.
    I forget which property goes where and can't read my code except by referencing W3Schools (not for this combo, but many others).
    Shorthand vs. longhand properties are, of course, entirely a matter of personal preference. You still need border-style though. Longhand, it would be written:
    Code:
    border-style: solid;
    border-color: black;
    border-width: 1px;
    My JS complies.
    This is again a matter of style, but since there are more than players involved in a game of mancala, I would suggest putting the whole script inside a namespacing object (called, perhaps, Mancala). You could then reference it as Mancala.Player, Mancala.Player.players, &c. I was raised on Java, and thus love namespacing; Dean Edwards would hate me Also, don't be afraid of creating small constructor functions for convenience methods. I would restructure this script entirely, dividing it into Mancala.Board, Mancala.Player, Mancala.Hole, and Mancala.Stone.
    The original DOCTYPE:
    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    is from my Dreamweaver 2004. You told me to use strict, and I only know (actually reference from W3Schools) the XHTML DOCTYPEs, but not what 'application/xhtml+xml' is.
    The HTML 4.01 Strict DOCTYPE (which you'd almost certainly be better off using) is:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    If you do wish to continue using XHTML, you need to serve it as XHTML: right now what you're actually sending is invalid HTML. When your webserver serves a document, it sends a series of headers containing meta-information about the document and request. One of these headers is called Content-Type, and it specifies what sort of content is being sent, in the form of a MIME type. Common values include, for example, image/jpeg for a JPEG image, text/html for an HTML document, or application/xhtml+xml for an XHTML document.
    ??? What (W3C) DOM methods do you mean?
    I apologise for not answering this earlier: I appear to have missed it. In this particular case, assuming you leave a spacer character in each hole, the only DOM property you would need to use would be .firstChild.nodeValue. You can set and get this just as you're currently doing with innerHTML (which, by the way, will cease to work if you switch to using XHTML).
    stones = this.holes[n - 1].innerHTML;
    Wouldn't it be easier to just zero-index everything? Also, stones is unintentionally global.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  7. #7
    Join Date
    Jul 2006
    Posts
    497
    Thanks
    8
    Thanked 70 Times in 70 Posts

    Default

    Quote Originally Posted by Twey View Post
    DOM collections have some special abilities. For example, if you destroy an element, the element is automatically removed from all DOM collections you may have stored that contain it (causing no end of confusion to newbies with loops that destroy elements).
    I just realized that my collection isn't flipping in response to this.holes = Array.prototype.reverse.call(this.holes). See the code at bottom.

    Quote Originally Posted by Twey View Post
    This is again a matter of style, but since there are more than players involved in a game of mancala, I would suggest putting the whole script inside a namespacing object (called, perhaps, Mancala). You could then reference it as Mancala.Player, Mancala.Player.players, &c. I was raised on Java, and thus love namespacing; Dean Edwards would hate me Also, don't be afraid of creating small constructor functions for convenience methods. I would restructure this script entirely, dividing it into Mancala.Board, Mancala.Player, Mancala.Hole, and Mancala.Stone.
    That'll take a while.

    Quote Originally Posted by Twey View Post
    The HTML 4.01 Strict DOCTYPE (which you'd almost certainly be better off using) is:
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    If you do wish to continue using XHTML, you need to serve it as XHTML: right now what you're actually sending is invalid HTML. When your webserver serves a document, it sends a series of headers containing meta-information about the document and request. One of these headers is called Content-Type, and it specifies what sort of content is being sent, in the form of a MIME type. Common values include, for example, image/jpeg for a JPEG image, text/html for an HTML document, or application/xhtml+xml for an XHTML document.
    I'm curious... How is it invalid HTML?

    Quote Originally Posted by Twey View Post
    I apologise for not answering this earlier: I appear to have missed it. In this particular case, assuming you leave a spacer character in each hole, the only DOM property you would need to use would be .firstChild.nodeValue. You can set and get this just as you're currently doing with innerHTML (which, by the way, will cease to work if you switch to using XHTML).
    When innerHTML is replaced with firstChild.nodeValue in the below script, firstChild is null so nodeValue aborts the script.

    Code:
    // JavaScript Document
    function Mancala(){
    	
    }
    Mancala.number = 0;
    Mancala.players;
    Mancala.init = function(s, p){// stones/hole, players
    	if(p < 2) return;
    	Mancala.stonesPerHole = s;
    	Mancala.players = new Array(p);
    	for(var i = 0; i < p; i++) Mancala.players[i] = new Mancala.Player();
    	(Mancala.current = Mancala.players[0]).turn();
    }
    Mancala.change = function(){
    	(Mancala.current = Mancala.current.next()).turn();
    }
    Mancala.Player = function(){
    	this.index = Mancala.number++;
    	
    	this.mancala = document.getElementById('p' + this.index);
    	this.mancala.innerHTML = 0;
    	
    	this.holes = document.getElementsByName('p' + this.index);
    	if(this.holes[0].id != ('h' + this.index + '-' + 0)) this.holes = Array.prototype.reverse.call(this.holes);
    	for(var i = 0; i < this.holes.length; i++){
    		alert(this.holes[i].innerHTML);
    		this.holes[i].innerHTML = Mancala.stonesPerHole;
    	}
    }
    Mancala.Player.prototype.turn = function(){
    	Mancala.current = this;
    	this.mancala.style.backgroundColor = 'red';
    	for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = 'red';
    }
    Mancala.Player.prototype.grab = function(n){
    	alert('grabbing ' + n);
    	var start = n;
    	var where = start - 1;
    	var stones = this.holes[n].innerHTML;
    	if(this != Mancala.current || stones == 0) return;
    	this.holes[n].innerHTML = 0;
    	while(stones > 0 && where > 0){
    		this.drop(where--);
    		stones--;
    	}
    	if(where != -1){
    		this.mancala.style.backgroundColor = 'white';
    		for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = 'white';
    		Mancala.change();
    	}
    }
    Mancala.Player.prototype.drop = function(n){
    	n = n % 13;
    	alert('dropping ' + n);
    	switch(n){
    		case -7: case -6: case -5: case -4: case -3: case -2:
    			this.next().holes[6 + n].innerHTML++;
    			break;
    		case -1:
    			this.mancala.innerHTML++;
    			break;
    		case 0: case 1: case 2: case 3: case 4: case 5:
    			this.holes[n].innerHTML++;
    			break;
    		default:
    			alert('uncaught: drop(' + n + ')');
    	}
    }
    Mancala.Player.prototype.next = function(){
    	return Mancala.players[this.index == Mancala.players.length - 1 ? 0 : this.index + 1];
    }
    Code:
    /* CSS Document */
    table{
    	border-style: solid;
    	border-color: black;
    	border-width: 1px;
    	width: 100%;
    }
    td{
    	border-style: solid;
    	border-color: black;
    	border-width: 1px;
    }
    td.hole{
    	height: 100px;
    	text-align: center;
    }
    td.mancala{
    	width: 100px;
    	text-align: center;
    }
    td.minihole{
    	height: 50px;
    	text-align: center;
    }
    td.minimancala{
    	height: 50px;
    	text-align: center;
    }
    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    		<link rel="stylesheet" type="text/css" href="mancala.css">
    		<title>Mancala</title>
    		<script type="text/javascript" src="mancala.js"></script>
    	</head>
    	<body onLoad="Mancala.init(4, 2)">
    		<table>
    			<tr>
    				<td class="mancala" id="p1" rowspan="2"></td>
    				<td class="hole" name="p1" id="h1-0" onClick="Mancala.players[1].grab(0)"></td>
    				<td class="hole" name="p1" id="h1-1" onClick="Mancala.players[1].grab(1)"></td>
    				<td class="hole" name="p1" id="h1-2" onClick="Mancala.players[1].grab(2)"></td>
    				<td class="hole" name="p1" id="h1-3" onClick="Mancala.players[1].grab(3)"></td>
    				<td class="hole" name="p1" id="h1-4" onClick="Mancala.players[1].grab(4)"></td>
    				<td class="hole" name="p1" id="h1-5" onClick="Mancala.players[1].grab(5)"></td>
    				<td class="mancala" id="p0" rowspan="2"></td>
    			</tr>
    			<tr>
    				<td class="hole" name="p0" id="h0-5" onClick="Mancala.players[0].grab(5)"></td>
    				<td class="hole" name="p0" id="h0-4" onClick="Mancala.players[0].grab(4)"></td>
    				<td class="hole" name="p0" id="h0-3" onClick="Mancala.players[0].grab(3)"></td>
    				<td class="hole" name="p0" id="h0-2" onClick="Mancala.players[0].grab(2)"></td>
    				<td class="hole" name="p0" id="h0-1" onClick="Mancala.players[0].grab(1)"></td>
    				<td class="hole" name="p0" id="h0-0" onClick="Mancala.players[0].grab(0)"></td>
    			</tr>
    		</table>
    	</body>
    </html>

  8. #8
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    I just realized that my collection isn't flipping in response to this.holes = Array.prototype.reverse.call(this.holes).
    Really? Try:
    Code:
    this.holes = Array.prototype.slice.call(this.holes).reverse();
    That'll take a while.
    Not that long -- it's not a particularly complex script. I'm surprised you didn't design it this way in the first place, given that you know Java.
    I'm curious... How is it invalid HTML?
    It's using a non-HTML DOCTYPE, for a start. There are other differences between XHTML and HTML as well, like self-closing tags:
    Code:
    <link />
    is (syntactically) valid XHTML, but not HTML except with short tags, which, although they are a feature of SGML, are usually not considered a feature of HTML because few or no HTML parsers support them. When they are supported, as I said, they don't mean the same as they do in XHTML.
    When innerHTML is replaced with firstChild.nodeValue in the below script, firstChild is null so nodeValue aborts the script.
    I said:
    Quote Originally Posted by myself
    assuming you leave a spacer character in each hole
    Try putting an &nbsp; in each hole element.
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

  9. #9
    Join Date
    Jul 2006
    Posts
    497
    Thanks
    8
    Thanked 70 Times in 70 Posts

    Default

    Quote Originally Posted by Twey View Post
    Really? Try:
    Code:
    this.holes = Array.prototype.slice.call(this.holes).reverse();
    Never mind on that. I decided to step through the IDs and not flip.

    Quote Originally Posted by Twey View Post
    Not that long -- it's not a particularly complex script. I'm surprised you didn't design it this way in the first place, given that you know Java.
    I'm not very object-oriented in JS, I guess because I don't have to be.

    Quote Originally Posted by Twey View Post
    It's using a non-HTML DOCTYPE, for a start. There are other differences between XHTML and HTML as well, like self-closing tags:
    Code:
    <link />
    is (syntactically) valid XHTML, but not HTML except with short tags, which, although they are a feature of SGML, are usually not considered a feature of HTML because few or no HTML parsers support them. When they are supported, as I said, they don't mean the same as they do in XHTML.
    I thought you meant my updated code was invalid.

    Quote Originally Posted by Twey View Post
    I said:

    Try putting an &nbsp; in each hole element.
    I took "spacer character" to mean the 0 that remains in the holes when the stones are gone.

    And I've apparently made a new problem: Nothing shows up because I transfered the layout to JS and the script aborts before entering the first function.

    Code:
    // JavaScript Document
    Mancala.number = 0;
    Mancala.init = function(s, area){// stones/hole, display area
    alert(0);
    	Mancala.board = new Mancala.Board(s);
    	Mancala.board.display(area);
    	Mancala.board.init();
    }
    Mancala.change = function(){
    	(Mancala.current = Mancala.current.next()).turn();
    }
    Mancala.Player = function(){
    	this.index = Mancala.number++;
    	
    	this.mancala = document.getElementById('p' + this.index);
    	this.mancala.innerHTML = 0;
    	
    	for(var i = 0; i < 6; i++) this.holes[i] = document.getElementById('h' + this.index + '-' i);
    	for(var i = 0; i < this.holes.length; i++){
    		alert(this.holes[i].innerHTML);
    		this.holes[i].innerHTML = Mancala.stonesPerHole;
    	}
    }
    Mancala.Player.prototype.turn = function(){
    	Mancala.current = this;
    	this.mancala.style.backgroundColor = 'red';
    	for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = 'red';
    }
    Mancala.Player.prototype.grab = function(n){
    	var start = n;
    	var where = start - 1;
    	var stones = this.holes[n].innerHTML;
    	if(this != Mancala.current || stones == 0) return;
    	alert('grabbing ' + n);
    	this.holes[n].innerHTML = 0;
    	while(stones > 0 && where > 0){
    		this.drop(where--);
    		stones--;
    	}
    	if(where != -1){
    		this.mancala.style.backgroundColor = 'white';
    		for(var i = 0; i < this.holes.length; i++) this.holes[i].style.backgroundColor = 'white';
    		Mancala.change();
    	}
    }
    Mancala.Player.prototype.drop = function(n){
    	n = n &#37; 13;
    	alert('dropping ' + n);
    	switch(n){
    		case -7: case -6: case -5: case -4: case -3: case -2:
    			this.next().holes[6 + n].innerHTML++;
    			break;
    		case -1:
    			this.mancala.innerHTML++;
    			break;
    		case 0: case 1: case 2: case 3: case 4: case 5:
    			this.holes[n].innerHTML++;
    			break;
    		default:
    			alert('uncaught: drop(' + n + ')');
    	}
    }
    Mancala.Player.prototype.next = function(){
    	return Mancala.players[this.index == Mancala.players.length - 1 ? 0 : this.index + 1];
    }
    Mancala.Board = function(s){
    	this.stonesPerHole = s;
    	this.players = new Array(2);
    }
    Mancala.Board.prototype.init(){
    	for(var i = 0; i < p; i++) this.players[i] = new Mancala.Player();
    	(this.current = this.players[0]).turn();
    }
    Mancala.Board.prototype.display(area){
    	var table = document.createElement('table');
    		table.insertRow(0);
    			table.rows[0].insertCell(0);
    				table.rows[0].cells[0].rowSpan = 2;
    				table.rows[0].cells[0].className = 'mancala';
    				table.rows[0].cells[0].id = 'p' + 0;
    			
    		for(var i2 = 0; i2 < 6; i2++){
    			table.rows[0].insertCell(i2);
    				table.rows[0].cells[i2].className = 'hole';
    				table.rows[0].cells[i2].id = 'h' + 0 + '-' i2;
    				table.rows[0].cells[i2].onClick='Mancala.board.players[0].grab(' + i2 + ')';
    		}
    			table.rows[0].insertCell(6);
    				table.rows[0].cells[6].rowSpan = 2;
    				table.rows[0].cells[6].className = 'mancala';
    				table.rows[0].cells[6].id = 'p' + 1;
    				
    		table.insertRow(1);
    		for(var i2 = 0; i2 < 6; i2++){
    			table.rows[1].insertCell(i2);
    				table.rows[1].cells[i2].className = 'hole';
    				table.rows[1].cells[i2].id = 'h' + 1 + '-' (6 - i2);
    				table.rows[0].cells[i2].onClick='Mancala.board.players[1].grab(' + i2 + ')';
    		}
    	area.appendChild(table);
    }
    HTML Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    		<link rel="stylesheet" type="text/css" href="mancala.css">
    		<title>Mancala</title>
    		<script type="text/javascript" src="mancala.js"></script>
    	</head>
    	<body onLoad="Mancala.init(4, this)">
    	</body>
    </html>
    Code:
    /* CSS Document */
    table{
    	border-style: solid;
    	border-color: black;
    	border-width: 1px;
    	width: 100%;
    }
    td{
    	border-style: solid;
    	border-color: black;
    	border-width: 1px;
    }
    td.hole{
    	height: 100px;
    	text-align: center;
    }
    td.mancala{
    	width: 100px;
    	text-align: center;
    }
    
    td.minihole, td.minimancala{
    	height: 50px;
    	text-align: center;
    }
    EDIT: I will be uploading the page to http://www.auto-chat.net/ccarter/mancala.html from now on. (I might forget, just remind me.)
    Last edited by Jesdisciple; 08-15-2007 at 03:27 AM.

  10. #10
    Join Date
    Jun 2005
    Location
    英国
    Posts
    11,876
    Thanks
    1
    Thanked 180 Times in 172 Posts
    Blog Entries
    2

    Default

    You haven't defined Mancala, which you need to do before adding properties to it:
    Code:
    var Mancala = {};
    Twey | I understand English | 日本語が分かります | mi jimpe fi le jbobau | mi esperanton komprenas | je comprends français | entiendo español | tôi ít hiểu tiếng Việt | ich verstehe ein bisschen Deutsch | beware XHTML | common coding mistakes | tutorials | various stuff | argh PHP!

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •