Jump to content

Dots


Recommended Posts

Well I was bored over the past week so I spend a little while creating this game using html5 canavas. The basic objective of the game is to make boxes by drawing lines. You can play against the computer.

 

In terms of the AI, the computer is pretty stupid. It'll take boxes you give it but other than that it basically just draws random lines. Let me know what you think/how can I improve it?

 

[hide=code]

<!DOCTYPE html>
<html>
<head><title>Dots</title></head>
<script type="text/javascript">

var turn = 0; //0 for human, 1 for computer
var canvas;
var timeCountInterval, compTurnInterval;
var time = 0;
var clickedX, clickedY;
var dX, dY, mode;
var fakeDrawn = false;
var barsArr = new Array(450);
var gameOn;
var humanLastX, humanLastY, humanLastMode;
var totalBoxes  = 0;

function draw_border(){
canvas = document.getElementById("dotboard");
var context = canvas.getContext("2d");
context.fillStyle = "#000000";
context.fillRect(0,0,500,500);
context.fillStyle = "#FFFFFF";
context.fillRect(1,1,498,498);
}

function clear_canvas() {
       canvas = document.getElementById("dotboard");
       canvas.width = 1;
       canvas.width = 500;
}

function update_screen() {
   clear_canvas();
draw_border();
}

function inc_time(){
time = time + 1;
timeDiv = document.getElementById("time");
timeDiv.innerHTML = "Time spent: " + time + " seconds";
}

function incrementScore(type){
var table;
totalBoxes = totalBoxes + 1;
switch(type){
	case 0:
		table = document.getElementById("yourScore");
		break;
	case 1:
		table = document.getElementById("machineScore");
		break;
	default:
		break;
}
currentScore = parseInt(table.innerHTML);
finalScore = currentScore + 1;
table.innerHTML = finalScore;
}

function incrementTurns(type){
var table;
switch(type){
	case 0:
		table = document.getElementById("yourTurn");
		break;
	case 1:
		table = document.getElementById("machineTurn");
		break;
	default:
		break;
}
currentTurns = parseInt(table.innerHTML);
finalTurns = currentTurns + 1;
table.innerHTML = finalTurns;
}

function dot(x, y){
canvas = document.getElementById("dotboard");
var context = canvas.getContext("2d");
context.fillStyle = "#000000";	
context.fillRect(x, y, 5, 5);
}


function draw_dots(){

for (IY=1;IY<=15;IY++){
	for (IX=1;IX<=15;IX++){
		xval = IX * 30;
		yval = IY * 30;
		dot(xval, yval);
	}
}

}

function fake_lines(event){	

if (fakeDrawn){
	line(fakeX, fakeY, 4, fakeMode);
	fakeX = 2;
	fakeY = 2;
	fakeMode = "v";
}

clickedX = event.clientX - 8;
clickedY = event.clientY - 8;

if ((clickedX < 31) || (clickedX > 454)){
	return false; //outside clickable x
} else if ((clickedY < 31) || (clickedY > 454)){
	return false; //outside clickable y
}

if (get_pipeLine(clickedX, clickedY)){
	if (line(dX, dY, 1, mode)){
		fakeX = dX;
		fakeY = dY;
		fakeMode = mode;
		fakeDrawn = true;
	} else {
		return false;
	}
}	
}

function comp_doTurn(){
if (turn != 1) {
	return false;
}
if (gameOn == false){
	return false;
}
if (totalBoxes >= 196){
	game_over();
	return false;
}

//this HAS to be improved - unacceptable think times near game end (when most options return false), more than a minute
//randomly generate clickedX and clickedY here. easy way is just w/e random numbers but it should be done properly
//should also call game_over
/*clickedX = (Math.floor(Math.random()*450) + 30);
clickedY = (Math.floor(Math.random()*450) + 30);
if (get_pipeLine(clickedX, clickedY)){
	if (line(dX, dY, 3, mode)) {
		if (do_check_score(dX, dY, mode)){

		} else {
			turn = 0;			}
	}

}*/
var hX, hY, hMode;
hX = humanLastX;
hY = humanLastY;
hMode = humanLastMode;
var canScore = true;

while (canScore == true){

	//if can't score
	canScore = false;
}

var vLR, vLL, vLRA, vLRB, vLLA, vLLB;
var hLB, hLA, hLBR, hLAR, hLBL, hLAL;

if (hMode == "v") {

	vLR = line_exists(hX + 30, hY);
	vLL = line_exists(hX - 30, hY);
	vLRA = line_exists(hX + 4, hY - 4);
	vLRB = line_exists(hX + 4, hY + 26);
	vLLA = line_exists(hX - 26, hY - 4);
	vLLB = line_exists(hX - 26, hY + 26);

	if (vLR || vLL){
		if (vLR && (vLRA || vLRB)){
			if (vLRA){
				if (get_pipeLine(hX + 4, hY + 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			} else if (vLRB){
				if (get_pipeLine(hX + 4, hY - 4)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			} 
		} else if (vLL && (vLLA || vLLB)){
			if (vLLA){
				if (get_pipeLine(hX - 26, hY + 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			} else if (vLLB){
				if (get_pipeLine(hX - 26, hY - 4)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			}
		}
	} else if (vLRA || vLRB){
		if (vLRA && (vLR || vLRB)){
			if (vLR){
				if (get_pipeLine(hX - 26, hY + 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			} else if (vLRB){
				if (get_pipeLine(hX + 30, hY)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			}
		}
	} else if (vLLA || vLLB){
		if (vLLA && (vLLB || vLL)){
			if (vLLB){
				if (get_pipeLine(hX - 30, hY)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			} else if (vLL){
				if (get_pipeLine(hX - 26, hY + 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){							
						} else {
							went = true;
						}
					}
				}
			}
		}
	}
} else if (hMode == "h"){

	hLB = line_exists(hX, hY + 30);
	hLA = line_exists(hX, hY - 30);
	hLBR = line_exists(hX + 26, hY + 4);
	hLAR = line_exists(hX + 26, hY - 26);
	hLBL = line_exists(hX - 4, hY + 4);
	hLAL = line_exists(hX - 4, hY - 26);

	if (hLB || hLA){
		if (hLB && (hLBL || hLBR)){
			if (hLBL){
				if (get_pipeLine(hX + 26, hY + 4)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){
						} else {
							went = true;
						}
					}
				}
			} else if (hLBR){
				if (get_pipeLine(hX - 4, hY + 4)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){
						} else {
							went = true;
						}
					}
				}
			}
		} else if (hLA && (hLAL || hLAR)){
			if (hLAL){
				if (get_pipeLine(hX + 26, hY - 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){
						} else {
							went = true;
						}
					}
				}
			} else if (hLAR){
				if (get_pipeLine(hX - 4, hY - 26)){
					if (line(dX, dY, 3, mode)){
						if (do_check_score(dX, dY, mode)){
						} else {
							went = true;
						}
					}
				}
			}
		}
	} else if (hLBR || hLBL){

	} else if (hLAR || hLAL){

	}
	//alert("hLB: " + hLB + "\n hLA: " + hLA + "\n hLBR: " + hLBR + "\n hLAR: " + hLAR + "\n hLBL: " + hLBL + "\n hLAL: " + hLAL);
}

//after all this we'll have to clear hmode and all that to try other stuff

var went = false;
while (went == false) {
	clickedX = (Math.floor(Math.random()*424) + 30);
	clickedY = (Math.floor(Math.random()*424) + 30);
	if (get_pipeLine(clickedX, clickedY)){
		if (line(dX, dY, 3, mode)) {
			incrementTurns(turn);
			if (do_check_score(dX, dY, mode)){

			} else {
				went = true;
			}
		}
	}
}	
turn = 0;
return true;
}

function do_check_score(x, y, mode){

var captured = false;
if (mode == "v") {
	if (line_exists(x + 30, y )){
		if (line_exists(x + 4, y - 4)){
			if (line_exists(x + 4, y + 26)){
				square(x + 4, y, turn);
				incrementScore(turn);
				captured = true;
			}
		}
	}		
	if (line_exists(x - 30, y)){
		if (line_exists(x - 26, y - 4)){
			if (line_exists(x - 26, y + 26)){
				square(x - 26, y, turn);
				incrementScore(turn);
				captured = true;
			}
		}
	} 
	if (captured == true) {
		return true;
	} else {
		return false;
	}
} else if (mode == "h"){
	if (line_exists(x, y - 30)){
		if (line_exists(x - 4, y - 26)){
			if (line_exists(x + 26, y - 26)){
				square(x, y - 26, turn);
				incrementScore(turn);
				captured = true;
			}
		}
	} 
	if (line_exists(x, y + 30)){
		if (line_exists(x - 4, y + 4)){
			if (line_exists(x + 26, y + 4)){
				square(x, y + 4, turn);
				incrementScore(turn);
				captured = true;
			}
		}
	}
	if (captured == true) {
		return true;
	} else {
		return false;
	}
}
}

function line(x, y, mode, vOrH){

canvas = document.getElementById("dotboard");
var context = canvas.getContext("2d");
var newmode;
switch (mode){
	case 1://human hover
		context.fillStyle = "#5DFC0A";	
		newmode = 0;
		break;
	case 2://human click
		context.fillStyle = "#0BB5FF";	
		newmode = 1;
		break;
	case 3://comp click
		context.fillStyle = "#FF6600";
		newmode = 2;
		break;
	case 4://clear
		context.fillStyle = "#FFFFFF";
		newmode = 0;
		break;
	default:
		return false;
		break;
}

if (vOrH == "v"){
	xx = 3;
	yy = 25;
} else if (vOrH == "h"){
	xx = 25;
	yy = 3;
}	

if (line_exists(x, y) == false){
	context.fillRect(x, y, xx, yy);
	if (newmode != 0){
		addToArray(x, y, newmode);
		return true;
	} else {
		return true;
	}
} else {
	return false;
}
}

function square(x, y, mode){
canvas = document.getElementById("dotboard");
var context = canvas.getContext("2d");
switch (mode){
	case 0://human click
		context.fillStyle = "#0BB5FF";	
		break;
	case 1://comp click
		context.fillStyle = "#FF6600";
		break;
	default:
		return false;
		break;
}

context.fillRect(x, y, 25, 25);
}

function line_exists(x, y){

for (w=0;w<barsArr.length;w++){
	if (barsArr[w][0] == x){
		if (barsArr[w][1] == y) {
			if (barsArr[w][2] == 0){
				return false;
			} else {
				return true;
			}
		}
	}
}
return false;
}

function addToArray(x, y, mode){
for (w=0;w<barsArr.length;w++){
	if(!barsArr[w][0]){
		barsArr[w][0] = x;
		barsArr[w][1] = y;
		barsArr[w][2] = mode;
		return true;
	}
}
}

//game will deadlock if i do last move (waiting on me before comp goes)
function do_humanTurn(event){
if (turn != 0){
	return false;
}
if (gameOn == false){
	alert("the game is over!");
	return false;
}
if (totalBoxes >= 196){
	game_over();
	return false;
}

clickedX = event.clientX - 8;
clickedY = event.clientY - 8;

if ((clickedX < 31) || (clickedX > 454)){
	return false; //outside clickable x
} else if ((clickedY < 31) || (clickedY > 454)){
	return false; //outside clickable y
}

if (get_pipeLine(clickedX, clickedY)){
	if (line(dX, dY, 2, mode)) {
		incrementTurns(turn);
		if (do_check_score(dX, dY, mode)) {				
		} else {
			turn = 1;
			humanLastX = dX;
			humanLastY = dY;
			humanLastMode = mode;
			return true;
		}
	} else {
		return false;
	}
} 
}

function get_pipeLine(cX, cY){

for (i=0;i<5;i++){
	obj = (cX - i) % 30;
	if (obj == 0){
		for (a=0;a<5;a++){
			obj2 = (cY - a) % 30;
			if (obj2 == 0){
				return false; 
			} 
		}
		for (b=0;b<30;b++){
			obj3 = (cY - b) % 30;
			if (obj3 == 0){
				dY = (cY - b) + 5;
				mode = "v";
				dX = (cX - i) + 1;
				return true;
			}
		}				
	}
}

for (i=0;i<5;i++){
	obj = (cY - i) % 30;
	if (obj == 0){
		for (a=0;a<5;a++){
			obj2 = (cX - a) % 30;
			if (obj2 == 0){
				return false; 
			}		
		}
		for (b=0;b<30;b++){
			obj3 = (cX - b) % 30;
			if (obj3 == 0){
				dX = (cX - b) + 5;
				mode = "h";
				dY = (cY - i) + 1;
				return true;
			}
		}
	}
}

return false;	
}

function clearIntervals(){
clearInterval(timeCountInterval);
clearInterval(compTurnInterval);
}

function game_over(){
clearIntervals();
gameOn = false;
compScore = parseInt(document.getElementById("machineScore").innerHTML);
yourScore = parseInt(document.getElementById("yourScore").innerHTML);

if (compScore == yourScore){
	alert("Tie game: " + compScore + " to " + yourScore + ". Random...");
} else if (yourScore > compScore){
	alert("You win: " + yourScore + " to " + compScore + ". Great job!");
} else if (yourScore < compScore){
	alert("You lost: " + compScore + " to " + yourScore + ". You got owned!");
}
}

window.onload = function(){
for (q=0;q<barsArr.length;q++){
	barsArr[q] = new Array(3);
}
draw_border();
draw_dots();
timeCountInterval = setInterval("inc_time()", 1000);
compTurnInterval = setInterval("comp_doTurn()", 1000);
gameOn = true;
}

</script>
<canvas id="dotboard" width="500" height="500" onclick="do_humanTurn(event);return false" onmousemove="fake_lines(event);return false">
<body>
<p>It isn't working :-(.</p>
</canvas><br /><br />
<div id="score">
<table id="theTable" cellpadding="10" border="1px">
<tr>
	<td></td>
	<td><b><span style="color:#0BB5FF"> You </b></span></td>
	<td><b><span style="color:#FF6600">Le machine</b></span></td>
</tr>
<tr id="scores">
	<td><b>Score:</b></td>
	<td id="yourScore">0</td>
	<td id="machineScore">0</td>
</tr>
<tr id="turns">
	<td><b>Turns:</b></td>
	<td id="yourTurn">0</td>
	<td id="machineTurn">0</td>
</tr>
</table>
</div><br />
<div id="time">
Time spent: 0 seconds
</div>
</body>
</html>

[/hide]

 

Just save the above code into a .html file and open it on an html5 compliant browser (any new browser should work).

polvCwJ.gif
"It's not a rest for me, it's a rest for the weights." - Dom Mazzetti

Link to comment
Share on other sites

It's a fun little game. I used to play it against class mates all the time. :P

 

But yeah, as you mentioned the AI is a bit too easy. For anything in the future you should try and make it a bit more challenging. :P

j0xPu5R.png

Link to comment
Share on other sites

sometimes the ai makes lines or w/e outside the playing board.

i can take a picture if you dont understand.

 

No I understand - it does it for me too (albeit very rarely). I couldn't trace the origin of the bug so I just left it.

I am curious as to the exact location: left, right, above, below the board?

 

It's a fun little game. I used to play it against class mates all the time. :P

 

But yeah, as you mentioned the AI is a bit too easy. For anything in the future you should try and make it a bit more challenging. :P

 

That's next on the to do list if I cbf. But it's a lot of work...

polvCwJ.gif
"It's not a rest for me, it's a rest for the weights." - Dom Mazzetti

Link to comment
Share on other sites

it happens on the left side.

Yeah that's where I thought it would. Actually, I think I just figured out what did it. Try with the new code?

polvCwJ.gif
"It's not a rest for me, it's a rest for the weights." - Dom Mazzetti

Link to comment
Share on other sites

I love that game!

 

About the thinking times - you could build an arraylist (thats what it's called in java at least) of available dots it could place, and it could just delete points as they are used up. Then it wouldn't have to wait until an acceptable random point was produced, it would just refer to an array. It would still complete boxes when that's appropriate. That should speed it up a fair bit. Dunno if it would be a bit memory-intensive though.

 

A couple of bugs

 

If you give the computer a box, and the line that is thus drawn creates the opportunity for a new box to be made, then it does not take the chance. eg (ignore dots)

_ _

| .. |

|_ _|

goes to this by a line drawn by me

_ . _

|..|..|

|_ _|

then the computer correctly makes a box

_ _

|_|. |

|_ _|

but it doesn't create the remaining boxes. Shouldn't be too difficult to fix, just stick the existing code in a loop.

 

To eliminate the machine creating easy boxes you can make when it's not necessary, you could simulate a line being made using the proposed coordinates, and then simulate the machine taking another move with code already in place for checking if a box is available (ie coords chosen, check if a box can be made if the proposed line is drawn (using existing code re. machine checking if a box can be made at the beginning of its turn)). if it is true that a box can be made, than get new random numbers. (Is that clear? I dunno)

 

Please don't take this as negative criticism, I enjoy the challenge of programming, thus debugging :P this is far more than I could make though, so i'm not knocking you.

RIP TET

 

original.png

 

"That which does not kill us makes us stronger." - Friedrich Nietzsche

Link to comment
Share on other sites

Really? It should account for all those scenarios if you're the one giving the first box. If it gives itself the first box it won't work...but all of the others should work.

polvCwJ.gif
"It's not a rest for me, it's a rest for the weights." - Dom Mazzetti

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.