{"id":5,"date":"2022-01-07T01:39:06","date_gmt":"2022-01-07T01:39:06","guid":{"rendered":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/?p=5"},"modified":"2022-01-07T01:58:02","modified_gmt":"2022-01-07T01:58:02","slug":"exploring-mari-o","status":"publish","type":"post","link":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/2022\/01\/07\/exploring-mari-o\/","title":{"rendered":"Exploring MarI\/O"},"content":{"rendered":"\n<p>During the holidays (while exploring various potential projects for this course) I dug a bit into some of the various neural networks being used to play video games.&nbsp; A few examples I enjoyed reading follow:<\/p>\n\n\n\n<p>A Neuroevolution Approach to General Atari Game Playing (<a href=\"http:\/\/www.cs.utexas.edu\/users\/pstone\/Papers\/bib2html-links\/TCIAIG13-mhauskn.pdf\">http:\/\/www.cs.utexas.edu\/users\/pstone\/Papers\/bib2html-links\/TCIAIG13-mhauskn.pdf<\/a>),<\/p>\n\n\n\n<p>Playing Atari with Deep Reinfocement Learning (<a href=\"https:\/\/www.cs.toronto.edu\/~vmnih\/docs\/dqn.pdf\">https:\/\/www.cs.toronto.edu\/~vmnih\/docs\/dqn.pdf<\/a>)<\/p>\n\n\n\n<p>SethBling\u2019s MarI\/O (https:\/\/www.youtube.com\/watch?v=qv6UVOQ0F44)<\/p>\n\n\n\n<p>While all are great, I\u2019m going to focus specifically on some of my notes\/thoughts while exploring MarI\/O\u2019s input layer.&nbsp; MarI\/O is an implementation of a genetic algorithm used to play Super Mario World (\u201cSMW\u201d) for the SNES.&nbsp; While digging into this implementation, I discovered the fascinating community surrounding SNES ROM hacking.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>For SMW specifically, there exists a community called SMW Central (<a href=\"https:\/\/www.smwcentral.net\/\">https:\/\/www.smwcentral.net\/<\/a>).&nbsp; This community consists of dedicated enthusiasts who create and share various hacks of the original ROM.&nbsp; This community has created and maintains very detailed technical specifications of SMW, and freely discusses and shares detail for other games as well.&nbsp; This resource was very invaluable in digging into the inputs for MarI\/O.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The following is a list of memory locations utilized by MarI\/O for SMW to create the inputs:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Variable<\/td><td>Memory Location &#8211; Per MarI\/O<\/td><td>Description (From SMW Central &#8211; https:\/\/www.smwcentral.net\/?p=nmap&amp;m=smwram)<\/td><\/tr><tr><td>getPositions \u2013 marioX<\/td><td>0x94<\/td><td>$7E0094 &#8211; Player X position (16-bit) within the level, next frame (calculates player position one frame ahead, as opposed to $7E:00D1). It&#8217;s also used as a player X position on-screen on the overworld border.<\/td><\/tr><tr><td>getPositions \u2013 marioY<\/td><td>0x96<\/td><td>$7E0096 &#8211; Player Y position (16-bit) within the level, next frame (calculates player position one frame ahead, as opposed to $7E:00D3). It&#8217;s also used as a player Y position on-screen on the overworld border.<\/td><\/tr><tr><td>getPositions \u2013 layer1x<\/td><td>0x1A<\/td><td>$7E1462 &#8211; Layer 1 X position, current frame. Mirror of SNES register $210D.<\/td><\/tr><tr><td>getPositions \u2013 layer1y<\/td><td>0x1C<\/td><td>$7E1464 &#8211; Layer 1 Y position, current frame. Mirror of SNES register $210E.<\/td><\/tr><tr><td>getTile \u2013 return<\/td><td>0x1C800<\/td><td>$7FC800 &#8211; Map16 high byte table. Same format as $7E:C800. $7F:FFF8 through $7F:FFFD are also used by Lunar Magic&#8217;s title screen recording ASM.<\/td><\/tr><tr><td>getSprites \u2013 status<\/td><td>0x14C8<\/td><td>$7E14C8 &#8211; Sprite status table: &nbsp; #$00 = Free slot, non-existent sprite. #$01 = Initial phase of sprite. #$02 = Killed, falling off screen. #$03 = Smushed. Rex and shell-less Koopas can be in this state. #$04 = Killed with a spinjump. #$05 = Burning in lava; sinking in mud. #$06 = Turn into coin at level end. #$07 = Stay in Yoshi&#8217;s mouth. #$08 = Normal routine. #$09 = Stationary \/ Carryable. #$0A = Kicked. #$0B = Carried. #$0C = Powerup from being carried past goaltape. &nbsp; States 08 and above are considered alive; sprites in other states are dead and should not be interacted with.<\/td><\/tr><tr><td>getSprites \u2013 spritex<\/td><td>0xE4<\/td><td>$7E00E4 &#8211; Sprite X position, low byte.<\/td><\/tr><tr><td>getSprites \u2013 spritex<\/td><td>0x14E0<\/td><td>$7E14E0 &#8211; Sprite X position, high byte.<\/td><\/tr><tr><td>getSprites \u2013 spritey<\/td><td>0xD8<\/td><td>$7E00D8 &#8211; Sprite Y position, low byte.<\/td><\/tr><tr><td>getSprites \u2013 spritey<\/td><td>0x14D4<\/td><td>$7E14D4 &#8211; Sprite Y position, high byte.<\/td><\/tr><tr><td>getExtendedSprites \u2013 number<\/td><td>0x170B<\/td><td>$7E170B &#8211; Extended sprite number.&nbsp; Last two bytes reserved for fireballs.<\/td><\/tr><tr><td>getExtendedSprites \u2013 spritex<\/td><td>0x171F<\/td><td>$7E171F &#8211; Extended sprite X position, low byte. Last two bytes reserved for fireballs.<\/td><\/tr><tr><td>getExtendedSprites \u2013 spritex<\/td><td>0x1733<\/td><td>$7E1733 &#8211; Extended sprite X position, high byte. Last two bytes reserved for fireballs.<\/td><\/tr><tr><td>getExtendedSprites \u2013 spritey<\/td><td>0x1715<\/td><td>$7E1715 &#8211; Extended sprite Y position, low byte. Last two bytes reserved for fireballs.<\/td><\/tr><tr><td>getExtendedSprites \u2013 spritey<\/td><td>0x1729<\/td><td>$7E1729 &#8211; Extended sprite Y position, high byte. Last two bytes reserved for fireballs.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>While the list is fairly straight forward, digging into the \u201cwhy\u201d behind each of these was very interesting.&nbsp; Let\u2019s start with the inputs from the getPositions function.&nbsp; This RAM maps to Mario\u2019s X and Y coordinate on the screen.&nbsp; This is used to drive the fitness within the algorithm, and to help determine the Map 16 tiles that need to be pulled from memory for purposes of building input tiles, and determining Mario\u2019s distance from enemies.&nbsp; It doesn\u2019t appear as if the layer1 variables are ultimately utilized in any of the calculations.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The getTile variable was probably the most confusing for me to find specific detail around.&nbsp; This variable maps to the map16 high byte.&nbsp; Thanks to the resources at SMW Central I was able to find Lunar Magic, which help clear up a lot of my confusion around how this memory was being used.&nbsp; In general, a Map 16 high byte of 01 in SMW maps to tiles that are solid &#8211; these can include everything from ground tiles, question mark blocks, slopes, and (unfortunately for the Mario character being controlled by this implementation) even spikes.&nbsp; <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"930\" height=\"934\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image.png\" alt=\"\" class=\"wp-image-6\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image.png 930w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-300x300.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-150x150.png 150w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-768x771.png 768w\" sizes=\"auto, (max-width: 930px) 100vw, 930px\" \/><figcaption>Map16 Tiles &#8211; Example 1 &#8211; The tiles in this tilemap seem like they would generally work fairly well. \ud83d\ude42<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"933\" height=\"934\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-1.png\" alt=\"\" class=\"wp-image-7\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-1.png 933w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-1-300x300.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-1-150x150.png 150w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-1-768x769.png 768w\" sizes=\"auto, (max-width: 933px) 100vw, 933px\" \/><figcaption>Map16 Tiles &#8211; Example 2 &#8211; The tiles in this tilemap have tiles that would kill Mario. \ud83d\ude41<\/figcaption><\/figure>\n\n\n\n<p>These inputs are all brought together in the getInputs function to ultimately drive the creation of a feature matrix within the neural network representing small areas of the screen.&nbsp; All features are initially assigned a value of 0, then is further assigned a value of 1 if there is a solid tile in that particular area, or a value of -1 if an enemy (sprite) or obstacle (extended sprite) exists in that particular area.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>While it isn\u2019t lost on me that MarI\/O was created mostly to create an awesome YouTube video, and I shouldn\u2019t be too critical, using this input feature selection wouldn&#8217;t work for a large number of the game&#8217;s levels.&nbsp; Simply assigning a weight to a tile based on the high byte loses a lot of information that could be provided to the neural network, and will lead to inconsistent results across various tilesets.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>For example, as discussed above, the example 2 tileset contains spikes with a high byte of 01. The image below shows an area where this would likely lead to issues for MarI\/O. Based on how the current inputs are utilized, the spikes would be assigned a weight of 1.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"928\" height=\"746\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-2.png\" alt=\"\" class=\"wp-image-8\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-2.png 928w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-2-300x241.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5066\/files\/2022\/01\/image-2-768x617.png 768w\" sizes=\"auto, (max-width: 928px) 100vw, 928px\" \/><figcaption>The spikes on this level wouldn&#8217;t be recognized as being different than other ground tiles.<\/figcaption><\/figure>\n\n\n\n<p>Ultimately, I&#8217;d like to pick up and continue to explore this (and other) implementations for ML in gaming.  This examination lead me down a path of exploring emulation as a project for this course.  I&#8217;m excited to dig more into emulation by building an NES emulator as a project for this course.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>During the holidays (while exploring various potential projects for this course) I dug a bit into some of the various neural networks being used to play video games.&nbsp; A few examples I enjoyed reading follow: A Neuroevolution Approach to General &hellip; <a href=\"https:\/\/blogs.oregonstate.edu\/ericmorgan\/2022\/01\/07\/exploring-mari-o\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":11915,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/posts\/5","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/users\/11915"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/comments?post=5"}],"version-history":[{"count":4,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/posts\/5\/revisions"}],"predecessor-version":[{"id":14,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/posts\/5\/revisions\/14"}],"wp:attachment":[{"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/media?parent=5"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/categories?post=5"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/ericmorgan\/wp-json\/wp\/v2\/tags?post=5"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}