{"id":750,"date":"2019-12-09T01:09:25","date_gmt":"2019-12-09T01:09:25","guid":{"rendered":"https:\/\/www.danielparente.net\/en\/2019\/12\/09\/learning-modern-javascript-with-tetris-michael-karen\/"},"modified":"2019-12-09T01:09:25","modified_gmt":"2019-12-09T01:09:25","slug":"learning-modern-javascript-with-tetris-michael-karen","status":"publish","type":"post","link":"https:\/\/www.danielparente.net\/en\/2019\/12\/09\/learning-modern-javascript-with-tetris-michael-karen\/","title":{"rendered":"Learning Modern JavaScript with Tetris &#8211; Michael Kar\u00e9n"},"content":{"rendered":"<p> [ad_1]<br \/>\n<br \/><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1200\/1*hekydXN81H_tb8GT_OSQqw.png\" \/><\/p>\n<div>\n<p id=\"2d92\" class=\"gj gk ar bz gl b gm ih go ii gq ij gs ik gu il gw\">The board in Tetris consists of cells, which are either occupied or not. My first thought was to represent a cell with boolean values. But, we can do better by using numbers. We can represent an empty cell with 0, and the colors with numbers 1\u20137.<\/p>\n<p id=\"72cb\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">The next concept is representing the rows and columns of the game board. We can use an array of numbers to represent a row. And the board is an array of rows. In other words, a two dimensional (2D) array or what we call a matrix.<\/p>\n<p id=\"80ff\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">Let\u2019s create a function in <code class=\"dx io ip iq ir b\">board.js<\/code> that returns an empty board with all cells set to zero. The <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/fill\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">fill()<\/a> method comes in handy here:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"13ca\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We can call this function in <code class=\"dx io ip iq ir b\">main.js<\/code> when we press play:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"35fa\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">By using <code class=\"dx io ip iq ir b\">console.table<\/code> we see the representation of the board in numbers:<\/p>\n<figure class=\"hk hl hm hn ho do da db paragraph-image\"\/>\n<p id=\"6aaf\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">The X and Y coordinates represent the cells of the board. Now that we have the board, let\u2019s take a look at the moving parts.<\/p>\n<p id=\"c6a3\" class=\"gj gk ar bz gl b gm ih go ii gq ij gs ik gu il gw\">A piece in Tetris is a shape consisting of four blocks that move as a unit. They are often called tetrominos and come in seven different patterns and colors. The names I, J, L, O, S, T, and Z are from the resemblance in their shape.<\/p>\n<figure class=\"hk hl hm hn ho do da db paragraph-image\"\/>\n<p id=\"c65e\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We represent the J tetromino as a matrix where the number two represents the colored cells. We add the row of zeros to get a center to rotate around:<\/p>\n<pre class=\"hk hl hm hn ho ka kb kc\"><span id=\"9233\" class=\"it hu ar bz ir b fh kd ke r kf\">[<strong class=\"ir kg\">2<\/strong>, 0, 0],<br\/>[<strong class=\"ir kg\">2, 2, 2<\/strong>],<br\/>[0, 0, 0];<\/span><\/pre>\n<blockquote class=\"kh ki kj\">\n<p id=\"f11f\" class=\"gj gk ar kk gl b gm gn go gp gq gr gs gt gu gv gw\">The tetrominos spawn horizontally with J, L, and T spawning flat-side first.<\/p>\n<\/blockquote>\n<p id=\"fcea\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We want the Piece class to know its <strong class=\"gl kg\">position<\/strong> on the board, what <strong class=\"gl kg\">color<\/strong> it has, and its <strong class=\"gl kg\">shape<\/strong>. So to be able to draw itself on the board, it needs a reference to the <strong class=\"gl kg\">canvas context<\/strong>.<\/p>\n<p id=\"8537\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">For starters, we can hard-code the values of our piece:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"d0ee\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">To draw the tetromino on the board, we loop through all the cells of the shape. If the value in the cell is greater than zero, then we color that block.<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"eabe\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">The board keeps track of the tetromino on the board so we can create and paint it when we press the play button:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"5c10\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">The blue J tetromino appears!<\/p>\n<figure class=\"hk hl hm hn ho do da db paragraph-image\"\/>\n<p id=\"1577\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">Next, let\u2019s make magic happen through the keyboard.<\/p>\n<p id=\"6057\" class=\"gj gk ar bz gl b gm ih go ii gq ij gs ik gu il gw\">We need to connect the keyboard events to move the piece on the board. The <code class=\"dx io ip iq ir b\">move<\/code> function changes the x or y variable of the current piece to change its position on the board.<\/p>\n<pre class=\"hk hl hm hn ho ka kb kc\"><span id=\"0514\" class=\"it hu ar bz ir b fh kd ke r kf\">move(p) {<br\/><em class=\"kk\">this<\/em>.x = p.x;<br\/><em class=\"kk\">this<\/em>.y = p.y;<br\/>}<\/span><\/pre>\n<h2 id=\"382f\" class=\"it hu ar bz by hv iu iv iw ix iy iz ja jb jc jd je\">Enums<\/h2>\n<p id=\"1331\" class=\"gj gk ar bz gl b gm ih go ii gq ij gs ik gu il gw\">Next, we map the keys to the key codes in <code class=\"dx io ip iq ir b\">constants.js<\/code>. For this, it would be nice to have an enum.<\/p>\n<blockquote class=\"kh ki kj\">\n<p id=\"37fb\" class=\"gj gk ar kk gl b gm gn go gp gq gr gs gt gu gv gw\">Enum (enumeration) is a special type used to define collections of constants.<\/p>\n<\/blockquote>\n<p id=\"6b70\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">There are no built-in enums in JavaScript so let\u2019s make one by creating an object with the values:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"c3e6\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">The const can be a bit misleading when working with objects and arrays and does not actually make them immutable. To achieve this, we can use <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/freeze\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Object.freeze()<\/a>. A couple of gotchas here are:<\/p>\n<ul class=\"\">\n<li id=\"a7b2\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw gx gy gz\">For this to work properly, we need to use <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Strict_mode\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">strict mode<\/a>.<\/li>\n<li id=\"deb1\" class=\"gj gk ar bz gl b gm he go hf gq hg gs hh gu hi gw gx gy gz\">This only works one level down. In other words, if we have an array or object inside our object, then this does not freeze them.<\/li>\n<\/ul>\n<h2 id=\"b849\" class=\"it hu ar bz by hv iu iv iw ix iy iz ja jb jc jd je\">Object literals<\/h2>\n<p id=\"d710\" class=\"gj gk ar bz gl b gm ih go ii gq ij gs ik gu il gw\">To match the key events to actions, we can use object literal lookups.<\/p>\n<blockquote class=\"kh ki kj\">\n<p id=\"d411\" class=\"gj gk ar kk gl b gm gn go gp gq gr gs gt gu gv gw\">ES6 allows property keys of object literals to use expressions, making them computed property keys.<\/p>\n<\/blockquote>\n<p id=\"da96\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We need the brackets to get computed property names so that we can use our constants. This is a simplified example of how it works:<\/p>\n<pre class=\"hk hl hm hn ho ka kb kc\"><span id=\"c8f7\" class=\"it hu ar bz ir b fh kd ke r kf\">const X = 'x';<br\/>const a = { [X]: 5 };<br\/>console.log(a.x); <em class=\"kk\">\/\/ 5<\/em><\/span><\/pre>\n<p id=\"340a\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We want to send in the current tetromino and return a copy of it together with the change in coordinates. For this, we can use the spread operator to get a shallow copy and then change the coordinates to our desired position.<\/p>\n<blockquote class=\"kh ki kj\">\n<p id=\"248b\" class=\"gj gk ar kk gl b gm gn go gp gq gr gs gt gu gv gw\">In JavaScript, we can use <strong class=\"gl kg\">shallow copying<\/strong> to copy primitive data types like numbers and strings. In our case, the coordinates are numbers. ES6 offers two shallow copy mechanisms: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/assign\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">Object.assign()<\/a> and the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/Spread_syntax\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">spread operator<\/a>.<\/p>\n<\/blockquote>\n<p id=\"8e86\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">In other words, a lot is going on in this code snippet:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"e3ab\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">Which we can use with the code beneath to get the new state without mutating the original piece. It\u2019s important because we don\u2019t always want to move to a new position.<\/p>\n<pre class=\"hk hl hm hn ho ka kb kc\"><span id=\"08e2\" class=\"it hu ar bz ir b fh kd ke r kf\">const p = <em class=\"kk\">this<\/em>.moves[event.key](<em class=\"kk\">this<\/em>.piece);<\/span><\/pre>\n<p id=\"1325\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">Next, we add an event listener that listens to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Document\/keydown_event\" class=\"bi cv ha hb hc hd\" target=\"_blank\" rel=\"noopener nofollow noreferrer\">keydown events<\/a>:<\/p>\n<figure class=\"hk hl hm hn ho do\"\/>\n<p id=\"09a5\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">Now we are listening to the keyboard events, and if we press left, right, or down arrows, then we can see the piece moving.<\/p>\n<figure class=\"hk hl hm hn ho do da db paragraph-image\"\/>\n<p id=\"4fb4\" class=\"gj gk ar bz gl b gm gn go gp gq gr gs gt gu gv gw\">We have a movement! However, ghost pieces going through walls are not what we want.<\/p>\n<\/div>\n<p>[ad_2]<br \/>\n<br \/><a href=\"https:\/\/medium.com\/@michael.karen\/learning-modern-javascript-with-tetris-92d532bcd057\" target=\"_blank\" rel=\"noopener\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>[ad_1] The board in Tetris consists of cells, which are either occupied or not. My first thought was to represent a cell with boolean values. But, we can do better by using numbers. We can represent an empty cell with 0, and the colors with numbers 1\u20137. The next concept is representing the rows and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":751,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-750","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"blocksy_meta":[],"jetpack_featured_media_url":"https:\/\/e928cfdc7rs.exactdn.com\/info\/uploads\/sites\/3\/2019\/12\/Learning-Modern-JavaScript-with-Tetris-Michael-Kar\u00e9n-scaled.png?strip=all","jetpack_shortlink":"https:\/\/wp.me\/p2TFCd-c6","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts\/750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/comments?post=750"}],"version-history":[{"count":0,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts\/750\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/media\/751"}],"wp:attachment":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/media?parent=750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/categories?post=750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/tags?post=750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}