7
\$\begingroup\$

In another attempt to further my knowledge in the JavaScript language, I've written a chess board generator that will essentially create a chess board with any initial state supplied. This supports the idea of chess game types like fairy chess or series self-mate and puzzle generation alike.

It was a rather fun project, and I'll end up expanding on it further in the future, and perhaps creating an API for it but I can't help but feel like it could use some improvement.

// Create and fill the array that holds our pieces.
var board = [];
board.push(["R", "N", "B", "K", "Q", "B", "N", "R"]);
board.push(["P", "P", "P", "P", "P", "P", "P", "P"]);
board.push(["E", "E", "E", "E", "E", "E", "E", "E"]);
board.push(["E", "E", "E", "E", "E", "E", "E", "E"]);
board.push(["E", "E", "E", "E", "E", "E", "E", "E"]);
board.push(["E", "E", "E", "E", "E", "E", "E", "E"]);
board.push(["P", "P", "P", "P", "P", "P", "P", "P"]);
board.push(["R", "N", "B", "K", "Q", "B", "N", "R"]);

// Draw the initial board.
var boardElement = document.getElementById("chess-board");
var rows = "";
for (var x = 0; x < board.length; x++) {
	rows += '<div class="row">';
	
	for (var y = 0; y < board[x].length; y++) {
		var args = x + ", " + y;
		var mouseOver = 'onmouseover="checkSquare(this, ' + args + ')" ';
		var mouseOut = 'onmouseout="clearSquare(this, ' + args + ')" ';
		var click = 'onclick="clickSquare(this, ' + args + ')" ';
		var square = "<div " + mouseOver + mouseOut + click + ">";
		
		var piece = "";
		if (board[x][y] != "E")
			piece = '<i class="fas fa-chess-';
			
		
		switch (board[x][y]) {
			case "P": piece += "pawn"; break;
			case "R": piece += "rook"; break;
			case "N": piece += "knight"; break;
			case "B": piece += "bishop"; break;
			case "K": piece += "king"; break;
			case "Q": piece += "queen"; break;
		}
		
		if (piece.length > 0){
			var shade = "dark";
			if (x > 5)
				shade = "light";
			
			piece += ' ' + shade + '"></i>';
		}
		
		rows += square + piece + '</div>';
	}
	
	rows += "</div>";
}
boardElement.innerHTML = rows;

function checkSquare(e, x, y) {}
function clearSquare(e, x, y) {}
function clickSquare(e, x, y) {
	if (e)
		e.classList.toggle("waiting");
}
/* Board Styles */
.chess-board {
	width: 75vh;
	min-width: 500px;
	height: 75vh;
	min-height: 500px;
	display: grid;
	grid-template-columns: repeat(1, 100%);
	grid-template-rows: repeat(8, 12.5%);
	place-items: center;
	border-radius: 15px;
	box-shadow: 0 0 15px #0005;
}
.chess-board > .row {
	width: 100%;
	height: 100%;
}
.chess-board > .row > div {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 12.5%;
	height: 100%;
	border: none;
	transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) all;
	cursor: pointer;
}
.chess-board > .row > div:hover > i { font-size: 7vh; }
.chess-board > .row > div > i {
	font-size: 5vh;
	text-shadow: 2px 2px 3px #0005;
	transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) all;
}

/* Border Radius */
.chess-board .row:nth-child(1) > div:nth-child(1) { border-top-left-radius: 15px; }
.chess-board .row:nth-child(1) > div:last-of-type { border-top-right-radius: 15px; }
.chess-board .row:last-of-type > div:nth-child(1) { border-bottom-left-radius: 15px; }
.chess-board .row:last-of-type > div:last-of-type { border-bottom-right-radius: 15px; }
.chess-board .row:last-of-type() {
	border-bottom-left-radius: 15px;
	border-bottom-right-radius: 15px;
}
.chess-board .row:nth-child(1) {
	border-top-left-radius: 15px;
	border-top-right-radius: 15px;
}

/* Colors */
.chess-board .row:nth-child(odd) > div:nth-child(odd),
.chess-board .row:nth-child(even) > div:nth-child(even) {
	background-color: #9995;
}
.chess-board .row:nth-child(odd) > div:nth-child(even),
.chess-board .row:nth-child(even) > div:nth-child(odd) {
	background-color: #3335;
}
.chess-board .row > div:hover { border: 5px solid #aafa; }
.chess-board .row > div.invalid:hover { border: 5px solid #f33a; }
.chess-board .row > div.checkmate { background-color: #f33a !important; }
.chess-board .row > div.waiting {
	animation: 1.5s border-pulse linear infinite;
}
.chess-board .row > div > i.dark { color: #97f; }
.chess-board .row > div > i.light { color: #f79; }

/* Animations */
@keyframes border-pulse {
	0%, 100% { border: 5px solid #5f90; }
	50% { border: 5px solid #5f9a; }
}

/* Cursors */
.chess-board .row > div.invalid { cursor: not-allowed; }

/* Title Area */
.display-3 .fa-chess { transform: translateY(-10px); }
.display-3 .flip { transform: translateY(-10px) rotateY(180deg); }

/* Template Overrides */
.primary-content {
	display: flex;
	flex-direction: column;
	align-items: center;
}
.lead { font-size: 25px; }
<link href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" rel="stylesheet"/>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/2940219/PerpetualJ.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div id="primary-content" class="primary-content">
	<h1 class="display-3"><i class="fas fa-chess"></i> Chess <i class="fas fa-chess flip"></i></h1>
	<p class="lead">Use the board array in the JavaScript to change the initial state of the board. This is still a WORK IN PROGRESS</p>
	<div id="chess-board" class="chess-board"></div>
</div>

Some of the things I'm wondering are:

  • Are there any security concerns with the current approach?
    • Focusing on the use of innerHTML here as I believe it could be potentially dangerous.
    • Should I be creating elements instead of using text based HTML insertion?
  • Are there any more-efficient ways of accomplishing this?
  • Are there any potential gotchas with the direction I took here?

As always, additional guidance and comments are more than welcome. Please ensure you supply documentation for anything meant to follow some kind of best practice.

\$\endgroup\$
  • \$\begingroup\$ Can you use ES6? \$\endgroup\$ – ggorlen Sep 6 at 18:11
  • 1
    \$\begingroup\$ @ggorlen I'd have to learn it, but I don't see why not. I run my website on Google Cloud Platform's Compute Engines so I can set it up with whatever I need. :) \$\endgroup\$ – PerpetualJ Sep 6 at 18:34
3
\$\begingroup\$

Are there any security concerns with the current approach?

No. You never interact with a server or a database. There is no way you could have any security concerns.

Focusing on the use of innerHTML here as I believe it could be potentially dangerous. Should I be creating elements instead of using text based HTML insertion?

No it does not matter. Users have access to this already. For example, on this webpage (codereview.stackexchange.com) you can right click an element and edit it. You can even edit the JavaScript. It's all client side. Users can always 'hack' themselves.

I recommend using an ENUM for your board pieces. This will help with readability.

This is a little picky, but I'd use a different variable name for args. Use descriptive names, don't name it args because you use it as an argument for a function. args is also used often inside of a main method in other languages.

Try to avoid magic numbers. Instead declare a static variable at the top. Or At the very least, add a comment describing what the number is.

if (x > 5)
    shade = "light";
\$\endgroup\$
  • 1
    \$\begingroup\$ With regards to using an enum for the board pieces, should I still consider that approach for just the foundational pieces and then use strings for user defined pieces for things such as fairy chess where you can name your own pieces or should I keep it strings all together to keep it consistent? If this is confusing let me know and I'll try to phrase it better. :) +1 for the great answer! \$\endgroup\$ – PerpetualJ Sep 6 at 16:38
  • 1
    \$\begingroup\$ In that case I'd say make a class (or anonymous object) for the pieces. Or just give the Enum an additional property. That way 'Knight' stays as 'Knight' even if the user names it something else. \$\endgroup\$ – dustytrash Sep 6 at 16:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.