
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>gamescapades</title>
    <description>it's all downhill from here.</description>
    <link>https://gamescapad.es/</link>
    <atom:link href="https://gamescapad.es/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 03 Jul 2025 04:01:45 +0200</pubDate>
    <lastBuildDate>Thu, 03 Jul 2025 04:01:45 +0200</lastBuildDate>
    <generator>11ty</generator>
    
      
        <item>
          
            <title>reviews</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;ul class=&#34;post-list categorylist&#34;&gt;
&lt;p&gt;&lt;li&gt;
&lt;a href=&#34;/review-of-mirrors-edge-catalyst/&#34; class=&#34;post-link&#34;&gt;
&lt;div class=&#34;post-link__heading&#34;&gt;
&lt;h1 class=&#34;post-link__title&#34;&gt;
Mirror&#39;s Edge Catalyst is a Crap Game
&lt;/h1&gt;
&lt;/div&gt;
&lt;span class=&#34;post-date&#34;&gt;
May 19, &#39;19
&lt;/span&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

          </description>
          <pubDate>Tue, 01 Jul 2025 08:14:43 +0200</pubDate>
          <link>https://gamescapad.es/reviews/</link>
          <guid isPermaLink="true">https://gamescapad.es/reviews/</guid>
          
          
        </item>
      
    
      
        <item>
          
            <title>home</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            
          </description>
          <pubDate>Tue, 01 Jul 2025 08:14:43 +0200</pubDate>
          <link>https://gamescapad.es/</link>
          <guid isPermaLink="true">https://gamescapad.es/</guid>
          
          
        </item>
      
    
      
        <item>
          
            <title>essays</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;ul class=&#34;post-list categorylist&#34;&gt;&lt;li&gt;
    &lt;a href=&#34;/increasing-diversity-decreases-team-blindspots/&#34; class=&#34;post-link&#34;&gt;
        &lt;div class=&#34;post-link__heading&#34;&gt;
            &lt;h1 class=&#34;post-link__title&#34;&gt;
                Increasing Diversity Decreases Team Blind Spots
            &lt;/h1&gt;
        &lt;/div&gt;
        &lt;span class=&#34;post-date&#34;&gt;
            Nov 22, &#39;22
        &lt;/span&gt;
    &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/&#34; class=&#34;post-link&#34;&gt;
        &lt;div class=&#34;post-link__heading&#34;&gt;
            &lt;h1 class=&#34;post-link__title&#34;&gt;
                Planet Ghibli Part 3 -  How AI can increase inequality in society if we do not engage in diversity
            &lt;/h1&gt;
        &lt;/div&gt;
        &lt;span class=&#34;post-date&#34;&gt;
            Aug 14, &#39;20
        &lt;/span&gt;
    &lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

          </description>
          <pubDate>Tue, 01 Jul 2025 08:14:43 +0200</pubDate>
          <link>https://gamescapad.es/essays/</link>
          <guid isPermaLink="true">https://gamescapad.es/essays/</guid>
          
          
        </item>
      
    
      
        <item>
          
            <title>contact</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Want to get in touch? Great! Email is probably the safest bet if you want a response this century.&lt;/p&gt;
&lt;ul class=&#34;contact-me&#34;&gt;
	&lt;li&gt;email: &lt;a href=&#34;mailto:h.siljebrat@gold.ac.uk&#34;&gt;h.siljebrat@gold.ac.uk&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;linkedin: &lt;a href=&#34;https://www.linkedin.com/in/henrik-siljebrat&#34;&gt;Henrik Siljebråt&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;twitter: &lt;a href=&#34;https://twitter.com/foh&#34;&gt;foh&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;github: &lt;a href=&#34;https://github.com/fohria&#34;&gt;fohria&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

          </description>
          <pubDate>Tue, 01 Jul 2025 08:14:43 +0200</pubDate>
          <link>https://gamescapad.es/contact/</link>
          <guid isPermaLink="true">https://gamescapad.es/contact/</guid>
          
          
        </item>
      
    
      
        <item>
          
            <title>about</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p class=&#34;about&#34;&gt;gamescapades is the &lt;s&gt;personal blog&lt;/s&gt; public rant storage of &lt;a href=&#34;https://henrik.siljebrat.se&#34;&gt;Henrik Siljebråt&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&#34;about&#34;&gt;gamescapades is a blog about life,&lt;br /&gt;
games&lt;br /&gt;
and my lovely adventures in both.&lt;br/&gt;
because life is a game.&lt;br/&gt;
a horrible and wonderful game.&lt;br /&gt;
and then you die.&lt;br /&gt;
maybe respawn is enabled?&lt;/p&gt;
&lt;p class=&#34;about&#34;&gt;To know more you can visit &lt;a href=&#34;https://henrik.siljebrat.se&#34;&gt;the website named after myself&lt;/a&gt;&lt;/p&gt;
&lt;p class=&#34;about&#34;&gt;If you&#39;re lazy, this is me in hash tag form:&lt;br/&gt;
&lt;span class=&#34;neuroscience&#34;&gt;#neuroscience&lt;/span&gt; &lt;span class=&#34;videogames&#34;&gt;#videogames&lt;/span&gt; &lt;span class=&#34;ledzeppelin&#34;&gt;#ledzeppelin&lt;/span&gt;&lt;/p&gt;
&lt;p class=&#34;about&#34;&gt;Here are some selected reviews of this site:&lt;/p&gt;
&lt;blockquote&gt;
&lt;h3&gt;&amp;quot;not totally horrendous&amp;quot;&lt;/h3&gt;
&lt;p&gt;-- &lt;a href=&#34;https://twitter.com/meowmentai&#34;&gt;zoë o&#39;shea&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class=&#34;about&#34;&gt;I used &lt;a href=&#34;https://11ty.dev&#34;&gt;11ty&lt;/a&gt; to create this site, using a modified &lt;a href=&#34;https://github.com/patdryburgh/hitchens&#34;&gt;Hitchens&lt;/a&gt; theme. I&#39;ve also made the effort to not rely on any third party sites for fonts and scripts. That means your adblocker should show nothing is blocked. I believe that such efforts are good for the health of the interwebs, for security and privacy reasons.&lt;/p&gt;
&lt;p class=&#34;about&#34; id=&#34;ratio&#34;&gt;The current post/redesign ratio is: 2 (10 posts, 5 redesigns)&lt;/p&gt;

          </description>
          <pubDate>Tue, 01 Jul 2025 08:14:43 +0200</pubDate>
          <link>https://gamescapad.es/about/</link>
          <guid isPermaLink="true">https://gamescapad.es/about/</guid>
          
          
        </item>
      
    
      
        <item>
          
            <title>Increasing Diversity Decreases Team Blind Spots</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;I was at an event the other day. Three AI talks followed by a panel discussion with the speakers.&lt;/p&gt;
&lt;p&gt;All three had these headsets with the mic itself at the end of an arm you can swing up and down. One of the speakers/panelists had long hair. Every time they turned their head to look at a fellow panelist, their hair bumped into the microphone so it swung upwards. Every time, they had to adjust the mic back down, next to their mouth. This was quite funny once I noticed it but also, why did this happen?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a) the headset was broken/worn out&lt;/li&gt;
&lt;li&gt;b) the headset was designed and tested exclusively by people with short hair&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the sake of argument, I assume it’s B&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, turning the anecdote into a great example of a team having blind spots in their knowledge. The headset designers simply didn’t think of what may happen if you have long hair and it bumps into the mic. If they had at least one person on the team with long hair, they would&#39;ve discovered the issue.&lt;/p&gt;
&lt;p&gt;This has hugely important implications for AI.&lt;/p&gt;
&lt;p&gt;Many of the questions to the panel had to do with ethics; transparency, trust, explainability, correctness, how to avoid discrimination and bias. My impression was the panelists have good intentions, as many answers brushed into diversity but it was never explicitly stated. What concerned me was the leaning towards technologist approaches.&lt;/p&gt;
&lt;p&gt;One of the answers to the question how to avoid biased datasets and discriminatory results/predictions was &amp;quot;that&#39;s the job of the data scientist&amp;quot;. But even if you’re the best data scientist in the world, due to your particular life experience and limited knowledge, there &lt;em&gt;will&lt;/em&gt; be aspects you miss. You will have blind spots.&lt;/p&gt;
&lt;p&gt;To decrease the unknown number of such blind spots, you have to increase diversity. Important to understand here is that diversity is not just about race, creed, gender, socioeconomic factors and other common diversity metrics. Those just mentioned are obviously important, but diversity is also about having more perspectives than that of computer science and maths. Like historians or sociologists. Ideally as integral parts of the team. Because bias and oppression is a societal problem, and AI systems use data from and have consequences in society.&lt;/p&gt;
&lt;p&gt;If you are not aware of this, you risk having a situation where you have an AI division made up and led by people who think everything is a technical problem. Facebook/Meta&#39;s AI division is the typical example here, which is led by Yann LeCun who &lt;a href=&#34;https://syncedreview.com/2020/06/30/yann-lecun-quits-twitter-amid-acrimonious-exchanges-on-ai-bias/&#34;&gt;quit twitter in 2020 over failing to see the bigger picture&lt;/a&gt;. More recently, Facebook/Meta &lt;a href=&#34;https://arstechnica.com/information-technology/2022/11/after-controversy-meta-pulls-demo-of-ai-model-that-writes-scientific-papers/&#34;&gt;released and then pulled an AI system advertised as being able to generate scientific papers and wiki articles&lt;/a&gt;, with &lt;a href=&#34;https://twitter.com/ylecun/status/1593293058174500865&#34;&gt;LeCun commenting&lt;/a&gt; that &amp;quot;it&#39;s no longer possible to have some fun&amp;quot;. The system was advertised as competent, not fun. In other words, LeCun continues to be unaware of the responsibility he and others at his company has to be mindful of the consequences of AI systems.&lt;/p&gt;
&lt;p&gt;AI already impacts society and will have even deeper impact in the future. If you are serious about using these systems to make society better - for everyone - then please take diversity to heart.&lt;/p&gt;
&lt;p&gt;You can do so by, for example, reading my &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/&#34;&gt;Planet Ghibli series&lt;/a&gt;. But don&#39;t take my word for it. If you&#39;re in the AI field and haven&#39;t watched &lt;a href=&#34;https://iclr.cc/virtual_2020/speaker_3.html&#34;&gt;Ruha Benjamin&#39;s ICLR 2020 keynote&lt;/a&gt; you should do yourself, your customers and society a service: watch it.&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;I realise the irony of basing my discussion on a biased assumption, but please bear with me :) &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Tue, 22 Nov 2022 01:00:00 +0100</pubDate>
          <link>https://gamescapad.es/increasing-diversity-decreases-team-blindspots/</link>
          <guid isPermaLink="true">https://gamescapad.es/increasing-diversity-decreases-team-blindspots/</guid>
          
          <category>machine learning</category>
          
          <category>human rights</category>
          
          <category>ethics</category>
          
          <category>equality</category>
          
          <category>ai</category>
          
          <category>artificial intelligence</category>
          
          <category>sustainability</category>
          
          <category>diversity</category>
          
          
          <category>essays</category>
          
        </item>
      
    
      
        <item>
          
            <title>Holistic Sustainability - Automating subtitles for Swedish public service with OpenAI Whisper</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Holistic Sustainability is my personal term&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt; to describe that sustainability is not only about the environment. For a truly sustainable society, we should minimise all forms of inequality, because they are all interconnected. If we cannot respect each other, how are we ever to respect the environment we are all part of and the earth we all share?&lt;/p&gt;
&lt;p&gt;Immigration and integration are two very loaded terms these days, and were big topics in the recent Swedish election. Without going into detail on these complex questions, part of the discussion revolves around difficulties to get new citizens feel included. Despite the fact that Swedes in general can and do speak English, most of Swedish society requires one to know Swedish.  Personally, I believe in providing people with the tools they need to succeed. So what if we could provide people a way to learn Swedish language and culture simultaneously?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;How is AI shifting power?&amp;quot;
-- &lt;a href=&#34;https://www.nature.com/articles/d41586-020-02003-2&#34;&gt;Pratyusha Kalluri&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://svt.se&#34;&gt;SVT&lt;/a&gt; is Sweden&#39;s public service TV. They provide a streaming service called &lt;a href=&#34;https://svtplay.se&#34;&gt;SVT Play&lt;/a&gt; with news, movies, documentaries, game shows - you name it. Most of their videos have subtitles in Swedish, but no other language. Many of their videos (like the one below) even have forced Swedish subtitles. Such subtitles are of course great if you know Swedish and have trouble hearing. But what if you don&#39;t know Swedish?&lt;/p&gt;
&lt;p&gt;I&#39;ve learned a lot of English by watching English language movies and TV shows with subtitles in Swedish. By being exposed to a language like that you get used to it and start to pick up phrases. Wouldn&#39;t it be a great idea if SVT had, at the very least, English subtitles?&lt;/p&gt;
&lt;p&gt;This is where &lt;a href=&#34;https://openai.com/blog/whisper&#34;&gt;OpenAI Whisper&lt;/a&gt; comes in. Whisper is a &amp;quot;general-purpose speech recognition model&amp;quot;, which means that it&#39;s a computer program that can transcribe voice into text. It can transcribe voices from 98 different languages, and - get this - even translate the text into English.&lt;/p&gt;
&lt;p&gt;I spent part of my weekend playing with it, and it is surprisingly easy to use. There are already many tutorials online on setup and basic use of Whisper, so I shall leave technical details for another post. The only relevant technical information I should make clear is that I used the &amp;quot;medium&amp;quot; size model. Results would likely be better with the &amp;quot;large&amp;quot; model. Yet, Whisper works surprisingly well.&lt;/p&gt;
&lt;h2&gt;The result&lt;/h2&gt;
&lt;p&gt;If you cannot see the video below, &lt;a href=&#34;https://vimeo.com/754221706&#34;&gt;check it out at Vimeo&lt;/a&gt;. I put the English subtitles at the top as the video already had hard coded Swedish subtitles at the bottom.&lt;/p&gt;
&lt;div style=&#34;padding:56.25% 0 0 0;position:relative;&#34;&gt;&lt;iframe src=&#34;https://player.vimeo.com/video/754221706?h=44a5d5087b&amp;amp;badge=0&amp;amp;autopause=0&amp;amp;player_id=0&amp;amp;app_id=58479&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; fullscreen; picture-in-picture&#34; allowfullscreen style=&#34;position:absolute;top:0;left:0;width:100%;height:100%;&#34; title=&#34;elpriset_subs&#34;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;script src=&#34;https://player.vimeo.com/api/player.js&#34;&gt;&lt;/script&gt;
&lt;br/&gt;
&lt;p&gt;If you know Swedish, you&#39;ll see the translation is quite good. Remember, this is with the medium size model, so presumably the large model would be even better. At around the 1min50s mark, the subtitle output gets ahead of itself and is a sentence ahead of what is being said for the rest of the video. We could adjust this manually, or there could be a Whisper setting to make this better from the start. Overall though, the subtitles do what subtitles should!&lt;/p&gt;
&lt;p&gt;Also, since Whisper translates audio, we don&#39;t get a translation of the title text at the start of the video. But if our primary audience is people learning Swedish, this is not a top priority anyway.&lt;/p&gt;
&lt;h2&gt;Thoughts and next steps&lt;/h2&gt;
&lt;p&gt;I think the result is really impressive, especially considering this was my first test. I haven&#39;t looked into all the Whisper settings, or had a chance to test the large model.&lt;/p&gt;
&lt;p&gt;However, Whisper is not capable of real-time translation and to get decent output speed you need a fairly beefy computer. But the system works well enough that it would be possible to create a web site where the user enters a URL to, for example, SVT Play, and after a few minutes you&#39;re provided with a subtitled video. Such a service is the obvious next step for this project, so keep an eye out for my next blog post by following me on &lt;a href=&#34;linkedin.com/in/henrik-siljebrat&#34;&gt;linkedin&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/foh&#34;&gt;twitter&lt;/a&gt; or subscribe to the &lt;a href=&#34;http://localhost:4000/feed.xml&#34;&gt;rss feed&lt;/a&gt; of this blog.&lt;/p&gt;
&lt;p&gt;Oh, by the way, I&#39;m looking for a job in the ML/AI space, hire me!&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;PS. If you like this idea and can fund cloud compute for this project, please get in touch.&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;Most likely, what I mean by the term is already included in existing theories like for example intersectionality. I just finished a PhD and have not had time to read up on these topics properly. I&#39;m obviously not the first to come up with this specific term, seeing as holisticsustainability.com was registered in 2009 &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Mon, 26 Sep 2022 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/holistic-sustainability-automating-subtitles-for-swedish-public-service/</link>
          <guid isPermaLink="true">https://gamescapad.es/holistic-sustainability-automating-subtitles-for-swedish-public-service/</guid>
          
          <category>machine learning</category>
          
          <category>human rights</category>
          
          <category>ethics</category>
          
          <category>equality</category>
          
          <category>ai</category>
          
          <category>artificial intelligence</category>
          
          <category>sustainability</category>
          
          <category>integration</category>
          
          <category>swedish</category>
          
          <category>english</category>
          
          <category>holistic sustainability</category>
          
          
          <category>tutorials</category>
          
          <category>experiment</category>
          
        </item>
      
    
      
        <item>
          
            <title>Planet Ghibli Part 3 -  How AI can increase inequality in society if we do not engage in diversity</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Welcome to part 3 of Planet Ghibli! This time we&#39;re getting political.&lt;/p&gt;
&lt;p&gt;As we have seen in &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/&#34;&gt;Part 1&lt;/a&gt; and &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part2/&#34;&gt;Part 2&lt;/a&gt;, machine learning (or &amp;quot;AI&amp;quot; in mainstream media) is time- and resource intensive. This because first of all you need data, which may or may not take up much of your time, because maybe you use an existing dataset. Another is picking an algorithm, where it may not be obvious which one is most suitable for your use case. Then, depending on your intent there is an unknown amount of time taken to train your model (run all the data through the algorithm), evaluate the result, and perhaps try again a bunch of times before you&#39;re happy with the output. As we saw in the &lt;a href=&#34;http://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part2/#discussion&#34;&gt;Part 2 discussion&lt;/a&gt;, this phase can be tricky because outputs may vary enormously depending on the methods used.&lt;/p&gt;
&lt;p&gt;With complicated use cases, like playing video games or generating text, we need huge amounts of data and huge architectures (algorithms). This quickly becomes so expensive that only huge companies are able to afford to train such systems. Take for example the text-generation system GPT-3 developed by OpenAI. It can do some amazing things like &lt;a href=&#34;https://twitter.com/sharifshameem/status/1282676454690451457&#34;&gt;generate code from text&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/zebulgar/status/1283927560435326976&#34;&gt;create novel solutions&lt;/a&gt;. Without going into mathematical details, it&#39;s one of the largest machine learning systems ever released and used what &lt;a href=&#34;https://techxplore.com/news/2020-05-microsoft-openai-world-5th-powerful.html&#34;&gt;one article states&lt;/a&gt; is the fifth most powerful supercomputer in the world, with hundreds of thousands of processors and a cost of at least $1 billion. I&#39;m not sure how much trial and error was needed, probably some, but also much less than I personally would need because these researchers are experts in their field after all.&lt;/p&gt;
&lt;p&gt;If you consider the amount of work we put into getting nice looking pictures for our Planet Ghibli style transfer, and the interaction between input and output; that was fairly time consuming right? And it was time consuming despite us having access to resources in the form of a graphics card. So with time and money becoming prohibitively expensive for individuals or even small organisations; what do you think will be the effect on society if we as regular citizens cannot investigate these systems ourselves? Is it a good thing we have to trust huge companies that they&#39;ve made these systems fair?&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://arxiv.org/abs/2005.14165&#34;&gt;their paper on GPT-3&lt;/a&gt;, the authors do discuss how their language model reflects biases in society, how it can be misused and the energy costs of training versus use when training is done. I want to say they should be lauded for including this, but at the same time such discussions should be the default. Nevertheless, it&#39;s great they have that discussion as it shows they&#39;ve thought about these issues and are (hopefully) open to further discussion about them. What about when the company is not transparent?&lt;/p&gt;
&lt;p&gt;If we have no possibility of investigating for ourselves the interaction between data, algorithms and their combined judgments; how can we trust automated systems that decide who will get jobs, loans, medical treatments and court sentences? The short answer is: we absolutely cannot.&lt;/p&gt;
&lt;h2&gt;Why shouldn&#39;t we trust automated decision making?&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;deep learning: computational depth without historical or sociological depth is superficial learning&amp;quot;&lt;br /&gt; -- Ruha Benjamin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Because these systems are trained on existing data, they can only &lt;a href=&#34;https://medium.com/fair-bytes/how-biased-is-gpt-3-5b2b91f1177&#34;&gt;reinforce existing stereotypes&lt;/a&gt;. For example a system trained on predicting future crime &lt;a href=&#34;https://thenextweb.com/neural/2020/07/31/the-6-unholy-ai-systems-thou-shalt-not-develop/&#34;&gt;is futile&lt;/a&gt;. Since such a system only relies on past data, that past data is usually biased towards police already being more aggressive and making more arrests in poor areas and towards minorities. So a predictive system will continue to predict that rich white people do not commit crime. And I hope you agree with me that black lives matter.&lt;/p&gt;
&lt;p&gt;Compare the just mentioned example of crime prediction to the different outputs we got when doing style transfer in the previous parts of this blog series. We can only change the output by changing the data we use as input, and in some cases entire groups of elephants disappeared from the output. As consumers of a pre-made system, we only see the final output so without insight we will never know what data is being considered and how it&#39;s used.&lt;/p&gt;
&lt;p&gt;Traditionally, if you applied for a bank loan, there was a person you could ask about why you can&#39;t get one. No matter what we may think of an economic system that builds on debt, knowing why you can&#39;t get that loan means you&#39;ll know what to do before trying again. With an opaque black box there is no why. And such systems are increasingly being used for job applications, bank loans and insurance.&lt;/p&gt;
&lt;p&gt;The danger here is that if we do not stop and think, we run the risk of these systems further reinforcing existing biases and stereotypes. Just a few examples are how &lt;a href=&#34;https://www.npr.org/2020/06/24/882683463/the-computer-got-it-wrong-how-facial-recognition-led-to-a-false-arrest-in-michig&#34;&gt;facial recognition can&#39;t distinguish between people of color&lt;/a&gt;, &lt;a href=&#34;https://www.technologyreview.com/2019/04/05/1175/facebook-algorithm-discriminates-ai-bias/&#34;&gt;facebook shows job ads in a discriminatory fashion&lt;/a&gt;, &lt;a href=&#34;https://towardsdatascience.com/towards-trans-inclusive-ai-a4abe9ad4e62&#34;&gt;any system that uses binary gender data is transphobic&lt;/a&gt; and &lt;a href=&#34;https://www.wired.com/story/excerpt-from-automating-inequality/&#34;&gt;prediction of child abuse punishes poor families&lt;/a&gt;. A huge issue here, and incidentally the same reason why self driving cars still don&#39;t work, is that most often these systems can&#39;t reliably catch outliers or handle situations they have never seen before. In other words; minority groups run the risk of disappearing as the data is averaged.&lt;/p&gt;
&lt;h2&gt;Shifting the power&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.nature.com/articles/d41586-020-02003-2&#34;&gt;Pratyusha Kalluri&lt;/a&gt; gives us this insightful thought:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;It is not uncommon now for AI experts to ask whether an AI is ‘fair’ and ‘for good’. But ‘fair’ and ‘good’ are infinitely spacious words that any AI system can be squeezed into. The question to pose is a deeper one: how is AI shifting power?&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In most of the discussed cases, I would like to believe the consequences were not intended by the researchers and engineers. It&#39;s rather a result of software engineering teams not being diverse, existing datasets not being diverse and that software engineers are trained in maths and programming but not in ethics, diversity and societal impact. So this discussion needs to be taken seriously. And what&#39;s more concerning here is that highly influential companies and people in the machine learning world seem to not fully understand this discussion and/or grasp their own role.&lt;/p&gt;
&lt;p&gt;Such as when it was found in 2015 that a Google algorithm &lt;a href=&#34;https://blogs.wsj.com/digits/2015/07/01/google-mistakenly-tags-black-people-as-gorillas-showing-limits-of-algorithms/&#34;&gt;tagged photos of  black people as gorillas&lt;/a&gt;. Two and a half years later, their solution was to &lt;a href=&#34;https://www.wired.com/story/when-it-comes-to-gorillas-google-photos-remains-blind/&#34;&gt;remove gorillas from the possible tags&lt;/a&gt;. With all the data Google/Alphabet has available and the resources to gather, together with their hundreds or even thousands of brilliant employees with PhDs in computer science; was this really the best solution they could find? Or is it a matter of not caring to allocate resources to increase equality?&lt;/p&gt;
&lt;p&gt;Another more recent example is how a system trained to depixelate faces had the effect of &lt;a href=&#34;https://twitter.com/bradpwyble/status/1274380641644294150&#34;&gt;turning Barack Obama into a white man&lt;/a&gt;. Yann Lecun - receiver of the &lt;a href=&#34;https://en.wikipedia.org/wiki/Turing_Award&#34;&gt;Turing award&lt;/a&gt; for his work in deep learning and currently Vice President and Chief AI Scientist at Facebook - &lt;a href=&#34;https://twitter.com/ylecun/status/1274782757907030016&#34;&gt;replied&lt;/a&gt; that this was a consequence of the data set used. Use another data set and the problem goes away. He was &lt;a href=&#34;https://twitter.com/timnitGebru/status/1274809417653866496&#34;&gt;criticised by Timnit Gebru&lt;/a&gt; for this statement being overly simplified because the problem is bigger than that; it&#39;s about why this sort of thing keeps happening and why did the authors not even think of trying their system with a diverse set of skin colours? Lecun refused to see the bigger picture and kept defending his position from a technical view. He later &lt;a href=&#34;https://twitter.com/ylecun/status/1277373793443463168?s=21&#34;&gt;quit Twitter&lt;/a&gt; and posted a long statement on facebook about his personal values of freedom and justice.&lt;/p&gt;
&lt;p&gt;To connect this drama to our experimentation with style transfer, it&#39;s a little like if we had stopped testing with the Princess Mononoke input picture and concluded that we would get a different result with a different input picture. It&#39;s technically correct, but fails to consider what our purpose is and how our methods of data collection and algorithm selection feeds into that purpose.&lt;/p&gt;
&lt;p&gt;Furthermore, unless you&#39;re a researcher it may be difficult to evaluate if the algorithm works for the dataset you&#39;re using. Perhaps the data you have would need algorithmic tweaks that the researchers never thought of testing for. But developers use off-the-shelf algorithms all the time, they don&#39;t have the knowledge and/or time to make their own.&lt;/p&gt;
&lt;p&gt;The authors of the &lt;a href=&#34;https://arxiv.org/abs/2003.03808&#34;&gt;paper in question&lt;/a&gt; have since added a section about biases, and some would perhaps criticise them for doing that only after discussion happened. But to be fair, that&#39;s how science should work; issues are pointed out and through discussion we move forward. This is where Lecun&#39;s answer becomes problematic in my view. He&#39;s technically correct about the data set being an issue, and you and I can see how he&#39;s correct about that, using our our style transfer as a visual simile. But Lecun seems incapable of looking beyond mathematics, defending his statement instead of being curious, and feeling so hurt for being called out that he completely quits Twitter. When the head of AI for Facebook cannot handle a discussion about issues of bias in AI/ML and saying it&#39;s only about data, it&#39;s obvious he doesn&#39;t understand the larger issue. Not to mention it says something about the company culture within Facebook.&lt;/p&gt;
&lt;p&gt;The sad consequence for everyone is that the outlook of using AI to shift power - to empower the disadvantaged - instead of reinforcing existing inequalities, is so much bleaker when the world&#39;s most influential companies act indifferent.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Most people are forced to live inside someone else&#39;s imagination&amp;quot;&lt;br /&gt; -- Ruha Benjamin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;So what can we do?&lt;/h2&gt;
&lt;p&gt;As software developers, ML/AI practitioners and data scientists, it&#39;s essential to gain a broader perspective than mathematical formulas. We have to be able to put the artefacts we create into a broader sociological and historical context. So learning more about those contexts is one action. Another action is to hire diverse teams. Not just diverse based on race or gender but also of perspective. Hire historians and sociologists. It doesn&#39;t matter they won&#39;t understand the details of your algorithms, you can explain the concepts so they can be valuable contributors anyway. And if you happen to not be great at explaining things, hire someone who can! A good educator can also help you be transparent by explaining to your customers how your product works.&lt;/p&gt;
&lt;p&gt;As citizens of the world, we have an obligation to not accept the status quo. Human rights is not a done deal, we have to keep pushing for better transparency, inclusiveness and justice. For ourselves, for our fellow humans, for the life we share this planet with and for Mother Earth herself. A very important part of that is to listen. Listen to the people saying they are mistreated. Understand where they are coming from. Only then can we understand how our own actions may impact the greater picture of systemic inequalities.&lt;/p&gt;
&lt;p&gt;My own understanding of these issues is only superficial at this point. Thanks to &lt;a href=&#34;https://blacklivesmatter.com&#34;&gt;#BLM&lt;/a&gt;, &lt;a href=&#34;https://rebellion.global&#34;&gt;XR&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/PennyRed&#34;&gt;Laurie Penny&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/timnitGebru/status/1274856360300044288&#34;&gt;Timnit Gebru&#39;s recommendations&lt;/a&gt; and many others I&#39;ve started to see how many different kinds of inequality are connected. But my to-read list&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt; is still way longer than my already-read-list and there&#39;s much I do not know.&lt;/p&gt;
&lt;p&gt;Among the amazing people I&#39;ve found there&#39;s one person in particular I want to promote. &lt;a href=&#34;https://www.ruhabenjamin.com&#34;&gt;Ruha Benjamin&lt;/a&gt; gave a &lt;a href=&#34;https://iclr.cc/virtual_2020/speaker_3.html&#34;&gt;brilliant keynote&lt;/a&gt; at ICLR this summer. I really, really, really recommend you watch her keynote. And the Q&amp;amp;A.&lt;/p&gt;
&lt;p&gt;So I will end this &lt;s&gt;rant&lt;/s&gt; essay with yet another quote from Benjamin, one I find particularly inspiring:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Remember to imagine and craft the worlds you cannot live without, just as you dismantle the ones you cannot live within.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;This list is obviously non-exhaustive:&lt;br /&gt;&lt;a href=&#34;https://www.angelasaini.co.uk/superior&#34;&gt;Angela Saini - Superior&lt;/a&gt;&lt;br /&gt;&lt;a href=&#34;https://mathbabe.org&#34;&gt;Cathy O&#39;Neil - Weapons of Math Destruction&lt;/a&gt;&lt;br /&gt;&lt;a href=&#34;https://www.ruhabenjamin.com/race-after-technology&#34;&gt;Ruha Benjamin - Race After Technology&lt;/a&gt;&lt;br /&gt;&lt;a href=&#34;https://safiyaunoble.com&#34;&gt;Safiya Umoja Noble - Algorithms of Oppression&lt;/a&gt;&lt;br /&gt;&lt;a href=&#34;https://virginia-eubanks.com&#34;&gt;Virginia Eubanks - Automating Inequality&lt;/a&gt;&lt;br /&gt;&lt;a href=&#34;https://shoshanazuboff.com/book/about/&#34;&gt;Shoshanna Zuboff - The Age of Surveillance Capitalism&lt;/a&gt; &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Fri, 14 Aug 2020 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/</link>
          <guid isPermaLink="true">https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/</guid>
          
          <category>planet earth</category>
          
          <category>studio ghibli</category>
          
          <category>neural style transfer</category>
          
          <category>neural networks</category>
          
          <category>machine learning</category>
          
          <category>human rights</category>
          
          <category>ethics</category>
          
          <category>inequality</category>
          
          <category>ai</category>
          
          <category>artificial intelligence</category>
          
          
          <category>tutorials</category>
          
          <category>essays</category>
          
        </item>
      
    
      
        <item>
          
            <title>Planet Ghibli Part 2 - Making a Video</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Welcome to the second part of our Planet Ghibli adventure. In the &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/&#34;&gt;first part&lt;/a&gt;, we styled single images and now we shall attempt to style an entire video. The video we will style is &lt;a href=&#34;https://www.youtube.com/watch?v=c8aFcHFu8QM&#34;&gt;this trailer for Planet Earth II&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So how do we do this? Well, the simple and straight forward answer is; we extract all the frames from the video and do the style transfer on each frame.&lt;/p&gt;
&lt;h3&gt;Quick links for this post (a.k.a. TLDR)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/fohria/fast_neural_style&#34;&gt;Code repository&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://vimeo.com/429736102&#34;&gt;Final result: Styled Trailer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;#discussion&#34;&gt;Discussion&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Before we move on&lt;/h3&gt;
&lt;p&gt;Remember from &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/&#34;&gt;Part 1&lt;/a&gt; it took us 1-2 minutes for &lt;em&gt;each image&lt;/em&gt;? The trailer is 2 minutes and 46 seconds long, so if we have 24 frames every second... Yeah. That&#39;s almost 4000 images, and thusly around 3 days. For 128 pixel resolution images.&lt;/p&gt;
&lt;p&gt;Time to go look for more efficient approaches! One of the fanciest is using something like &lt;a href=&#34;https://github.com/junyanz/CycleGAN&#34;&gt;CycleGAN&lt;/a&gt;. But from what I understand looking into it, the computational requirements are high. What might work better is &lt;a href=&#34;https://github.com/pytorch/examples/tree/master/fast_neural_style&#34;&gt;fast neural style transfer&lt;/a&gt; (&lt;a href=&#34;https://arxiv.org/pdf/1603.08155.pdf&#34;&gt;original paper&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This only takes a few seconds per image, &lt;em&gt;if&lt;/em&gt; we have a trained model. So what does it mean to have a trained model?&lt;/p&gt;
&lt;h2&gt;Training models briefly explained&lt;/h2&gt;
&lt;p&gt;In part 1, our pytorch code used a pre-trained object recognition network to calculate values for images. Someone had already gone through the process of &amp;quot;teaching&amp;quot; this network to recognise objects in images, by &amp;quot;showing&amp;quot; it thousands and thousands of images and pointing out where the objects are&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. By exploiting aspects of this pre-trained object recognition network, we could run our style and input images through it, calculate difference values, and manipulate an output image so that it became a mix between the style and input.&lt;/p&gt;
&lt;p&gt;The fast neural transfer also uses a pre-trained object recognition network, but additionally, it trains a &amp;quot;image transformation network&amp;quot; (see Figure 2 in &lt;a href=&#34;https://arxiv.org/pdf/1603.08155.pdf&#34;&gt;the paper&lt;/a&gt; for a nice overview). By running many images through this system, this image transformation network learns to output a styled image without having to calculate any differences between the style, input and output. It just changes the input image into an output image directly.&lt;/p&gt;
&lt;p&gt;In other words, we could say that when we train our fast neural transfer, it&#39;s similar to what happens in part 1, but instead of treating each successive image as a new and separate case, the image transformation network will first learn how to style the first image, then it learns how to style the first and second image, then the first, second and third... you get the picture. Hah! Picture. Pun not intended, but pun happened.&lt;/p&gt;
&lt;p&gt;The downside here is we need thousands of images to train on. So it will take some time to do this training for our chosen style image, but when it&#39;s done, each frame of our video will only take seconds. So in a way, we&#39;re betting here that the training will take less time than the 3 days or so we estimate to use the method from part 1 to style the entire video.&lt;/p&gt;
&lt;p&gt;I should mention that when I make this bet, I take into consideration that I&#39;ve access to a GTX980Ti graphics card at university. It accelerates training significantly compared to my laptop, on which this kind of deep learning is basically pointless. We will discuss this at the end of this post.&lt;/p&gt;
&lt;h2&gt;Actually training our model(s)&lt;/h2&gt;
&lt;p&gt;I cloned the git repo mentioned earlier for &lt;a href=&#34;https://github.com/pytorch/examples/tree/master/fast_neural_style&#34;&gt;fast neural style&lt;/a&gt;, and used their instructions to train a model using the same style image we used in Part 1. I used the image of Sir David and our custom Planet Ghibli &amp;quot;logo&amp;quot; as test images, as seen here:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/nausicaa.jpg&#34;&gt;&lt;img src=&#34;/img/nausicaa.jpg&#34; alt=&#34;landscape from Nausicaa Valley of the Wind&#34; style=&#34;max-width:33%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/planetghibli_sirdavid_org.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_sirdavid_org.jpg&#34; alt=&#34;sir david and a meerkat&#34; style=&#34;max-width:33%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/planetghibli_scene_org.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_scene_org.jpg&#34; alt=&#34;aerial scene from planet earth&#34; style=&#34;max-width:33%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Style image to the far left and our test images to be styled. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;One training run on the COCO2014 image dataset (the one recommended in their readme), took around 3h using a GTX980Ti for CUDA acceleration. Good thing I&#39;ve access to such a card at the university, or it would likely not have been worth it compared to those 3 days we spoke of in the beginning of this post. Deep learning without GPU acceleration, like on my laptop (and most other non gaming laptops), is basically impossible unless it&#39;s for small toy examples&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn2&#34; id=&#34;fnref2&#34;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The first training run used the default parameter settings for &lt;code&gt;content-weight&lt;/code&gt; and &lt;code&gt;style-weight&lt;/code&gt;; &lt;code&gt;1e5&lt;/code&gt; and &lt;code&gt;1e10&lt;/code&gt;, respectively, and gives us these results:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/pg2_david_model_default.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_david_model_default.jpg&#34; alt=&#34;sir david styled with default parameter values&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/pg2_logo_model_default.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_logo_model_default.jpg&#34; alt=&#34;planet earth scene styled with default parameter values&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Images styled with style-weight=1e10. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;These look okay, but to my eyes more like color and blur filters or something than actual style. They don&#39;t look &amp;quot;painting-like&amp;quot; if you get what I mean? Let&#39;s try using &lt;code&gt;style-weight=1e11&lt;/code&gt; instead!&lt;/p&gt;
&lt;p&gt;Wait, wait; I hear you. What is this style weight business? Again referring back to &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/&#34;&gt;Part 1&lt;/a&gt;, the style weight tells the training algorithm to give more weight to the style than the content. By adjusting both the &lt;code&gt;style-weight&lt;/code&gt; and &lt;code&gt;content-weight&lt;/code&gt; parameters we can fine tune the look of our output images. How do we find good values, you ask? Well, my friend, that&#39;s the secret about these things. You have to test and retest. Luckily for us, the readme tells us their example images have used values between &lt;code&gt;1e10&lt;/code&gt; and &lt;code&gt;1e11&lt;/code&gt; for the style weight.&lt;/p&gt;
&lt;p&gt;So! &lt;a href=&#34;https://xkcd.com/303/&#34;&gt;Another three hours go by&lt;/a&gt; and we have a new model to test with our images:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/pg2_david_model_11.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_david_model_11.jpg&#34; alt=&#34;sir david styled with parameter values up to eleven&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/pg2_logo_model_11.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_logo_model_11.jpg&#34; alt=&#34;planet earth scene styled with parameter values up to eleven&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Images styled with style-weight=1e11. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Notice those red stripes on Sir David&#39;s shirt? And in the water in the bottom right of the elephant shot? You recognise it? If not, scroll back up to the style image from Nausicaa that we use. Then continue to the next paragraph.&lt;/p&gt;
&lt;p&gt;You&#39;re right, those &lt;em&gt;are&lt;/em&gt; the windmill sails! How did they get there? Mayhaps you figured it out already, but remember we just spoke of what style weight does? By increasing the weight - the importance - of the style image over the content images during training, more of the style &amp;quot;seeps through&amp;quot;. In our case, it seems that during training, one of the features identified by the object recognition network, was these sails. Again, looking at the Nausicaa image, those sails do stand out from the rest of the picture so it&#39;s not surprising it&#39;s a stand out feature.&lt;/p&gt;
&lt;p&gt;Either way, this isn&#39;t what we want right? Sure, both the test images now look more &amp;quot;painted&amp;quot; but we don&#39;t want those sails. Let&#39;s try using &lt;code&gt;style-weight=5e10&lt;/code&gt;, a value in-between the first and second attempts. Another three hours of training and now we get this:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/pg2_david_model_510.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_david_model_510.jpg&#34; alt=&#34;sir david styled with parameter values in-between&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/pg2_logo_model_510.jpg&#34;&gt;&lt;img src=&#34;/img/pg2_logo_model_510.jpg&#34; alt=&#34;planet earth scene styled with parameter values in-between&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Images styled with style-weight=5e10. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;These aren&#39;t too bad! To be honest I slightly prefer the results of the method in &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/&#34;&gt;Part 1&lt;/a&gt;, but these are good enough. We have already spent nine hours training, plus a few extra hours fiddling around with the code.&lt;/p&gt;
&lt;h2&gt;Extracting frames and running the style transfer&lt;/h2&gt;
&lt;p&gt;I downloaded the trailer using &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;youtube-dl&lt;/a&gt;, which if you didn&#39;t know can be used to download video clips from twitter, reddit and other sites as well. Very useful when you want to save those cute animal gifs for future use.&lt;/p&gt;
&lt;p&gt;Next step is to use another wonderfully useful little application; &lt;a href=&#34;https://ffmpeg.org&#34;&gt;ffmpeg&lt;/a&gt;&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn3&#34; id=&#34;fnref3&#34;&gt;[3]&lt;/a&gt;&lt;/sup&gt;. It can convert between video formats quickly and do many other nifty things with video and audio. For our use case, it can extract all the frames from our trailer into individual jpg files at 24 frames per second:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;ffmpeg &lt;span class=&#34;token parameter variable&#34;&gt;-i&lt;/span&gt; input.mp4 &lt;span class=&#34;token parameter variable&#34;&gt;-r&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;24&lt;/span&gt;/1 out%03d.jpg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we extract the audio:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;ffmpeg &lt;span class=&#34;token parameter variable&#34;&gt;-i&lt;/span&gt; input.mp4 &lt;span class=&#34;token parameter variable&#34;&gt;-q:a&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-map&lt;/span&gt; a audio.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we get out is almost 4000 images (!), and it&#39;s impressive, at least to me, that this process only takes a few minutes even on my crappy laptop.&lt;/p&gt;
&lt;h3&gt;Style transfer&lt;/h3&gt;
&lt;p&gt;Even though the fast style transfer is much quicker than the original one, each image still takes up to 10 seconds on my laptop. That would be 11h for 4000 images. So again, I use the office graphics card, which takes only 12 minutes in total. That&#39;s because our image dataset easily fits into the memory of the graphics card, and pytorch intelligently identifies this and transfers all the images to the graphics memory, converts them, and then sends the images back to the CPU and saves to disk.&lt;/p&gt;
&lt;p&gt;Also, the code we&#39;re using has no support to do many images in batch, so I created a wrapper file, which I uploaded to my forked repository &lt;a href=&#34;https://github.com/fohria/fast_neural_style&#34;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Putting the pieces back together&lt;/h3&gt;
&lt;p&gt;With all the images styled and downloaded to my laptop, we use ffmpeg to put the pieces back together:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;ffmpeg &lt;span class=&#34;token parameter variable&#34;&gt;-r&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-i&lt;/span&gt; out%03d.jpg &lt;span class=&#34;token parameter variable&#34;&gt;-i&lt;/span&gt; audio.mp4 &lt;span class=&#34;token parameter variable&#34;&gt;-c:v&lt;/span&gt; libx264 &lt;span class=&#34;token parameter variable&#34;&gt;-c:a&lt;/span&gt; mp3 &lt;span class=&#34;token parameter variable&#34;&gt;-r&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-shortest&lt;/span&gt; output.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command assumes you have not changed the filenames from the extracted ones :)&lt;/p&gt;
&lt;p&gt;The final result can be seen &lt;a href=&#34;https://vimeo.com/429736102&#34;&gt;on Vimeo&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Discussion&lt;/h2&gt;
&lt;p&gt;If you check out the vimeo video, you&#39;ll see that some scenes don&#39;t look that great. Others look really cool! So like in the previous post, we see this interaction between input and output where we can&#39;t be sure of how things turn out until we try it.&lt;/p&gt;
&lt;p&gt;When we trained our model we used an existing dataset of thousands of images, training our image transformation network to output styled images in a way that&#39;s an average of all those thousands of pictures. So it could be the case we would get better results if we either trained on extracted images from the trailer. Another way to improve the result would be to have separate transformation networks for different parts of the trailer. For example, if there are lots of details in the image, like in an aerial shot of a horde of animals or a forest scene with many leaves and branches; that would be one category or model variant. Another variant could be when there&#39;s a close up shot of an animal. We could also go back to the image used for styling, perhaps another kind of image would work better for some scenes?&lt;/p&gt;
&lt;p&gt;Since I don&#39;t have much experience with style transfer, I cannot say what approach would be best or has the highest chance of producing better results. Perhaps it would be a waste of time to try any of the suggestions I gave, because we actually should look at another neural network architecture or maybe we just can&#39;t get noticeably better results.&lt;/p&gt;
&lt;p&gt;What (hopefully) does become obvious here is that machine learning involves lots of trial and error. As mentioned above, it took three hours to train the style model on a 980Ti GPU. Its launch price in 2015 was $649, but can still be found on ebay for £100-200. This graphics card needs 250w, excluding the energy needs of the rest of the system. So there&#39;s a decent amount of energy use here, especially adding that we had to train for 3x3h to find a good parameter setting.&lt;/p&gt;
&lt;p&gt;There are analyses of compute cost (&lt;a href=&#34;https://openai.com/blog/ai-and-compute/&#34;&gt;open ai&lt;/a&gt;) and/or energy and cash cost (&lt;a href=&#34;https://www.yuzeh.com/data/agz-cost.html&#34;&gt;yuzeh&lt;/a&gt;) of machine learning, but they only take the final training cost into consideration. What I mean is, if they would talk about my simple experiment here they would use the 3h number to calculate compute, energy and money cost&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn4&#34; id=&#34;fnref4&#34;&gt;[4]&lt;/a&gt;&lt;/sup&gt;. Even if they take all self-play matches of AlphaZero into consideration, they don&#39;t consider all the testing it took to find the parameter values they would use for all those self-play matches!&lt;/p&gt;
&lt;p&gt;But wait, there&#39;s more! We have only mentioned the trial and error procedure to find the right parameters &lt;em&gt;when we have the right architecture&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What about coming up with the architecture in the first place? It&#39;s not easy, and is a combination of experience and exploration. I honestly don&#39;t know how much you can predict mathematically about the performance and output effects of different architectures, as that&#39;s not my research area. I do know that it&#39;s a very active field of research though, because we simply don&#39;t know enough about how neural networks function, leading to for example the &lt;a href=&#34;https://www.technologyreview.com/2019/05/10/135426/a-new-way-to-build-tiny-neural-networks-could-create-powerful-ai-on-your-phone/&#34;&gt;&amp;quot;lottery ticket hypothesis&amp;quot;&lt;/a&gt; about using bigger neural networks. In short, it means there&#39;s trial and error in finding a good architecture as well.&lt;/p&gt;
&lt;p&gt;It&#39;s uncommon these efforts are mentioned in papers presenting results, or even in discussions such as those referenced above about compute cost, which is unfortunate. It can give the impression that machine learning, especially using neural networks, is easier than it actually is. The resource costs to get into this kind of research are enormous, and even if you had lots of money, you would need expertise and experience to not waste those resources.&lt;/p&gt;
&lt;p&gt;If we look at deep reinforcement learning research (deep RL) for example, this becomes even more apparent. In deep RL research, the most common task is to get machine learning systems to play video games. In a rare example of transparency (though still glossed over), the &lt;a href=&#34;https://arxiv.org/abs/1708.04782&#34;&gt;paper presenting pysc2&lt;/a&gt; - a python framework to play Starcraft 2 - has a few graphs like this:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/pg2_sc2.png&#34;&gt;&lt;img src=&#34;/img/pg2_sc2.png&#34; alt=&#34;graph showing training results for an agent playing starcraft 2&#34; style=&#34;max-width:70%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Graph from &lt;a href=&#34;https://arxiv.org/pdf/1708.04782.pdf&#34;&gt;pys2c paper&lt;/a&gt; showing score on the vertical axis and time steps on horisontal axis. The different colours represent different architectures for the neural net.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;It doesn&#39;t really matter what the task is that this graph represents, it could be any task. Each colour is a different neural network architecture, and the bold lines are the best results for each architecture. The faint lines are what I want to point out. These faint lines grey lines are using the same architecture as the winning thick grey line, but uses different hyperparameters. Meaning, parameters such as the style weight and content weight we had to trial and error for the style transfers.&lt;/p&gt;
&lt;p&gt;So, not only did they run 100 experiments &lt;em&gt;for each architecture&lt;/em&gt;. If we read this graph right, it looks like only &lt;strong&gt;two&lt;/strong&gt; of those 100 experiments for the winning grey architecture rose high above the others. And you would not even know that until after around 200 &lt;strong&gt;million&lt;/strong&gt; time steps. Additionally, if we look at averages across all the lines of each colour, doesn&#39;t it look like the orange architecture is better overall? If so, the researchers have actually chosen &lt;em&gt;outliers&lt;/em&gt; as their presented result!&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn5&#34; id=&#34;fnref5&#34;&gt;[5]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Are you starting to grasp the enormous amount of work put into something that &lt;em&gt;works?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s no wonder Deepmind and OpenAI have hundreds of top-of-the-line PhD graduates for research and millions of dollars in backing to fund the computational resources they require. Looking at recent advances in text generation, specifically &lt;a href=&#34;https://openai.com/blog/openai-api/&#34;&gt;GPT-3&lt;/a&gt;, it&#39;s an enormous computational achievement that&#39;s only feasible for large and well funded organisations.&lt;/p&gt;
&lt;h2&gt;Conclusions and up next&lt;/h2&gt;
&lt;p&gt;To conclude, machine learning and deep learning in particular are expensive activities. One could question if it&#39;s worth the climate costs. And what are the societal costs and effects when only huge companies can train these systems?&lt;/p&gt;
&lt;p&gt;In the next post we shall touch on those questions. We will also discuss the input/output relationship we have seen both here and in part 1; how we need to test and evaluate output depending on the input. If we are not careful, we can cause real issues in society so it&#39;s important to discuss the implications of magic input-output boxes.&lt;/p&gt;
&lt;p&gt;Edit: Now available at a server near you: &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/&#34;&gt;Part 3&lt;/a&gt;&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;Of course, this is a highly simplified description of what happens, see &lt;a href=&#34;https://en.wikipedia.org/wiki/Object_detection&#34;&gt;Wikipedia&#39;s object detection&lt;/a&gt; for an overview and more links. &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn2&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;There are services like &lt;a href=&#34;https://colab.research.google.com&#34;&gt;Google Colab&lt;/a&gt;, but unless you pay there are limits on the size of your models and how long you can use it. Also you should consider if you&#39;re comfortable letting Google access your dataset. &lt;a href=&#34;#fnref2&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn3&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;Thanks to &lt;a href=&#34;https://twitter.com/rob_homewood&#34;&gt;@rob_homewood&lt;/a&gt; for sending me ready to use command line snippets, it likely saved me at least an hour of reading to find out the correct combinations :) &lt;a href=&#34;#fnref3&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn4&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;And I only knew the range of parameter values that were worth testing because the &lt;a href=&#34;https://github.com/pytorch/examples/tree/master/fast_neural_style&#34;&gt;readme on github&lt;/a&gt; specifically mentioned the range of values they used! &lt;a href=&#34;#fnref4&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn5&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;This could be seen as a biased presentation of results, but I don&#39;t have their data available so I cannot say for sure and it is difficult to distinguish the colours in the graph. The paper is not peer-reviewed so this is one thing reviewers hopefully would catch. &lt;a href=&#34;#fnref5&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Fri, 31 Jul 2020 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part2/</link>
          <guid isPermaLink="true">https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part2/</guid>
          
          <category>planet earth</category>
          
          <category>studio ghibli</category>
          
          <category>neural style transfer</category>
          
          <category>neural networks</category>
          
          
          <category>tutorials</category>
          
        </item>
      
    
      
        <item>
          
            <title>Planet Ghibli Part 1 - Setup and Play</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Ever since I first saw the examples of &lt;a href=&#34;https://duckduckgo.com/?q=neural+style+transfer&amp;amp;iax=images&amp;amp;ia=images#&#34;&gt;neural style transfer&lt;/a&gt; back in 2015 or 2016 I wanted to see what &lt;a href=&#34;https://en.wikipedia.org/wiki/Planet_Earth_(2006_TV_series)&#34;&gt;Planet Earth&lt;/a&gt; would look like in the style of &lt;a href=&#34;https://en.wikipedia.org/wiki/Studio_Ghibli&#34;&gt;Studio Ghibli&lt;/a&gt;. Since I&#39;m a &lt;s&gt;lazy&lt;/s&gt; busy person, I&#39;ve eagerly awaited someone doing this for me. Alas, here we are several years later and no such thing has come to pass. Humankind, you have failed me.&lt;/p&gt;
&lt;p&gt;Good news everyone! I decided to take a crack at it myself. And at this point style transfer has become such a standard example that it&#39;s easy to find code for exactly what we want. However, while doing this I also realised this is a great visual example of how machine learning works in practice; why it&#39;s so heavily dependent on what data you use and what parameters you set, how it&#39;s about trial and error and waiting for training to complete, and therefore why it&#39;s often about &lt;s&gt;black magic&lt;/s&gt; experience and how much resources you have, can buy, and is willing to sacrifice the environment to use.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/planetghibli.jpeg&#34;&gt;&lt;img src=&#34;/img/planetghibli.jpeg&#34; alt=&#34;Planet Ghibli - BBC&#39;s Planet Earth in the style of Studio Ghibli&#39;s Nausicaa Valley of the Wind&#34;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;I will not be going into much detail about the algorithm or the code, as I based this on the &lt;a href=&#34;https://pytorch.org/tutorials/advanced/neural_style_tutorial.html&#34;&gt;excellent tutorial for Pytorch&lt;/a&gt; where they explain the algorithm as they go along. Their conceptual overview is nicely complemented by the &lt;a href=&#34;https://en.wikipedia.org/wiki/Neural_Style_Transfer#Formulation&#34;&gt;wikipedia page on neural style transfer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, I have provided a &amp;quot;cleaned up&amp;quot; version of their code &lt;a href=&#34;https://github.com/fohria/styletransfer&#34;&gt;on GitHub&lt;/a&gt; where it&#39;s easy for you to replace the filenames with your own images. This can be useful if you just want to test things without having to understand much of the code or going through the tutorial I linked to.&lt;/p&gt;
&lt;p&gt;What I will be discussing and showing more than code is the process; how what images you select impact what comes out the other end. The trial and error process of machine learning.&lt;/p&gt;
&lt;h2&gt;Very brief explanation of style transfer that is likely to annoy people fluent in mathematical details&lt;/h2&gt;
&lt;p&gt;Let&#39;s say we have three images, the &lt;code&gt;style&lt;/code&gt; (say, picasso) the &lt;code&gt;input&lt;/code&gt; (for example a photo you have) and the &lt;code&gt;output&lt;/code&gt; (the resulting combination of your style and input images). Style transfer as presented here involves using pre trained object recognition networks (VGG16 and &lt;a href=&#34;https://microscope.openai.com&#34;&gt;VGG19&lt;/a&gt;) to calculate &#39;values&#39; for the content and style for the &lt;code&gt;output&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt; and &lt;code&gt;input&lt;/code&gt; images respectively. When I say &amp;quot;content&amp;quot; and &amp;quot;style&amp;quot; here without writing them like &lt;code&gt;this&lt;/code&gt; I mean the &amp;quot;conceptual&amp;quot; aspects of our images. Maybe your photo is you in a silly hat. That&#39;s the &amp;quot;conceptual content&amp;quot; so to speak. The &amp;quot;style&amp;quot; of the photo is, well, a photo, so it looks like &amp;quot;reality&amp;quot; (whatever that is). Whereas our &lt;code&gt;style&lt;/code&gt; image is a painting so regardless of what the painting supposedly depicts, it&#39;s a painting and not a photo. Get it? Great!&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;So the algorithm can exploit the fact that object recognition neural networks have many layers and depending on what layer we decide to look at we can extract and manipulate the &amp;quot;content&amp;quot; and &amp;quot;style&amp;quot; separately.&lt;/p&gt;
&lt;p&gt;So, say we start out having the &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;input&lt;/code&gt; images being the same; your photo. We calculate a &amp;quot;distance&amp;quot; between the &lt;em&gt;content&lt;/em&gt; of &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;input&lt;/code&gt; which of course here start out being &lt;code&gt;0&lt;/code&gt;. Let&#39;s call that &lt;code&gt;C&lt;/code&gt;. We then calculate the distance between the &lt;em&gt;style&lt;/em&gt; of &lt;code&gt;output&lt;/code&gt; and &lt;code&gt;style&lt;/code&gt;, let&#39;s call this &lt;code&gt;S&lt;/code&gt;. Here&#39;s the magic: the algorithm now tries to minimize &lt;code&gt;S&lt;/code&gt; while keeping &lt;code&gt;C&lt;/code&gt; as low as possible. So the pixels of your photo are slowly being manipulated so that it&#39;s still you in a silly hat but it will look more and more like a picasso painting.&lt;/p&gt;
&lt;h2&gt;Let&#39;s get this stylin&#39; goin&#39;&lt;/h2&gt;
&lt;p&gt;Assuming you have downloaded &lt;a href=&#34;https://github.com/fohria/styletransfer&#34;&gt;my code&lt;/a&gt;, the main part starts at or around line 230. We load a style image, and define a directory where we have a bunch of input images.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; __name__ &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#39;__main__&#39;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;

    style_img &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; image_loader&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;style/yourstyle.jpg&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;

    input_dir &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; Path&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#39;./input_images&#39;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Put just one image in the folder the first time, so you know how long one image takes to style. On my crappy old dual core i5 laptop it&#39;s around 2 minutes for 128 pixel resolution. Some of the larger resolution images in this post have 456 pixel resolution which took around 35 minutes on the same laptop. With a graphics card that supports CUDA it&#39;ll be much faster. To change the resolution used, check around line 22 in the code and set the resolution depending on if you have CUDA available or not:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;imsize &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;720&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; torch&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;cuda&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;is_available&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;128&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, say we have the following image we want to style (i.e. put this image in the input directory defined in the code):&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/planetearth.jpg&#34;&gt;&lt;img src=&#34;/img/planetearth.jpg&#34; alt=&#34;Planet Earth III title screen&#34;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;But what style image to use? Here we bump into the first issue. It turns out you can&#39;t just use whatever image you want as the style. I mean you can, but it won&#39;t look any good. It has to be carefully selected.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;https://gamescapad.es/why-you-should-use-duckduckgo/&#34;&gt;duckduckgo&lt;/a&gt;&#39;d for images to use and most are stills of characters. Which makes sense, you know, because there are characters in these films. Anyway. Princess Mononoke is cool, let&#39;s use a shot of her for the style. Here&#39;s what happens when used to style the above shown :&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/mononoke.jpg&#34;&gt;&lt;img src=&#34;/img/mononoke.jpg&#34; alt=&#34;Princess Mononoke&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/pe_mononoke.jpg&#34;&gt;&lt;img src=&#34;/img/pe_mononoke.jpg&#34; alt=&#34;Planet Earth III title screen styled with Princess Mononoke&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;&#34;Style&#34; image to the left, &#34;output&#34; image to the right. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Okay, so it&#39;s not that this isn&#39;t kinda cool. The bottom right looks good, the main features of the content are kept and has been stylised. But the upper left has lost most of its features, i.e. its elephants can&#39;t really be seen anymore as they&#39;ve all been taken up by the whiteness of the wolf from the style image. What seems to happen is some of the content of the image that we use as style is slipping through.&lt;/p&gt;
&lt;p&gt;What happens if we instead find a style image that has fewer features of its own, like a landscape image? This turns out to work much better:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/nausicaa.jpg&#34;&gt;&lt;img src=&#34;/img/nausicaa.jpg&#34; alt=&#34;Landscape shot from Nausicaa Valley of the Wind&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/pe_nausicaa.jpg&#34;&gt;&lt;img src=&#34;/img/pe_nausicaa.jpg&#34; alt=&#34;Planet Earth III title screen styled with Nausicaa Valley of the Wind&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;&#34;Style&#34; image to the left, &#34;output&#34; image to the right. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now we get a result where the content is better preserved, we can distinguish each elephant in the upper left of the picture which we couldn&#39;t in the previous example. The style image from Nausicaa Valley of the Wind happens to have similar colors, which also helps. But importantly: it&#39;s the exact same code! There&#39;s a reason the tutorials for style transfer use paintings that are fairly uniform and distinct in style: they produce much nicer results. But the tutorials rarely mention this, from what I&#39;ve seen, so I bet there are people out there wondering why it doesn&#39;t look as nice when they try using their own images. There&#39;s nothing wrong with your code, it&#39;s just that the algorithm isn&#39;t as magical as it may seem! :)&lt;/p&gt;
&lt;p&gt;Now that we&#39;ve found a style image that works we can try on a few more examples to see if it works for them as well.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/planetghibli_scene_org.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_scene_org.jpg&#34; alt=&#34;aerial scene from planet earth of a horde of animals&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/planetghibli_scene.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_scene.jpg&#34; alt=&#34;planet ghibli version of the aerial scene from planet earth&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Original image to the left, styled image to the right. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Looks pretty cool! Let&#39;s do another one:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;div style=&#34;display:flex;justify-content:space-evenly;&#34;&gt;
  &lt;a href=&#34;/img/planetghibli_sirdavid_org.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_sirdavid_org.jpg&#34; alt=&#34;sir david and a meerkat&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;a href=&#34;/img/planetghibli_sirdavid.jpg&#34;&gt;&lt;img src=&#34;/img/planetghibli_sirdavid.jpg&#34; alt=&#34;planet ghibli version of sir david and a meerkat&#34; style=&#34;max-width:50%;height:auto;&#34;&gt;&lt;/a&gt;
  &lt;/div&gt;
  &lt;p&gt;Original image to the left, styled image to the right. Click for larger versions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Sir David has never looked better!&lt;/p&gt;
&lt;p&gt;To summarize, we see it&#39;s important what data you have and how you use it, the algorithm is only part of the story. I should also mention that sometimes the result is pretty different in 128 pixel resolution compared to higher resolutions. So you have to spend time waiting for styling to happen in order to explore results. Machine learning is thus costly in time, money and energy use, since you have to wait around even if you have bought fancy graphics cards and fast processors. We will see more examples of this in the next part, where we style an entire video; a Planet Earth trailer.&lt;/p&gt;
&lt;p&gt;Until then, go forth and style!&lt;/p&gt;
&lt;p&gt;Edit: Now available at a server near you: &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part2/&#34;&gt;Part 2&lt;/a&gt; and &lt;a href=&#34;https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part3/&#34;&gt;Part 3&lt;/a&gt;&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;Please ignore paintings in realistic style to make this example work &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Sat, 04 Jul 2020 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/</link>
          <guid isPermaLink="true">https://gamescapad.es/planet-ghibli-neural-style-transfer-planet-earth-studio-ghibli-part1/</guid>
          
          <category>planet earth</category>
          
          <category>studio ghibli</category>
          
          <category>neural style transfer</category>
          
          <category>neural networks</category>
          
          
          <category>tutorials</category>
          
        </item>
      
    
      
        <item>
          
            <title>Access apps like Jupyter notebook remotely using SSH tunnels</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Hello there. I hope you and your loved ones are safe in these disturbing times.&lt;/p&gt;
&lt;p&gt;I&#39;ve been working from home since early March now. Currently this work mostly involves writing Python code for simulations and modelling of data. My laptop is fine for the initial experimentation, but at some point I need more computational power to do &#39;big runs&#39; of my models. That&#39;s when I connect to a machine in my office by typing &lt;code&gt;http://localhost:9999&lt;/code&gt; and I get a full jupyter lab session that&#39;s running on the office machine.&lt;/p&gt;
&lt;p&gt;What? I can access a remote machine by writing &lt;em&gt;local&lt;/em&gt; host? Yes. This is the magic of SSH tunnels.&lt;/p&gt;
&lt;p&gt;Maybe you already use TeamViewer or similar software and don&#39;t see the point of this exercise. Well if that works for you, great. But the advantage of this method is that much less information has to travel over the interwebs. With TeamViewer you send the entire picture of the desktop so it can often be unresponsive, especially if you&#39;re on a bad connection. With SSH tunnels, results can still be slow to arrive, but at least the image won&#39;t become huge pixels where you can&#39;t see the text anymore :)&lt;/p&gt;
&lt;p&gt;In case you don&#39;t care for long explanations there&#39;s a TL;DR towards the end.&lt;/p&gt;
&lt;h2&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#some-prerequisites&#34;&gt;Some prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#running-an-app-locally&#34;&gt;Running an app locally&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#accessing-an-app-remotely&#34;&gt;Accessing an app remotely&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#multiple-tunnels&#34;&gt;Multiple tunnels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#summary-and-more-possibilities&#34;&gt;Summary and more possibilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tldr&#34;&gt;TLDR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#troubleshooting&#34;&gt;Troubleshooting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Some prerequisites&lt;/h2&gt;
&lt;p&gt;If you&#39;ve never heard of SSH this tutorial might be tricky. But if you&#39;ve ever used GitHub to store your code you&#39;ve probably already used SSH. However I will assume basic knowledge of SSH here, so if you lack that basic knowledge, you can for example check out &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-use-ssh-to-connect-to-a-remote-server-in-ubuntu&#34;&gt;this tutorial at Digitalocean&lt;/a&gt; and then come back :)&lt;/p&gt;
&lt;p&gt;Another concept you need to be familiar with is that of ports. Most computers and networks today have firewalls so you cannot access them without opening ports, or doors, into their juicy innards. Web sites are accessed over ports &lt;code&gt;80&lt;/code&gt; and &lt;code&gt;443&lt;/code&gt; so if you run a web server those ports need to be open. To access a computer by SSH, the default is port &lt;code&gt;22&lt;/code&gt;. Digitalocean generally has great tutorials, and &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-18-04&#34;&gt;here&#39;s one about firewalls and opening ports for SSH&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and our main prerequisite is that you are able to access this remote machine over the interwebs via SSH. We will also look at the case where we cannot access the target machine directly, but have to &#39;jump&#39; through another machine first. That&#39;s what I have to do; I first SSH into a publicly available machine on the university network, and from there, I can then access my office machine with another SSH connection.&lt;/p&gt;
&lt;p&gt;I will also switch between using the terms machine and computer, FYI.&lt;/p&gt;
&lt;h2&gt;Running an app locally&lt;/h2&gt;
&lt;p&gt;Before launching a site on the interwebs, we usually develop it locally first. Blog applications like &lt;a href=&#34;http://jekyllrb.com&#34;&gt;Jekyll&lt;/a&gt; have a built in web server that automatically reloads any changes you make. So when I&#39;m writing this blog post, I have a browser window open pointed to &lt;code&gt;http://localhost:4000&lt;/code&gt;. Every time I save, Jekyll automatically rebuilds the site and I can check out what my post looks like now and then while writing.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;localhost&lt;/code&gt; part means your local computer. This is usually interchangeable with the IP addresses &lt;code&gt;127.0.0.1&lt;/code&gt; and &lt;code&gt;0.0.0.0&lt;/code&gt;. I say usually because there are some exceptions but those are not really important for our purposes today. Just be aware of it if you see those IPs when you&#39;re poking around getting these things to work.&lt;/p&gt;
&lt;p&gt;And the &lt;code&gt;4000&lt;/code&gt; is the port Jekyll has attached itself to. So &lt;code&gt;localhost:4000&lt;/code&gt; means you tell your browser to &amp;quot;go connect to my local computer, find door 4000 and there shall be magic sights there&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you have Python installed, you can test this very easily by opening your terminal and change to any directory you want, like the one where you store all your cat pictures. Then you can start a web server from there:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token builtin class-name&#34;&gt;cd&lt;/span&gt; whatever/folder/where/you/have/cats
python &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; http.server&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will most likely tell you it&#39;s now serving HTTP on port &lt;code&gt;8000&lt;/code&gt;. Go to &lt;code&gt;http://localhost:8000&lt;/code&gt; and you should see a list of all those cat pictures. This nifty little python command is very convenient for testing what we will be doing next, in case you don&#39;t have or need JupyterLab. You can select what port will be used by specifying it at the end of the command, like so:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;python &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; http.server &lt;span class=&#34;token number&#34;&gt;12345&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many applications these days use a browser interface, and a very common one in the Python world is &lt;a href=&#34;https://jupyterlab.readthedocs.io/en/stable/&#34;&gt;JupyterLab&lt;/a&gt;. It&#39;s not my personal favourite when it comes to code editors, but it&#39;s very convenient to have it running on the beefy machine in the office and I can access it from the comfort of my office desk by just pointing my web browser to the beefy machine (we call it the Beast, because it&#39;s got beastly powers. Well, it did a few years ago, it&#39;s actually not that powerful compared to what&#39;s available today, but let&#39;s not hurt its feelings. It will always be the Beast to us.).&lt;/p&gt;
&lt;p&gt;But what if I&#39;m not on the same network, or there are firewall restrictions, or I&#39;m far away in the comfort of my home?&lt;/p&gt;
&lt;h2&gt;Accessing an app remotely&lt;/h2&gt;
&lt;p&gt;The magic of SSH is that we can connect through its port, and bind local ports on the remote machine to local ports on the computer you&#39;re sitting at.&lt;/p&gt;
&lt;p&gt;This is going to be more tricky to keep track of pretty soon, so let&#39;s recap what was just stated. Every computer has its own local ports. They are local &lt;em&gt;to that computer&lt;/em&gt;. What SSH can do is that it can connect a local port on some other computer to a local port on &lt;em&gt;your&lt;/em&gt; computer. No need to open any more ports than SSH!&lt;/p&gt;
&lt;p&gt;Okay! Open a terminal window, ssh into the remote machine and start JupyterLab. We need it running or there&#39;s nothing to connect to, and especially for testing it&#39;s nice to have it running so we can see if someone (like ourselves) connect.&lt;/p&gt;
&lt;p&gt;JupyterLab by default runs on port &lt;code&gt;8888&lt;/code&gt;. So what we are going to do is bind the port &lt;code&gt;9999&lt;/code&gt; on my laptop to &lt;code&gt;8888&lt;/code&gt; on the Beast. This is also called port forwarding. Like forwarding mail if you&#39;ve moved temporarily, you put a temporary address to your temporary house&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/ssh_singlestep.svg&#34;&gt;&lt;img src=&#34;/img/ssh_singlestep.svg&#34; alt=&#34;Diagram showing localhost:9999 on laptop connected to localhost:8888 on the beast over SSH&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Diagram showing localhost:9999 on laptop connected to localhost:8888 on the beast over SSH. Created with &lt;a href=&#34;https://mermaid-js.github.io/mermaid-live-editor&#34;&gt;mermaid&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now open a new terminal window. Assuming you connect to your remote machine over the default SSH port, all the magic happens in a single line in your terminal:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:9999:localhost:8888 user@remotemachine&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s go through those commands we give ssh one by one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-f&lt;/code&gt; means we tell ssh to go to the background. We don&#39;t really want to do anything on the remote machine other than set up the port, so this way we can issue more commands in this terminal window or just close it to keep our workspace clean.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-N&lt;/code&gt; command means we don&#39;t execute any commands on the &amp;quot;other side&amp;quot; of our connection. Again, we only need to set up the ports so we don&#39;t need to execute commands on the remote machine.&lt;/p&gt;
&lt;p&gt;And then we have &lt;code&gt;-L&lt;/code&gt; which is the command to bind our ports and we give it the instructions to bind &lt;code&gt;localhost:9999:localhost:8888&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you now go to &lt;code&gt;localhost:9999&lt;/code&gt; in your computer&#39;s browser you should see JupyterLab running on the remote machine! (Or whatever application it is you might be running) If not, is the application actually running on the remote machine? Forgetting that step is the usual error for me :) Otherwise, try going through the steps again from the start.&lt;/p&gt;
&lt;p&gt;Crystal clear? Super green? Good. Things will get more complicated now.&lt;/p&gt;
&lt;h2&gt;Multiple tunnels&lt;/h2&gt;
&lt;p&gt;Now, let&#39;s say our Beast machine cannot be accessed over the interwebs. But it can be accessed on the internal network of our company or university. And there is some other machine at our place of work, a machine that is both open to the public web and the internal network.&lt;/p&gt;
&lt;p&gt;So to do anything on our Beast we have to first - let&#39;s call this computer Unicorn - login to Unicorn. From there we SSH into the Beast and start our JupyterLab session.&lt;/p&gt;
&lt;p&gt;Now, we can only bind/forward ports on our local machine, so we need to do this in two steps. First we create a tunnel to the Beast, and then we can do the same connection we did in the previous section. Let&#39;s look at it step by step.&lt;/p&gt;
&lt;h3&gt;Multiple tunnels: step 1&lt;/h3&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/ssh_tounicorn.svg&#34;&gt;&lt;img src=&#34;/img/ssh_tounicorn.svg&#34; alt=&#34;Diagram showing localhost:12345 on laptop forwarding to beast:22 on Unicorn over SSH&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Diagram showing localhost:12345 on laptop forwarding to beast:22 on Unicorn over SSH. Created with &lt;a href=&#34;https://mermaid-js.github.io/mermaid-live-editor&#34;&gt;mermaid&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The first step is we bind a local port on our home machine that works as a shorthand to connect to the Beast &lt;em&gt;as if we are on Unicorn&lt;/em&gt;. What we then have is a local port that automagically connects directly to the Beast through Unicorn.&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:12345:beast:22 user@unicorn&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what we do here is not actually connecting to the Beast, we only say that &lt;code&gt;localhost:12345&lt;/code&gt; - meaning port &lt;code&gt;12345&lt;/code&gt; on our laptop - can be used to connect to the Beast via ssh. If you run the above line, exchanging the values for your own addresses and users, you&#39;ll see that you only get asked for the password for &lt;code&gt;user@unicorn&lt;/code&gt;. (If you&#39;re using SSH keys this is not as clear, it&#39;ll just work if everything went well.)&lt;/p&gt;
&lt;p&gt;To test that this works, you should now be able to connect to the Beast through the local port we created:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-p&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;12345&lt;/span&gt; beastuser@localhost&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s where things might become confusing, because as you see you have to use your Beast user account &lt;code&gt;@localhost&lt;/code&gt;. Which is because our local port &lt;code&gt;12345&lt;/code&gt; is now actually our forwarding address for the Beast! If we again use the analogy of forwarding mail to a new house, the tunnel we have created is just the forwarding address. Connecting through that address is like actually sending mail to the new house.&lt;/p&gt;
&lt;p&gt;Got it? Great! (If you don&#39;t, play around with different port numbers until it clicks)&lt;/p&gt;
&lt;h3&gt;Multiple tunnels: step 2&lt;/h3&gt;
&lt;p&gt;Cool. Almost there now. This final step is very similar to what we did in the &amp;quot;single hop&amp;quot; scenario where we can connect directly to the Beast through SSH. Thanks to the tunnel we setup in step 1, we now have the same situation, only with a slight twist:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:9999:localhost:8888 &lt;span class=&#34;token parameter variable&#34;&gt;-p&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;12345&lt;/span&gt; beastuser@localhost&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything is using localhost now! You said a &amp;quot;slight&amp;quot; twist! What is going on?!&lt;/p&gt;
&lt;p&gt;Calm down. You get this if we just look at it in parts.&lt;/p&gt;
&lt;p&gt;So the last part, &lt;code&gt;-p 12345 beastuser@localhost&lt;/code&gt; is the same as when we did the test connection in the previous step, right? We connect to the Beast using our new forwarding address &lt;code&gt;localhost:12345&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And by doing that, we can access the local ports on the Beast, in this case &lt;code&gt;8888&lt;/code&gt; where JupyterLab is running. And just like before, we bind our home computer/laptop port &lt;code&gt;9999&lt;/code&gt; to the Beast&#39;s &lt;code&gt;8888&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In other words, now we can use JupyterLab from the comfort of our own browser!&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/ssh_multihop.svg&#34;&gt;&lt;img src=&#34;/img/ssh_multihop.svg&#34; alt=&#34;Diagram showing localhost:9999 on laptop forwarding to beast:8888 through Unicorn server&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Diagram showing localhost:9999 on laptop forwarding to beast:8888 through Unicorn server. The direct arrow is our end result and the upper arrow is the path we actually take. Created with &lt;a href=&#34;https://mermaid-js.github.io/mermaid-live-editor&#34;&gt;mermaid&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Summary and more possibilities&lt;/h2&gt;
&lt;p&gt;So now you know how to tunnel like a mole. Pretty nifty, huh?&lt;/p&gt;
&lt;p&gt;These basics allow for more uses. Just three examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mount the filesystem of the remote server and browse it as if you&#39;re using a local disk using SSHFS (SSH file system)&lt;/li&gt;
&lt;li&gt;Use graphical applications of a Linux app using X forwarding&lt;/li&gt;
&lt;li&gt;Use a cheap cloud server in another country and tunnel through to watch local video streams&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&#39;s also the concept of reverse SSH connections, in cases the machine you need remote access to is behind a firewall and there are no other servers on the network you can SSH into. I might write a guide for that in the future, depending on how eager I am to increase my &lt;a href=&#34;/about/#ratio&#34;&gt;post/design ratio&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope you find all this useful. I do almost every day!&lt;/p&gt;
&lt;h2&gt;TLDR&lt;/h2&gt;
&lt;p&gt;App running on port 8888 on a remote machine can be accessed on your local machine&#39;s port 9999 with:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:9999:localhost:8888 user@remotemachine&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In case you need to multihop through a &amp;quot;jump server&amp;quot; we need the extra step:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:12345:remotemachine:22 user@jumpserver&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Followed by:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-f&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-N&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-L&lt;/span&gt; localhost:9999:localhost:8888 &lt;span class=&#34;token parameter variable&#34;&gt;-p&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;12345&lt;/span&gt; remotemachineuser@localhost&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If your internet connection drops, the ports and bindings are sometimes not cleaned up properly. You&#39;ll then be unable to access your application through the browser, but when you try to establish the SSH tunnel you get errors saying the port is in use.&lt;/p&gt;
&lt;p&gt;On Mac and Linux you can issue the following command to check currently running ssh processes:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;ps&lt;/span&gt; aux &lt;span class=&#34;token operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;ssh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have no active ssh sessions this will most likely output only two lines, one saying something about &lt;code&gt;ssh-agent&lt;/code&gt; which is a background process keeping track of your ssh-keys if you need them. The other would be saying something about &lt;code&gt;grep&lt;/code&gt; because it shows the command we just issued.&lt;/p&gt;
&lt;p&gt;But if you do have active connections these should be listed here, and their process ID should be the second column from the left. Meaning you can kill those processes manually with:&lt;/p&gt;
&lt;pre class=&#34;language-bash&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;&lt;span class=&#34;token function&#34;&gt;kill&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;12345&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have &#39;multi-hopped&#39; then you can save yourself a few keyboard taps by killing the process of the first port binding in the chain, the others should drop automatically.&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;Yes, nobody sends mail anymore, but I think analogies tied to the real world are easier to handle than the abstractness of digital things. &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Thu, 16 Apr 2020 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/access-apps-like-jupyter-notebook-remotely-using-ssh-tunnels/</link>
          <guid isPermaLink="true">https://gamescapad.es/access-apps-like-jupyter-notebook-remotely-using-ssh-tunnels/</guid>
          
          <category>ssh</category>
          
          <category>work from home</category>
          
          <category>jupyter</category>
          
          <category>remote access</category>
          
          
          <category>tutorials</category>
          
        </item>
      
    
      
        <item>
          
            <title>Creating Websites Like It&#39;s 1999</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Around Christmas I launched a new &lt;a href=&#34;https://henrik.siljebrat.se&#34;&gt;personal website&lt;/a&gt;. It&#39;s the first time in years I&#39;ve written all the code for a website from scratch. All those new CSS things with responsive design and media queries scared me off so for this blog and other sites I&#39;ve mostly depended on themes made by others and then customized them a bit. Then I came across a great &lt;a href=&#34;http://taniarascia.com/overview-of-css-concepts/&#34;&gt;summary/overview of CSS&lt;/a&gt; and was inspired! So now I&#39;ve also changed this blag&#39;s design a bit, the main addition being a dynamic header menu that stays at the top when you scroll&lt;sup class=&#34;footnote-ref&#34;&gt;&lt;a href=&#34;#fn1&#34; id=&#34;fnref1&#34;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. I can find these annoying as they reduce the amount of space for text, especially on the phone, but I think it works fairly well here as it&#39;s now easier no navigate around even if you&#39;ve scrolled to the middle of a long blog post.&lt;/p&gt;
&lt;p&gt;I originally also planned to convert this blag from &lt;a href=&#34;https://jekyllrb.com&#34;&gt;Jekyll&lt;/a&gt; to &lt;a href=&#34;https://www.gatsbyjs.org/&#34;&gt;Gatsby&lt;/a&gt; as the latter is apparently very fast and search engine optimized and all that jazz. But when I started reading the documentation my eyes glazed over. Why all these contortions just to get a simple blog up and running? I&#39;m sure Gatsby is great for someone out there, but in my mind it&#39;s only great for those already brainwashed in the horrible mess that is Javascript package management.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/heavy_node.png&#34;&gt;&lt;img src=&#34;/img/heavy_node.png&#34; alt=&#34;the heaviest objects in the universe - sun, neutron star, black hole, node_modules&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Image stolen from random reddit thread.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;However I did find &lt;a href=&#34;https://www.11ty.dev/&#34;&gt;11ty&lt;/a&gt; which looked nice, and more recently updated than Jekyll. They have great little animations making fun of buzzwords and a cute possum on their website. That&#39;s enough to sell me. I love that you can run it from basically nothing without any setup other than installing and creating a new directory. What finally put me off using it was mainly that their plugin ecosystem isn&#39;t as strong as Jekyll&#39;s yet, in particular the syntax highlighter could need some work. But when/if I decide I want to give myself &lt;s&gt;more work&lt;/s&gt; a fun hobby, I&#39;ll definitely look into it again. Jokes aside this current setup with Jekyll would really need some dynamic resizing of images so download size can be adapted automagically when you&#39;re on a bad connection.&lt;/p&gt;
&lt;h2&gt;When I was seventeeeeeeeen&lt;/h2&gt;
&lt;p&gt;I used to create and run websites in the late &#39;90s and early &#39;00s. If I remember correctly I learned HTML by copy-pasting from other websites and magazines. It&#39;s difficult to do that these days as the source code for most websites is obfuscated by ad tracker javascript. Back then CSS was really new or even non-existent so we did silly things like designing with &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; and using 1x1px images to align elements. When CSS came around we could style the table borders to align things instead. Yes it was the stone age.&lt;/p&gt;
&lt;p&gt;I&#39;m sure you&#39;re dying to know what kind of websites I used to create.&lt;/p&gt;
&lt;p&gt;Mostly it was video game fansites. One of the more interesting ones was &#39;the Games Comparison Archive&#39; where I wrote articles comparing games in the same genre, as well as collected and normalised review scores from game review sites. Unfortunately &lt;a href=&#34;https://web.archive.org&#34;&gt;Wayback Machine&lt;/a&gt; doesn&#39;t have a snapshot (likely because the site didn&#39;t last very long) and weirdly redirects to some dos games archive but I&#39;m 99% sure this was the URL: &lt;a href=&#34;https://web.archive.org/web/2/http://gamesarchive.etmnet.com/&#34;&gt;gamesarchive.etmnet.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Too bad I didn&#39;t continue, I heard metacritic was fairly successful.&lt;/p&gt;
&lt;p&gt;The coolest thing I did was probably a Swedish fansite for Warcraft 3. I started it in May 1998, one and a half years before the game had even been announced. The first version was just a wishlist for what I wanted Warcraft 3 to be. Then I started getting emails from random people, who wanted to share their own wishlists. So I put theirs up as well. I started posting news, and as the rumour mill of the actual game wasn&#39;t running very quickly, the news were mostly about the wishlists and what happened on other Warcraft fansites. It was fun and kind of weird to know there were other nerds like me out there, and be able to connect. I managed to find web hosting from &lt;a href=&#34;https://web.archive.org/web/19990208004240/http://etmnet.com/&#34;&gt;ETMNet&lt;/a&gt; so I could use Perl CGI scripts to update the news more dynamically than editing and uploading HTML all the time.&lt;/p&gt;
&lt;p&gt;At some point I figured all these nerds sending me wishlists might want to talk to each other and not just me. So I found a book about &lt;a href=&#34;https://php.net&#34;&gt;PHP&lt;/a&gt; with a tutorial of how to program a forum. My foundation skills in programming started there, and to this day I still believe the PHP documentation is one of the best ones out there. If nothing else for the fact they&#39;ve got a comment system where people shared tips and tricks. Kind of like &lt;a href=&#34;https://stackoverflow.com&#34;&gt;Stack Overflow&lt;/a&gt; but much earlier. The site grew, the forums got more active and I even hired people to help out. I paid them in nerd sweat. (If you, dear reader, happen to be one of them then please get in touch! It&#39;s been too long :)&lt;/p&gt;
&lt;p&gt;I redesigned the site a billion times. The oldest version I can find on Wayback machine is one from &lt;a href=&#34;https://web.archive.org/web/19990429203234/http://war3se.etmnet.com/&#34;&gt;April 1999&lt;/a&gt;, five months before Warcraft 3 was announced in September 1999.&lt;/p&gt;
&lt;p&gt;And &lt;a href=&#34;https://web.archive.org/web/20010401014756/http://www.war3se.com/&#34;&gt;here&#39;s what it looked like in 2001&lt;/a&gt;, when I apparently had gotten my own domain name.&lt;/p&gt;
&lt;p&gt;I closed and reopened the site many times as my motivation went up and down. The funniest &#39;closing message&#39; I remember was one that went something like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;If motivation could be bought on a can, this wouldn&#39;t be a problem. Unfortunately, such is not the case.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Somewhere around when World of Warcraft was announced, me and the fine people of &lt;a href=&#34;https://web.archive.org/web/20030404003903/http://www.diabloii.nu/&#34;&gt;diabloii.nu&lt;/a&gt;, a Swedish fansite for the Diablo games, got together and created &lt;a href=&#34;https://web.archive.org/web/20040924154417/http://www.warcraft.nu/&#34;&gt;warcraft.nu&lt;/a&gt;. It was likely Sweden&#39;s biggest Warcraft fansite at some point, we had at least 10k visitors a month if I recall correctly.&lt;/p&gt;
&lt;p&gt;I lost interest around 2005-2006 or so, I can&#39;t remember exactly when. But the others kept the site going for years after.&lt;/p&gt;
&lt;p&gt;Looking back at it now, I cringe at some of the things teenager me wrote. Not to mention my nickname, I&#39;m dying of embarrassment. But mostly it&#39;s fine. Sometimes even funny. And also it was 20 years ago. I suddenly feel old. The interwebs were cooler before they became cable TV.&lt;/p&gt;
&lt;h3&gt;ps&lt;/h3&gt;
&lt;p&gt;If you&#39;re wondering about the &lt;a href=&#34;https://en.wikipedia.org/wiki/.nu&#34;&gt;.nu domain&lt;/a&gt; it was commonly used among Swedes because &#39;nu&#39; means &#39;now&#39; in Swedish (and in a few other languages). Also I think it was difficult to get a .se domain name as an individual back then so .nu was the common way to go. Apparently the country Niue &lt;a href=&#34;https://www.hawaiipublicradio.org/post/pacific-news-minute-niue-sues-swedish-company-markets-its-domain-name-nu&#34;&gt;sued Sweden&#39;s internet foundation&lt;/a&gt; in 2018 for taking control of the domain name.&lt;/p&gt;
&lt;p&gt;Awkward!&lt;/p&gt;
&lt;hr class=&#34;footnotes-sep&#34;&gt;
&lt;section class=&#34;footnotes&#34;&gt;
&lt;ol class=&#34;footnotes-list&#34;&gt;
&lt;li id=&#34;fn1&#34; class=&#34;footnote-item&#34;&gt;&lt;p&gt;This is no longer true as of April 2020, I changed the design again! &lt;a href=&#34;#fnref1&#34; class=&#34;footnote-backref&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

          </description>
          <pubDate>Tue, 25 Feb 2020 01:00:00 +0100</pubDate>
          <link>https://gamescapad.es/creating-websites-like-its-1999/</link>
          <guid isPermaLink="true">https://gamescapad.es/creating-websites-like-its-1999/</guid>
          
          <category>webdev</category>
          
          <category>nostalgia</category>
          
          <category>bragging</category>
          
          <category>websites</category>
          
          <category>redesign</category>
          
          <category>teenagers</category>
          
          <category>clickthesitelogoforaneasteregg</category>
          
          
          <category>musings</category>
          
        </item>
      
    
      
        <item>
          
            <title>Mirror&#39;s Edge Catalyst is a Crap Game</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;I used to have a huge 3x2 meter version of the below art on the wall of my hallway. I fucking loved the first Mirror&#39;s Edge. The art style was cool, I discovered the magic music of &lt;a href=&#34;https://solarfields.bandcamp.com&#34;&gt;Solar Fields&lt;/a&gt; and though there were bugs and quirks in the gameplay, the concept of a first person platformer was fresh (2009). There wasn&#39;t much story to talk about, but Rihanna Pratchett did admirably, seeing how she was presented with a basically finished game when DICE hired her. And when Mirror&#39;s Edge flowed, the white and brightly coloured surroundings melted into streams of light feathered bliss.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/mirrorsedge.jpg&#34;&gt;&lt;img src=&#34;/img/mirrorsedge.jpg&#34; alt=&#34;mirrors edge - faith standing on roof looking down on the streets&#34;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;So I was slightly annoyed that the sequel, Mirror&#39;s Edge Catalyst, was released late 2016, just when I had moved to London and didn&#39;t have access to a gaming rig. Fast forward to January 2019, when I bought a PS4 in order to create some form of work/life balance with this stressful PhD I&#39;m doing. (Let&#39;s not mention that it took time to save enough money to justify the purchase. Oops!)&lt;/p&gt;
&lt;p&gt;The first game I played on this PS4 was Horizon: Zero Dawn and I loved it. Not revolutionary in any way, but a beautiful and very competent game with tight and fun combat mechanics, a decent story and main character who was not only tough as hell but also wonderfully sarcastic if you chose the right dialogue options. Oh, and robot dinosaurs. I mean, they had me at robot dinosaurs. I only really have two real criticisms of Horizon: Zero Dawn. The first being that cliffs are only scalable at certain points, and these points can be difficult to find, so several times I spent lots of time running along cliffs trying to find that point only to sometimes conclude there was none. The second criticism is that I initially ran around randomly to explore the world, only to find big areas completely empty, later realising I had to activate a quest for these areas to be populated. But those things don&#39;t matter, because the rest of the game is amazing, just look at this:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/horizon.gif&#34;&gt;&lt;img src=&#34;/img/horizon.gif&#34; alt=&#34;video of aloy from horizon zero dawn kicking dinosaur ass in slow motion&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Aloy kicks ass. Dinosaur ass. Clip courtesy of &lt;a href=&#34;https://twitter.com/SunhiLegend&#34;&gt;SunhiLegend&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Mirror&#39;s Edge Catalyst however, is not amazing. Mirror&#39;s Edge Catalyst is a worse game than the first one in all areas. I&#39;d go so far as saying it&#39;s a worse game than most games. I can&#39;t believe that this game is the result of any reasonable designer&#39;s actual vision. It&#39;s a mess of half-assed things that all scream &amp;quot;me too!&amp;quot;. The kind of metoo that managers give orders about because all they do is read feature lists of the top games on metacritic.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;It has to be open world! Lots of side missions with map icons like how Ubisoft does it! Players want combat! We need to monetise! There has to be some kind of multiplayer interactions!&amp;quot;&lt;/p&gt;
&lt;p&gt;--random marketing exec&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I really hope, for the sake of all the people who worked on this game, that this crap shoot of a game is the result of management being idiots. It’s like a game from I don’t know when but absolutely not 2016. If you want to copy other games, why did you not look at anything that happened between the first Mirror&#39;s Edge and 2016? Texture resolution is so low the game looks like it&#39;s from before even 2009, and there&#39;s still texture pop-in. I would&#39;ve been satisfied with a free runner with tight controls but not even that part of the game is polished. Running and jumping was generally fine though, until I got to an area supposed to be a big mainframe of some kind. I jumped into invisible walls and needed several tries and very particular aiming to progress. Apparently the test department got tired somewhere around here. Or fired.&lt;/p&gt;
&lt;p&gt;I mean if it’s open world; why not allow us to see some of this world and its actual inhabitants by having some levels set on the ground or at least among civilians? Parkouring through a shopping center filled with people, up and down escalators and statues, or jumping from car roof to car roof or.. so many missed opportunities and instead this mess where the only random people you bump into are these people standing around extremely weird places giving side missions. They can be placed in the middle of fights, next to explosions, in ventilation shafts and just generally nonsensical places.&lt;/p&gt;
&lt;p&gt;The only way to get some information about what&#39;s happening in the game world is through TV screens. But more often than not, the sound of these TV screens is drowned out by characters also standing next to the TV screen, and they&#39;re saying random things because you’re standing close. If you step away from the character to avoid this happening, you can&#39;t hear the TV anymore. Good job there.&lt;/p&gt;
&lt;p&gt;Speaking about thinking things through, as usual there are helpful tips displayed on loading screens, exemplified below:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/mirrorsedge_loadscreen.jpg&#34;&gt;&lt;img src=&#34;/img/mirrorsedge_loadscreen.jpg&#34; alt=&#34;mirrors edge catalyst - loading screen saying it is often preferable to run away than fight&#34;&gt;&lt;/a&gt;
  &lt;p&gt;You don&#39;t always have to stay and fight. This is technically correct. Because often, you cannot progress without fighting. But not always.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This text makes sense, it’s a game about free runners after all. Well, unless it’s a boss fight, where you &lt;em&gt;have&lt;/em&gt; to fight waves of enemies. Which is stupid for two main reasons. First, it’s a game about free runners, why is there forced combat? Two, did you completely miss the whole shitshow that went down with Deus Ex Human Revolution? Where players had to fight and kill really tough bosses even if they had spent all their points into sneaking? I know, I know, that was 2011, but I had spent all my points on running when I first encountered this kind of forced battle. So why? Honestly I don&#39;t think it would matter much, because the combat system is really bad. To properly dodge you have to lock on to the target which allows you to spin around them to dodge. But the lock is so wonky it sometimes doesn&#39;t work and/or releases randomly. And if there are multiple enemies you can&#39;t dodge them, because only the enemy you&#39;re locking on to can be spun around. Why not just have a dodge roll?&lt;/p&gt;
&lt;p&gt;It would make sense because, oh I don&#39;t know, rolling is what Faith does every single time after landing from a high fall? So yeah, these boss fights are completely ridiculous. In the case of Deus Ex Human Revolution, Eidos&#39; excuse was that &lt;a href=&#34;https://www.rockpapershotgun.com/2011/09/19/deus-ex-hrs-boss-fights-were-outsourced/&#34;&gt;another company made the boss fights&lt;/a&gt;. Not that that absolves them since they still chose to put those boss fights into the game, but what’s your excuse, DICE? Oh right, you&#39;re still stuck in 2009. And everybody knows the dodge roll was invented in 2014 by the developer &lt;a href=&#34;http://dodgeroll.com&#34;&gt;Dodge Roll&lt;/a&gt;, how else would they have gotten that domain name?&lt;/p&gt;
&lt;p&gt;Speaking of loading screens. They go on forever, probably because of bad optimisation (remember texture pop-in mentioned earlier?) I also saw them way too often. Because I kept falling to my death. Which is fine, if it&#39;s because I screw up. But most of the time, it was because of bad hit boxes, imprecise controls and extremely unclear &lt;a href=&#34;https://en.wikipedia.org/wiki/Affordance&#34;&gt;affordances&lt;/a&gt; (hints; visual or auditory markers). Like here:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/mirrorsedge_affordance1.jpg&#34;&gt;&lt;img src=&#34;/img/mirrorsedge_affordance1.jpg&#34; alt=&#34;mirrors edge catalyst - example of runner vision painting the wrong thing red&#34;&gt;&lt;/a&gt;
  &lt;p&gt;The red is a lie. We want to get to the platform over to the right in the picture.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The pipe is red, thanks to &amp;quot;runner vision&amp;quot; which paints red those objects that can be used for climbing and jumping. However, if I climb up it and try to jump onto the platform to the right in the picture, I won’t reach it and will fall to my death. Meaning loading screen.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/mirrorsedge_affordance2.jpg&#34;&gt;&lt;img src=&#34;/img/mirrorsedge_affordance2.jpg&#34; alt=&#34;mirrors edge catalyst - example of when runner vision correctly paints an object red&#34;&gt;&lt;/a&gt;
  &lt;p&gt;The red is not a lie here, surprisingly enough. This is a view from the far side of the room seen in the previous picture. The platform in front of us is the same middle platform we wanted to get to in the previous picture. We can make out the grey pipe from the previous picture waaay over there.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The correct action is to jump from the fence/railing. If I use that to go to that other side then the railing/fence is correctly marked as red. There is no pipe here, but apparently the existence of one in the middle platform screws up the runner vision. This kind of thing happens way too often in Mirror&#39;s Edge Catalyst.&lt;/p&gt;
&lt;p&gt;Here&#39;s another fun example:&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/mirrorsedge_navigation.jpg&#34;&gt;&lt;img src=&#34;/img/mirrorsedge_navigation.jpg&#34; alt=&#34;mirrors edge catalyst - navigation markers and compass show irrelevant information&#34;&gt;&lt;/a&gt;
  &lt;p&gt;The red is not exactly a lie here, but very misleading. The red beam to the right can be seen from far away and is basically a vertical red stick shoved into the ground where the objective is located. The compass marker in the lower part of the screen also shows where the objective is. They&#39;re both technically correct, but not helpfully correct.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The red objective marker in the lower part of the screen tells us to go down, and the objective &amp;quot;beam&amp;quot; to the right shows the exact location of the objective like a red vertical stick through the world. But neither of these &amp;quot;helpful&amp;quot; markers show that actually I need to go left into that tent to get underground in order to reach the objective.&lt;/p&gt;
&lt;p&gt;Affordances are also often non-existent. At one point, the platforms you’re running on start breaking. In many games, this is scripted so the platforms break slightly after you pass them, so they’re there only for dramatic effect. In other games, there are affordances that indicate when a platform is about to break. In Mirror&#39;s Edge Catalyst however, it’s completely random. I died four or five times because I fell down. I tried just running, died. Tried jumping along. Died. Randomly pressed jump here and there a few times and eventually made it. I’ve no clue what I did, which is why I draw the conclusion this section was just random. Great feedback loop to improve your play, huh?&lt;/p&gt;
&lt;p&gt;Seriously, did anybody test this game, at all? Oh right, they fired the test department. We already concluded that. Sorry, I forgot.&lt;/p&gt;
&lt;p&gt;Speaking of crap game design. It&#39;s possible to &amp;quot;hack&amp;quot; TV screens, for no functional reason at all. So when the villains started using turrets against me, I thought; &amp;quot;sweet! I can hack them and use them to my advantage!&amp;quot;. Nope. I can shut them down but not hack them. Maybe I was stupid and hadn&#39;t put points into hacking. Nope. There&#39;s no hacking skill. There was an opportunity here to allow for non direct violence but nope. Oh well, it&#39;s not like the entire story is based around you helping a hacker to take down an evil computer system. Or that the game opens up with you meeting some hacker dude who sees you as his big sister. So you know, hacking is not a skill that is easily accessible to you as a protagonist.&lt;/p&gt;
&lt;p&gt;You think that&#39;s not really game design, it&#39;s just story or setting or whatever? How about all the times you&#39;re running through literal storms of bullets and enemies and reach an elevator/door button, press it, and suddenly all enemies are gone? Apparently &lt;em&gt;they&lt;/em&gt; can be teleported but when &lt;em&gt;I&lt;/em&gt; fall down the side of a building I have to see a loading screen. Poor enemies, I imagine they have to see the text  &amp;quot;you won&#39;t be executed if you kill the player before they reach the button&amp;quot; on the loading screen for NPC heaven.&lt;/p&gt;
&lt;p&gt;And these random documents and recordings scattered all over the place. What is this, the &#39;90s? System Shock started this a long time ago (afaik), and it was kind of working although sometimes awkward as story/setting explainers. But at least it made kind of sense that these recordings were made, within the setting. This is the case in Horizon; the recordings you find are lab notes or diaries that you find where appropriate. For example, you can find lab note recordings...in a lab! There &lt;em&gt;are&lt;/em&gt; recordings in random locations of the world, but from what I can recall, they are usually found in the rubble of old buildings. In Mirror’s Edge Catalyst however, you find a recording of a very sensitive conversation between two main characters...in a random ventilation shaft.&lt;/p&gt;
&lt;p&gt;Sure, that could&#39;ve made sense if that was the only recording found in this way. Because &lt;em&gt;maybe&lt;/em&gt; someone secretly recorded the conversation and then hid it in a ventilation shaft. But this particular ventilation shaft is nowhere close to anything, it&#39;s not mentioned by anybody that this conversation has been recorded and was hidden, and it&#39;s just as randomly placed as all other recordings and secret documents you find. It&#39;s like someone was running out of time and placed all these collectibles everywhere and nowhere without thought.&lt;/p&gt;
&lt;p&gt;Without thought, yeah, that pretty much sums up how Mirror&#39;s Edge Catalyst must&#39;ve been created.&lt;/p&gt;
&lt;p&gt;EA/DICE turned into a Battlefield making workshop many years ago now. I haven&#39;t really played any of them much since Battlefield 1942. Wait that&#39;s not true, I played Battlefield 3 for several hours. Oh, but 1942, that was a great game. What a multiplayer demo. I guess EA/DICE are incapable of doing anything innovative these days. Or even slightly different than run-of-the-mill manshooters. Which isn&#39;t that surprising, they haven&#39;t tried leaving their comfort zone in years. And seeing how crap Mirror&#39;s Edge Catalyst is, they never will again. You keep making your Battlefield FPS games, DICE. It&#39;s okay to be a one-trick pony. At least your shareholders are happy.&lt;/p&gt;
&lt;p&gt;Compare all this to Horizon: Zero Dawn, which as I mentioned is not a revolutionary or even innovative game. But it’s great because the parts they have are well made, make sense in their context of the world and are actually interesting. The developers &lt;a href=&#34;https://en.wikipedia.org/wiki/Guerrilla_Games&#34;&gt;Guerilla Games&lt;/a&gt; must&#39;ve had lots of experience making this kind of game before. Oh, they don&#39;t? They&#39;re mainly known for their FPS series Killzone?&lt;/p&gt;
&lt;p&gt;Well, isn&#39;t that a funny coincidence?&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/horizon_peace.jpg&#34;&gt;&lt;img src=&#34;/img/horizon_peace.jpg&#34; alt=&#34;horizon zero dawn - aloy standing on top of a strider making the peace sign with the sun behind her&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Peace out bitches.&lt;/p&gt;
&lt;/div&gt;

          </description>
          <pubDate>Sun, 19 May 2019 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/review-of-mirrors-edge-catalyst/</link>
          <guid isPermaLink="true">https://gamescapad.es/review-of-mirrors-edge-catalyst/</guid>
          
          <category>mirrorsedge</category>
          
          <category>horizonzerodawn</category>
          
          <category>review</category>
          
          <category>rant</category>
          
          <category>gamedesign</category>
          
          
          <category>reviews</category>
          
        </item>
      
    
      
        <item>
          
            <title>Building Bots in StarCraft 2 for Psychologists</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;Hello visitor! I haven&#39;t blogged in many years, so I thought I&#39;d kick start a new era of blogging with a tutorial series on how to make bots with the recently released pysc2.&lt;/p&gt;
&lt;p&gt;I&#39;m not a great programmer in any way, but neither is this a tutorial on how to program, so I will assume you have basic knowledge of python. You will likely also want some familiarity with working with matrices in python via numpy, but maybe not. I actually explain many of the numpy things in some detail, since the Deepmind coders do stuff in one line i would need a bunch of lines to do. But please tell me if there&#39;s something you want me to explain further!&lt;/p&gt;
&lt;p&gt;Without further ado, let us get cracking.&lt;/p&gt;
&lt;h2&gt;Introduction: humans are amazing&lt;/h2&gt;
&lt;p&gt;Imagine yourself standing on the street. You take in your surroundings, your senses send signals to your brain, while your brain sends signals back to your senses, telling them what they should see, and you decide to...&lt;/p&gt;
&lt;p&gt;Well, what would you like to do? So many things you could choose. That thing about brain sending signals back to your senses is a real thing by the way. And there are more of these connections than those going from your eyes to your brain, implying that we indeed see what we want to! (&lt;a href=&#34;http://www.sciencedirect.com/science/article/pii/S0896627307003765&#34;&gt;See here for an example&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Makes you think doesn&#39;t it? (pun intended) However, we shall not dwell on that subject more (although it is part of my &lt;a href=&#34;http://iggi.org.uk/students/2016/henrik-siljebrat/&#34;&gt;research&lt;/a&gt; if you&#39;d like to know more).&lt;/p&gt;
&lt;p&gt;So, back on the street again, let&#39;s simplify the scenario. You can only take discrete steps. For every step you take (&lt;a href=&#34;https://youtu.be/OMOGaugKpzs&#34;&gt;and every move you make&lt;/a&gt;), you look around  and decide on an action based on what you see (we shall disregard imagination for now, you only make decisions based on your surroundings). What would you do and how would you reach that decision?&lt;/p&gt;
&lt;p&gt;This is still a very complicated scenario, as the real world is filled with many wondrous and horrible things and we can choose to interact with our world in even more combinations.&lt;/p&gt;
&lt;p&gt;Let&#39;s simplify even more, to the scenario of playing a video game. This is a much more constrained space of possible observations, it&#39;s governed by rules we know and the actions we can take in that game are pre-defined.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://deepmind.com/blog/ai-and-neuroscience-virtuous-circle/&#34;&gt;In my field of research&lt;/a&gt;, we use video games as experimental settings to try and understand how humans make decisions and use that knowledge to improve the capabilities of artificial intelligence.&lt;/p&gt;
&lt;p&gt;Which takes us to StarCraft 2. It&#39;s a so called Real Time Strategy (RTS) game, where you gather resources to build a base and enough units to destroy your enemy. It&#39;s like Chess but in real time and way more complicated as the combinations of possible things to do are way more than in Chess.&lt;/p&gt;
&lt;p&gt;It&#39;s a lovely game, I especially like the colors and sounds of the Colossus unit&#39;s energy beams as they disintegrate pathetic Zerglings trying to come close enough to bite.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;img src=&#34;/img/sc2_giraffe.gif&#34; alt=&#34;colossus destroying reapers&#34;&gt;
  &lt;p&gt;This is not a Colossus disintegrating Zerglings, but I think giraffes are more amusing anyway.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;How do we learn to play a game like StarCraft 2 (SC2)? If you think about it, it&#39;s crazy that anyone can learn to play something that complicated. Yet here we are, with huge tournament prizes for being the best SC2 player in the world. And, you know, since we can learn to read and write, play football, play musical instruments, climb Mount Everest and go to the fucking moon, maybe playing SC2 isn&#39;t that big of a deal, right?&lt;/p&gt;
&lt;p&gt;Actually, all of our assumptions so far have relied on that we know how to interpret our sensory signals and how to perform actions like moving our arms, pressing buttons and so on. Which is something babies have to learn how to do (and there are different opinions on how much innate knowledge we have at birth).&lt;/p&gt;
&lt;p&gt;That&#39;s not even the whole story. If you take the approach of &lt;a href=&#34;https://en.wikipedia.org/wiki/Embodied_cognition&#34;&gt;embodied cognition&lt;/a&gt;, human behavior is not just input-brain-output. It&#39;s a brain in a body in an environment and our behavior is an emergent phenomenon in the interaction between those three systems (which themselves contain many different subsystems).&lt;/p&gt;
&lt;p&gt;So, you know, to create an experiment closer to how humans learn to play StarCraft, we should do something more complicated. Like, creating a Minecraft bot that learns how to use its body, navigate and survive in its environment, and then learns to play SC2. An artificial intelligence agent embedded in its world (Minecraft), learning to play a game (SC2).&lt;/p&gt;
&lt;p&gt;Confused? Yeah, now you know why there&#39;s so much confusion in the psychology and neuroscience fields. It&#39;s a complicated subject. Now that you know that, building a bot will feel so easy :)&lt;/p&gt;
&lt;p&gt;So forget all I just said. Don&#39;t think about the incredible complexity of human behavior for a moment and lets get down to the business of creating a bot that can play SC2.&lt;/p&gt;
&lt;h2&gt;pysc2 - a love story between Blizzard and Deepmind&lt;/h2&gt;
&lt;p&gt;If you&#39;re not familiar with StarCraft II, I highly recommend trying it out. Not only is it fun, but you&#39;ll also be able to understand this tutorial better. You can try the free Starter Edition on &lt;a href=&#34;https://us.battle.net/account/sc2/starter-edition/&#34;&gt;Battle.net&lt;/a&gt;. You can actually use the free starter edition for this tutorial!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/deepmind/pysc2&#34;&gt;pysc2&lt;/a&gt; is Deepminds python wrapper of Blizzard&#39;s &lt;a href=&#34;https://github.com/Blizzard/s2client-api&#34;&gt;sc2 api&lt;/a&gt;. This is nice for people like me who don&#39;t know much about C++, and also because python has access to so many great libraries for neural networks and data science. Additionally, pysc2 was made specifically as a reinforcement learning environment. To know more, &lt;a href=&#34;https://deepmind.com/documents/110/sc2le.pdf&#34;&gt;read the paper&lt;/a&gt;. I don&#39;t think you have to read that to follow along in this tutorial but it will likely help you get a feel for how the framework...works.&lt;/p&gt;
&lt;p&gt;However, an issue is that the &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md&#34;&gt;documentation&lt;/a&gt; for pysc2 is not great. It mentions the main concepts but is low on detail, so for a fool like myself it was not easy to understand how to go about making my own bot. But I want to use this in my own research so I need to understand this whole thing. And might as well share my findings in case it helps anyone.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;The instructions on the official &lt;a href=&#34;https://github.com/deepmind/pysc2#quick-start-guide&#34;&gt;pysc2 Github page&lt;/a&gt; are clear and helpful. It&#39;s fairly easy to get started if you ever used &lt;code&gt;pip&lt;/code&gt; before to install something.&lt;/p&gt;
&lt;p&gt;But in short, if you&#39;re on Windows or Mac, install StarCraft II with the &lt;a href=&#34;http://eu.battle.net/en/app/&#34;&gt;standard installer&lt;/a&gt;. If you&#39;re on Linux, there&#39;s a special version for you on &lt;a href=&#34;https://github.com/Blizzard/s2client-proto#downloads&#34;&gt;Blizzard&#39;s Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then you need python, which you can download from the &lt;a href=&#34;https://www.python.org/&#34;&gt;official site&lt;/a&gt;. The latest version, 3.6, should work fine.&lt;/p&gt;
&lt;p&gt;When you have installed those two, open a command prompt (Win) or terminal window (Mac) and do a:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;$ pip3 &lt;span class=&#34;token function&#34;&gt;install&lt;/span&gt; pysc2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Or just &lt;code&gt;pip&lt;/code&gt; if you have python2) When that is done, download the &lt;a href=&#34;https://github.com/Blizzard/s2client-proto#downloads&#34;&gt;maps&lt;/a&gt; and Deepmind &lt;a href=&#34;https://github.com/deepmind/pysc2/releases/download/v1.0/mini_games.zip&#34;&gt;mini games&lt;/a&gt; and extract those to your &lt;code&gt;StarCraftII/Maps/&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;You should now be able to do a test run using:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; pysc2.bin.agent &lt;span class=&#34;token parameter variable&#34;&gt;--map&lt;/span&gt; Simple64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it. This procedure was all I needed for installing on a Windows 7 machine. Your mileage may vary, as usual when computers are involved.&lt;/p&gt;
&lt;h2&gt;Overview of the framework&lt;/h2&gt;
&lt;p&gt;Following on from the story about yourself walking around the streets making people uncomfortable, it&#39;s worth repeating the three basic conceptual terms we&#39;re going to refer to over and over again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;agent - yourself in the street walking analogy. Here it is another name for bot, which in turn means automated player&lt;/li&gt;
&lt;li&gt;observation - your surroundings on the street at a discrete point in time. The state of the world (game) at a certain time point&lt;/li&gt;
&lt;li&gt;action - waving to someone, walking down the street. Commands sent to the game&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Worth noting is that in reinforcement learning (next lesson), the algorithms usually speak of states (s) and actions (a) instead of observations and actions. But we&#39;ll get to that in the next lesson.&lt;/p&gt;
&lt;p&gt;Other important terms are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;episode - one full training round, usually one episode is from the start of the game to its end and/or when a reward is received. So to use our walking down the street scenario, one episode could be you walking down the street and successfully getting on the bus to work. The next episode would be the next day when you try to do the same thing. This may sound silly, but maybe you just moved into this house and it&#39;s the first time you&#39;re going to the bus stop. You need a few days - a few episodes - to learn the route to the bus stop.&lt;/li&gt;
&lt;li&gt;step - An episode can contain many steps. Each step is basically Observation -&amp;gt; Decision -&amp;gt; Action. Then we move onto the next step.&lt;/li&gt;
&lt;li&gt;reward - Each action taken can lead to reward. Sometimes that means the end of the episode (getting on the bus can be the reward). It could also be that you get a reward for reaching checkpoints along the way to the bus stop, and getting on the bus is the end of the episode. The goal is to maximize your reward over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On a conceptual level, pysc2 provides an &amp;quot;environment&amp;quot; for an agent. pysc2 takes care of starting up the game, waking up your agent and works as the intermediary between your agent and the game. pysc2 gets observations from the game, sends these to your agent, and your agent sends back actions through pysc2 to the game itself.&lt;/p&gt;
&lt;h3&gt;Observations&lt;/h3&gt;
&lt;p&gt;Since StarCraft 2 is a complicated game with lots of information, Deepmind has scaled all of this down. Instead of getting the entire screen contents in full resolution, we have two main things; the screen and minimap.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;img src=&#34;/img/sc2_screen_minimap.jpg&#34; alt=&#34;screenshot of starcraft where the main game window is highlighter in blue and the minimap highlighted in yellow&#34;&gt;
  &lt;p&gt;The blue box is the screen and the yellow box the minimap.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The game screen we get each observation is not in full resolution. The default here is that the entirety of that game screen is scaled down to an 84x84 matrix. Which is very small and it would be close to impossible to discern any useful details in all that. So, instead of all 1920x1080 RGB pixels being scaled down to 84x84, we have what is called &#39;feature layers&#39;. One feature layer for example shows only the units you currently have selected, by giving you an 84x84 matrix where &lt;code&gt;0&lt;/code&gt; is background and &lt;code&gt;1&lt;/code&gt; is a selected unit. Important to note is that since it&#39;s a scaled down image, one unit can cover more than one pixel/one position in the 84x84 matrix. Another feature layer shows the health of units on different parts of the screen.&lt;/p&gt;
&lt;p&gt;The same goes for the minimap, it has feature layers like this as well, and the default size for that matrix is 64x64 (i think?). You can read more details in environment.md if you&#39;d like.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;/img/sc2_featurelayers.png&#34;&gt;&lt;img src=&#34;/img/sc2_featurelayers.png&#34; alt=&#34;screenshot of pysc2 interface where you can see all the feature layers&#34;&gt;&lt;/a&gt;
  &lt;p&gt;This is the pysc2 UI, where you can see all the different feature layers on the right and a very basic graphical representation of the game to the left. Click the image for a larger version.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Actions&lt;/h3&gt;
&lt;p&gt;The amount of possible actions are potentially enormous. So Deepmind has discretized these as well. Based on actions taken by human players in thousands of games, they have defined around 500 actions. For example you have actions to select units, move units, pan around the map and so on. We will go into more detail about how these are used later, but if you&#39;re curious you can check out what they say about actions in the &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md#actions&#34;&gt;official documentation&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Putting it together&lt;/h3&gt;
&lt;p&gt;When we start a mini game or map with pysc2, it boots up StarCraft II and uses a &lt;code&gt;run loop&lt;/code&gt; to go through all episodes and steps within those episodes. The &lt;code&gt;run loop&lt;/code&gt; can be found in &lt;code&gt;pysc2.env.run_loop&lt;/code&gt; and if we try to write that in pseudocode, the run loop in pysc2 is something like this:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;number_of_episodes &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;50&lt;/span&gt;
env &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; start starcraft2
&lt;span class=&#34;token builtin&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; load &lt;span class=&#34;token builtin&#34;&gt;map&lt;/span&gt; MoveToBeacon
agent &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; setup some agent
&lt;span class=&#34;token keyword&#34;&gt;while&lt;/span&gt; number_of_episodes &lt;span class=&#34;token keyword&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  goal_reached &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token boolean&#34;&gt;False&lt;/span&gt;
  &lt;span class=&#34;token keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;not&lt;/span&gt; goal_reached&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    obs &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; environment&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;update&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
    action &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; agent&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;step&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
    reward &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; takeAction&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;env&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; reward &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
      goal_reached &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token boolean&#34;&gt;True&lt;/span&gt;
  number_of_episodes &lt;span class=&#34;token operator&#34;&gt;-=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&#39;t how it actually looks but I tried to make more understandable. Don&#39;t worry though if all of that doesn&#39;t make sense, the main thing to remember is that &lt;code&gt;obs&lt;/code&gt; variable sent to the agent, as it contains all the observations for the current state/step. Inside of that variable we have a dictionary of all observations made, in &lt;code&gt;obs.observations&lt;/code&gt;. This is not very clear in Deepminds environment.md so I&#39;ve started an effort to update that in my forked repo version of the same file. You can find that &lt;a href=&#34;https://github.com/fohria/pysc2/blob/master/docs/environment.md#observation&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Basically, to get for example all available actions in the current game state (some actions may not always be available, if you do not have any selected units you don&#39;t have access to the &amp;quot;move unit&amp;quot; command) we can do this:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;available_actions &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observations&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;available_actions&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, now that you know that we have observations and actions, how do we put these together to make decisions? Let us look at the provided bots for inspiration and understanding.&lt;/p&gt;
&lt;h2&gt;Step 1: understanding the scripted bots&lt;/h2&gt;
&lt;p&gt;Our first thing to do is to understand the scripted agents that Deepmind has provided. We shall start with the BaseAgent class which is found in the pysc2/agents directory, as the example agents we shall look at later all inherit from this class. We will also use it as our base class when we construct our own agent in a later lesson.&lt;/p&gt;
&lt;h3&gt;Case study 1: class BaseAgent&lt;/h3&gt;
&lt;p&gt;What does the BaseAgent do? Let&#39;s take a look at the entire BaseAgent class:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;A base agent to write custom scripted agents.&#34;&#34;&#34;&lt;/span&gt;

&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; __future__ &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; absolute_import
&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; __future__ &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; division
&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; __future__ &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; print_function

&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; actions


&lt;span class=&#34;token keyword&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;token class-name&#34;&gt;BaseAgent&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;A base agent to write custom scripted agents.&#34;&#34;&#34;&lt;/span&gt;

  &lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs_spec&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; action_spec&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;episodes &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;steps &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;obs_spec &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs_spec
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;action_spec &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; action_spec

  &lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;reset&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;episodes &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;

  &lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;steps &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward
    &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first few lines are importing stuff from the future, in case you&#39;re running an older version of python. We don&#39;t really need to care about those. We&#39;re all using python3 now right?&lt;/p&gt;
&lt;p&gt;Anyway, the next line is slightly more interesting:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; actions&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The actions module is important, as it&#39;s from here we gain access to all the possible actions we can do like selecting units, moving units, looking around the map and so on. But maybe that was obvious. All available actions in the base version of pysc2 can be found &lt;a href=&#34;https://github.com/fohria/pysc2/blob/master/docs/all_actions.txt&#34;&gt;here&lt;/a&gt; and a general explanation &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md#actions&#34;&gt;here&lt;/a&gt; in the official documentation.&lt;/p&gt;
&lt;p&gt;Let&#39;s move on to some actual interesting stuff, namely the BaseAgent class itself and the setup function:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;token class-name&#34;&gt;BaseAgent&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;A base agent to write custom scripted agents.&#34;&#34;&#34;&lt;/span&gt;

  &lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;setup&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs_spec&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; action_spec&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;episodes &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;steps &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;obs_spec &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs_spec
    self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;action_spec &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; action_spec&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The setup function is called by the framework to create an instance of the agent as we launch the game itself. It sets up internal variables for the total amount of points for reward, number of episodes and number of steps. Pretty straightforward.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;obs_spec&lt;/code&gt; and &lt;code&gt;action_spec&lt;/code&gt; are called from the environment run loop and are there because different environments may have different observation and action specifications. We don&#39;t really need to care about those right now.&lt;/p&gt;
&lt;p&gt;Next up is the reset function:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;reset&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;episodes &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is called by the &lt;code&gt;pysc2.env.run_loop&lt;/code&gt; before an episode starts, to increase the number of episodes this agent has experienced.&lt;/p&gt;
&lt;p&gt;Finally, we have the step function:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;steps &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;
  self&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward &lt;span class=&#34;token operator&#34;&gt;+=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;reward
  &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every step that &lt;code&gt;pysc2.env.run_loop&lt;/code&gt; (the environment) makes, the agent is sent the observations (&lt;code&gt;obs&lt;/code&gt;) made in that step. The agent increases the number of steps, increases the reward with the one observed in the environment (0 if last step did not lead to reward and 1 if the last step did lead to reward). It then takes the action&lt;br/&gt; &lt;code&gt;actions.FunctionCall(0, [])&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(For the observant and insightful reader you may wonder how many game frames that &lt;code&gt;obs&lt;/code&gt; contains, every 1 frame rendered by the game or what? Well, it&#39;s complicated. In short, each step size is related to actions per minute. We may go into further detail in a later lesson, but for now you can read &amp;quot;game and action speed&amp;quot; in the &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md#game-and-action-speed&#34;&gt;official documentation&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;We&#39;ll get back to what that action call means in a minute. First let me explain that what this function basically does is the same as if you imagine yourself going out, closing the door behind you and walk out onto the sidewalk to stand there, staring into thin air. That&#39;s what we&#39;ve gone through here, you walking out is the setup function. And now, you take a &amp;quot;step&amp;quot;. Which means, you look around, your senses make observations, and you perform an action. Maybe that action is to take an actual step down the street. Maybe you wave at your neighbor across the street. Maybe you turn around and go back home because the world is a scary place.&lt;/p&gt;
&lt;p&gt;How do you make the decision of what to do? Well, that&#39;s what neuroscience and psychology is trying to explain, so we won&#39;t go into that right now (even though this is also part of &lt;a href=&#34;http://iggi.org.uk/students/2016/henrik-siljebrat&#34;&gt;my research&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In our case, that part, the decision making part/logic is totally missing here. Which takes us to the action made here in BaseAgent:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how you make an action, and why we needed to import &lt;code&gt;actions&lt;/code&gt; from &lt;code&gt;pysc2.lib&lt;/code&gt; earlier. The &lt;code&gt;0&lt;/code&gt; is the action ID number and the brackets are the parameters for this action. Apparently, this action needs no parameters. If you&#39;ve got your terminal handy, you can write the following to see all possible actions:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python3 &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; pysc2.bin.valid_actions&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(If you use python2 you probably don&#39;t need the 3 there). In the output of that command, we get all actions, each action one line on the list starting from 0. Our function call is 0 (remember it was `return actions.FunctionCall(0, [])) so we only need to see the first few lines of that output:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python3 &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; pysc2.bin.valid_actions &lt;span class=&#34;token operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;&#34;&lt;/span&gt; &lt;span class=&#34;token operator&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token function&#34;&gt;head&lt;/span&gt; &lt;span class=&#34;token parameter variable&#34;&gt;-n&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m sure there&#39;s an easier way to do that but it&#39;s what I managed to put together when &lt;a href=&#34;/why-you-should-use-duckduckgo/&#34;&gt;using duckduckgo&lt;/a&gt; okay? That command won&#39;t work if you&#39;re on Windows so you&#39;ll just have to scroll up, sorry!&lt;/p&gt;
&lt;p&gt;In any case, we get the following output:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/no_op                                              &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;/move_camera                                        &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;/minimap &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;/select_point                                       &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;6&lt;/span&gt;/select_point_act &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/screen &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/select_rect                                        &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_add &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/screen &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;/screen2 &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;/select_control_group                               &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;/control_group_act &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;5&lt;/span&gt;/control_group_id &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;5&lt;/span&gt;/select_unit                                        &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;8&lt;/span&gt;/select_unit_act &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;9&lt;/span&gt;/select_unit_id &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;6&lt;/span&gt;/select_idle_worker                                 &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;10&lt;/span&gt;/select_worker &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_army                                        &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_add &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;8&lt;/span&gt;/select_warp_gates                                  &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_add &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;9&lt;/span&gt;/select_larva                                       &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the action ID is the number to the left, then we have the action name and to the right are the parameters for that action. So we see that we have the command &lt;code&gt;no_op&lt;/code&gt; being returned every time by the BaseAgent. &lt;code&gt;no_op&lt;/code&gt; being short for &amp;quot;no operation&amp;quot;. That also explains why it needs no parameters.&lt;/p&gt;
&lt;p&gt;In other words, BaseAgent does nothing. That&#39;s all right for a while you know, but what if you get hungry, just standing there on the sidewalk?&lt;/p&gt;
&lt;p&gt;We learned lots about the basic concepts of a bot, though, right?&lt;/p&gt;
&lt;p&gt;In the next chapter, we shall look at a so called scripted bot, which cannot learn but is specifically written for one of the mini games.&lt;/p&gt;
&lt;h3&gt;Case Study 2: class MoveToBeacon&lt;/h3&gt;
&lt;p&gt;The MoveToBeacon class is a bot written specifically for solving the mini game MoveToBeacon. This mini game is very simple; you have one marine and you need to move it to a beacon, a highlighted area on the map. The marine and beacon are always within one &#39;game screen&#39; so you don&#39;t need to scroll/pan around the map to find the beacon. When the marine steps onto the beacon, the agent receives a reward &lt;code&gt;1&lt;/code&gt; and the game restarts with the beacon in a new place. Every step taken that does not result in the marine walking onto the beacon the agent receives a reward of &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;post-insert&#34;&gt;
  &lt;a href=&#34;https://www.youtube.com/watch?v=6L448yg0Sm0&#34;&gt;&lt;img src=&#34;/img/sc2_minigame_video.png&#34; alt=&#34;link to youtube video of the minigames&#34;&gt;&lt;/a&gt;
  &lt;p&gt;Youtube video of four of the mini games, including the MoveToBeacon one. The video is not embedded, because the code to do that will inject tracking scripts and I don&#39;t want to subject my dear visitors to such nonsense. &lt;a href=&#34;https://www.youtube.com/watch?v=6L448yg0Sm0&#34;&gt;Click here&lt;/a&gt; to watch it on Youtube.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here&#39;s the whole first part of the &lt;code&gt;pysc2.agents.scripted_agents&lt;/code&gt; module, which contains some imports, some constant definitions and the MoveToBeacon class:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; numpy

&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;agents &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; base_agent
&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; actions
&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; features

_PLAYER_RELATIVE &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; features&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;SCREEN_FEATURES&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;player_relative&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;index
_PLAYER_FRIENDLY &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;
_PLAYER_NEUTRAL &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;  &lt;span class=&#34;token comment&#34;&gt;# beacon/minerals&lt;/span&gt;
_PLAYER_HOSTILE &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;
_NO_OP &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;no_op&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;
_MOVE_SCREEN &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;Move_screen&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;
_ATTACK_SCREEN &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;Attack_screen&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;
_SELECT_ARMY &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;select_army&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;
_NOT_QUEUED &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
_SELECT_ALL &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;


&lt;span class=&#34;token keyword&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;token class-name&#34;&gt;MoveToBeacon&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;base_agent&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;BaseAgent&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;An agent specifically for solving the MoveToBeacon map.&#34;&#34;&#34;&lt;/span&gt;

  &lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;token builtin&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;MoveToBeacon&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; self&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;step&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; _MOVE_SCREEN &lt;span class=&#34;token keyword&#34;&gt;in&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;available_actions&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
      player_relative &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;screen&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_PLAYER_RELATIVE&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
      neutral_y&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; neutral_x &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;player_relative &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; _PLAYER_NEUTRAL&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;not&lt;/span&gt; neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
        &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_NO_OP&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
      target &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_x&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
      &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_MOVE_SCREEN&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_NOT_QUEUED&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; target&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;token keyword&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
      &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_SELECT_ARMY&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_SELECT_ALL&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow, this looks way more complicated, right? Calm down, it&#39;s fine! Take a deep breath, relax, and we&#39;ll work this through together.&lt;/p&gt;
&lt;p&gt;First off, we import numpy:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; numpy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The convention is to do &lt;code&gt;import numpy as np&lt;/code&gt;. Which is what they do in &lt;code&gt;pysc2.lib.features&lt;/code&gt; so likely an example of different people coding different parts and they haven&#39;t really consolidated the code base properly. Which is why we&#39;re doing this tutorial/documentation because the whole thing feels slightly unfinished. Doesn&#39;t really matter though, it&#39;s just code nerdery. If you didn&#39;t know, &lt;a href=&#34;http://www.numpy.org/&#34;&gt;numpy&lt;/a&gt; is a library for mathematical functions. Linear algebra. Matrices. You know, stuff you calculate other stuff with.&lt;/p&gt;
&lt;p&gt;Next up, we import the &lt;code&gt;base_agent&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;agents &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; base_agent&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one we know! It&#39;s the class we looked at earlier, so we&#39;re familiar with what this does.&lt;br/&gt; &lt;em&gt;highfive!&lt;/em&gt; &lt;br/&gt;Moving on:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; actions
&lt;span class=&#34;token keyword&#34;&gt;from&lt;/span&gt; pysc2&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;lib &lt;span class=&#34;token keyword&#34;&gt;import&lt;/span&gt; features&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We went through the &lt;code&gt;action&lt;/code&gt; module earlier, as it&#39;s used in the &lt;code&gt;BaseAgent&lt;/code&gt; class. We need it to be able to call and perform actions. The &lt;code&gt;features&lt;/code&gt; module contains information about the feature layers; the observations we/the agent can make. This is not strictly needed, as we could enter things manually, but as you&#39;ll see presently, this way we make the code more flexible/dynamic.&lt;/p&gt;
&lt;p&gt;Now, let&#39;s go through the constant definitions one by one.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_PLAYER_RELATIVE &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; features&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;SCREEN_FEATURES&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;player_relative&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;index&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we assign a variable for the index of feature &lt;code&gt;player_relative&lt;/code&gt;. If you recall from earlier, the screen features can be accessed from the &lt;code&gt;obs.observation&lt;/code&gt; dictionary like so:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;screen&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;token comment&#34;&gt;# where 5 is the id for player_relative&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically, getting the index from the &lt;code&gt;features&lt;/code&gt; module like this and assigning a variable to it is equal to us just doing:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_PLAYER_RELATIVE &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what is &lt;code&gt;player_relative&lt;/code&gt; you ask? Well, if we look in the &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md#screen&#34;&gt;official documentation&lt;/a&gt;, the screen feature player_relative means;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;player_relative: Which units are friendly vs hostile. Takes values in [0, 4], denoting [background, self, ally, neutral, enemy] units respectively.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, what we get from &lt;code&gt;player_relative&lt;/code&gt; is a matrix of size (84, 84) representing the game screen, where 0 is background, 1 is self and so on.&lt;/p&gt;
&lt;p&gt;Now that you know that, the following three lines should be fairly obvious:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_PLAYER_FRIENDLY &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;
_PLAYER_NEUTRAL &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;  &lt;span class=&#34;token comment&#34;&gt;# beacon/minerals&lt;/span&gt;
_PLAYER_HOSTILE &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we assign variables/constants to the relevant features we are interested in to solve the MoveToBeacon mini game. Well, actually the hostile part is not used but it is defined here as &lt;code&gt;scripted_agent.py&lt;/code&gt; also contains classes for two other mini games. We&#39;ll get to those later. So, the two variables we are interested in right now are &lt;code&gt;_PLAYER_FRIENDLY&lt;/code&gt; and &lt;code&gt;_PLAYER_NEUTRAL&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_NO_OP &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;no_op&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember earlier when we used the terminal to find the &lt;code&gt;no_op&lt;/code&gt; action in the list of all actions? Here, if we know the name of the action we want to use, we can get its id (&lt;code&gt;0&lt;/code&gt;) by using the &lt;code&gt;actions&lt;/code&gt; module. This way, as long as this action will be called &lt;code&gt;no_op&lt;/code&gt; in the future, we don&#39;t need to remember its specific id number. It&#39;s also easier to read the code with a variable name than numbers everywhere.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_MOVE_SCREEN &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;Move_screen&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Move_screen&lt;/code&gt; action is not self explanatory, or at least it wasn&#39;t for me at first. It could mean move the game screen, which is what I first thought it meant. But actually, it means moving a selected unit to somewhere on the current screen. We can figure this out by looking at the definition in our terminal window:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python3 &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; pysc2.bin.valid_actions &lt;span class=&#34;token operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;Move_screen&#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which gives us the output:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;&lt;span class=&#34;token number&#34;&gt;19&lt;/span&gt;/Scan_Move_screen                                   &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/queued &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/screen &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;331&lt;/span&gt;/Move_screen                                        &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/queued &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/screen &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our case, it&#39;s the 331 we&#39;re looking for. To the right we see that it takes two arguments; &lt;code&gt;queued&lt;/code&gt; and &lt;code&gt;screen&lt;/code&gt;. The first is a boolean and indicates if the action should be taken now or after previous actions (more on that later). The second argument is a point/pixel on the screen, which is (84, 84) pixels big. So since it&#39;s a single pixel being asked for, it must be moving a unit to somewhere on the current game screen. And actually, this makes sense, as if we think about the feature layers, we have the two main categories of minimap and screen, remember? This &lt;code&gt;Move_screen&lt;/code&gt; command is likely the &amp;quot;move&amp;quot; command on the current &amp;quot;screen&amp;quot;. If that&#39;s true there should be a &lt;code&gt;Move_minimap&lt;/code&gt; as well. Let&#39;s see:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;python3 &lt;span class=&#34;token parameter variable&#34;&gt;-m&lt;/span&gt; pysc2.bin.valid_actions &lt;span class=&#34;token operator&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;grep&lt;/span&gt; &lt;span class=&#34;token string&#34;&gt;&#34;Move_minimap&#34;&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;20&lt;/span&gt;/Scan_Move_minimap                                  &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/queued &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;/minimap &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token number&#34;&gt;332&lt;/span&gt;/Move_minimap                                       &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/queued &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;/minimap &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hypothesis correct, yay! Let&#39;s move on.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_ATTACK_SCREEN &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;Attack_screen&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Move_screen&lt;/code&gt; command has the advantage of being used as an example in &lt;a href=&#34;https://github.com/deepmind/pysc2/blob/master/docs/environment.md#actions&#34;&gt;Deepminds documentation&lt;/a&gt;. &lt;code&gt;Attack_screen&lt;/code&gt; is not. But the parameters look the same as &lt;code&gt;Move_screen&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;&lt;span class=&#34;token number&#34;&gt;12&lt;/span&gt;/Attack_screen               &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;/queued &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;/screen &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;, &lt;span class=&#34;token number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, this should be the command to attack somewhere on the screen. In StarCraft II, if you press attack and then click a unit, that unit will be attacked. Quite obvious, I know. However, if you click attack and then somewhere on the screen, your unit(s) will go towards that point and attack anything they encounter on the way.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_SELECT_ARMY &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FUNCTIONS&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;select_army&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;id&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since you can have both army units and worker units in SC2, this command selects all army units which is useful when you want to consolidate all your army units or cannot select an area on the screen with the mouse without selecting workers. It only has one parameter:&lt;/p&gt;
&lt;pre class=&#34;language-shell&#34;&gt;&lt;code class=&#34;language-shell&#34;&gt;&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_army                 &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;7&lt;/span&gt;/select_add &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had to look through &lt;code&gt;pysc2.lib.actions&lt;/code&gt; to figure out what this was exactly, but it&#39;s a boolean denoting whether to add all army to current selection (True) or select all army units regardless of what is currently selected (False). So if you have a few workers selected and use &lt;code&gt;select_army&lt;/code&gt; with the &lt;code&gt;True&lt;/code&gt; flag, you&#39;d have all army units and those workers selected.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_NOT_QUEUED &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we create a variable for the parameter of the current action not being queued. As previously stated, I&#39;m not sure how this queue works. In &lt;code&gt;pysc2.lib.actions&lt;/code&gt; we find that:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;queued: Whether the action should be done now or later.&#34;&#34;&#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;queued&lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt;ArgumentType&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;enum&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token boolean&#34;&gt;False&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token boolean&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;token comment&#34;&gt;# (now vs add to queue)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, 0 (or False) as assigned to &lt;code&gt;_NOT_QUEUED&lt;/code&gt; means perform the action now, while True (1) means add to the queue. It could be that actions in the queue are automatically performed if the agent class step function is called without an action being returned. Could also be that actions in the queue are performed the next time the agent sends a &lt;code&gt;no_op&lt;/code&gt;. And another possibility is that this queue is only active during the same step, so that you can put a bunch of actions together and send them. Guess we need to experiment to know more, and I&#39;ll just move on for now because I don&#39;t think we need to worry too much about it at this point.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;_SELECT_ALL &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final constant defined is the parameter for the above mentioned &lt;code&gt;_SELECT_ARMY&lt;/code&gt; action. &lt;code&gt;_SELECT_ALL&lt;/code&gt; is not a great name, as 0 (False) means select all army units without adding current selection. Then again maybe the variable name works fine, if you read it as &amp;quot;select all army&amp;quot;. Anyway. Now it&#39;s finally time for the actual class &lt;code&gt;MoveToBeacon&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;If you want, take a breath and go pee or something. We got this far, now prepare for the real stuff.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;token class-name&#34;&gt;MoveToBeacon&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;base_agent&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;BaseAgent&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token triple-quoted-string string&#34;&gt;&#34;&#34;&#34;An agent specifically for solving the MoveToBeacon map.&#34;&#34;&#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class definition. We inherit from the BaseAgent class. Not much more to say.&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;token function&#34;&gt;step&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;self&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token builtin&#34;&gt;super&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;MoveToBeacon&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; self&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;step&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;obs&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to define the step function, as this is where all of our bot&#39;s behavior happens. It gets the &lt;code&gt;obs&lt;/code&gt; variable as input which is the variable containing all of the observations for that step. Then we call the same function in the parent class (BaseAgent) using &lt;code&gt;super&lt;/code&gt;. Why do we call the parent function? Well, if you remember from before (and if you don&#39;t just scroll up and look) the BaseAgent increases number of steps and reward every step. Using super here we can do that without explicitly writing those two lines ourselves. You can read more about super on &lt;a href=&#34;https://stackoverflow.com/questions/222877/what-does-super-do-in-python&#34;&gt;stackoverflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s look now at the entire rest of the code block and then break it down:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; _MOVE_SCREEN &lt;span class=&#34;token keyword&#34;&gt;in&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;available_actions&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  player_relative &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;screen&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_PLAYER_RELATIVE&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
  neutral_y&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; neutral_x &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;player_relative &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; _PLAYER_NEUTRAL&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;not&lt;/span&gt; neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_NO_OP&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
  target &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_x&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_MOVE_SCREEN&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_NOT_QUEUED&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; target&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;token keyword&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_SELECT_ARMY&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_SELECT_ALL&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s an outer if/else here, &lt;code&gt;if _MOVE_SCREEN in obs.observation[&amp;quot;available_actions&amp;quot;]&lt;/code&gt;. The &amp;quot;available_actions&amp;quot; contains, well, all available actions at this current observational step. If no units are selected, the move command will not be available. Makes sense, right? So if the move command is not available, we have no selected units, hence the &lt;code&gt;else: return actions.FunctionCall(_SELECT_ARMY, [_SELECT_ALL])&lt;/code&gt; as that will select all your army units. In the current context, the MoveToBeacon mini game, that means our lonely marine.&lt;/p&gt;
&lt;p&gt;Now, if we have our marine selected, we want to move it to the beacon. How do we find this beacon?&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;player_relative &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; obs&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;observation&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token string&#34;&gt;&#34;screen&#34;&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_PLAYER_RELATIVE&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
neutral_y&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; neutral_x &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;player_relative &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; _PLAYER_NEUTRAL&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We start on the first line here by getting the (84, 84) matrix for &lt;code&gt;_PLAYER_RELATIVE&lt;/code&gt;. If you remember from before, that will show 0 for background, 1 for where the marine is (self) and 3 where the beacon is (neutral). The next line gives us all the points in the (84, 84) matrix that are equal to 3 (equal to &lt;code&gt;_PLAYER_NEUTRAL&lt;/code&gt;) and that are not zero. As an example, consider the following small matrix:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;matrix &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; numpy&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(if you have your terminal ready you can open the python interactive prompt or use ipython to follow along and experiment for yourself if you&#39;re unsure of how this works)&lt;/p&gt;
&lt;p&gt;Imagine this 4x4 matrix is the game screen, instead of the usual 84x84 matrix we&#39;re actually working with. Each number in this 4x4 matrix is a pixel. And we see that the beacon covers a total of 4 pixels, the pixels saying &lt;code&gt;3&lt;/code&gt;. The marine covers one pixel in the upper left, that&#39;s the &lt;code&gt;1&lt;/code&gt;. If we use &lt;code&gt;nonzero&lt;/code&gt; on this we get:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;In&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; matrix&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
Out&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We get two arrays for the positions of nonzero values. The left array contains the row values and the right array contains the column values. So the marine for example is at position (0, 1) and can be accessed directly from &lt;code&gt;matrix&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;In&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; matrix&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
Out&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we only want the beacon, we don&#39;t care about where the marine is. So we can do:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;In&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; numpy&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;matrix &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
Out&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;In&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;matrix &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;
Out&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; array&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we get only the pixels where the beacon is! So to get the &amp;quot;upper-left&amp;quot; &lt;code&gt;3&lt;/code&gt; we can do:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;In&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt; matrix&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the main code above, they&#39;ve said:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;neutral_y&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; neutral_x &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;player_relative &lt;span class=&#34;token operator&#34;&gt;==&lt;/span&gt; _PLAYER_NEUTRAL&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;nonzero&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why y before x? Because usually if you look at most graphs, you put x on the horizontal line and y on the vertical. Since the left array are rows and the right array columns, by doing this we can think better since it&#39;ll be like any regular graph. Or something.&lt;/p&gt;
&lt;p&gt;Get it? Good. Otherwise, play around on your own with these functions, it helps when trying to get stuff like this to experiment you know.&lt;/p&gt;
&lt;p&gt;Now that we&#39;ve looked for where the beacon is, there&#39;s a test in case there&#39;s no beacon found:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;&lt;span class=&#34;token keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;token keyword&#34;&gt;not&lt;/span&gt; neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;:&lt;/span&gt;
  &lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_NO_OP&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If no beacon was found on the screen - if there are no &lt;code&gt;3&lt;/code&gt;s in the matrix - we send back a &lt;code&gt;no_op&lt;/code&gt; action.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;neutral_y&lt;/code&gt; did contain at least one &lt;code&gt;3&lt;/code&gt; then we move onto the final two lines of code:&lt;/p&gt;
&lt;pre class=&#34;language-python&#34;&gt;&lt;code class=&#34;language-python&#34;&gt;target &lt;span class=&#34;token operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_x&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token builtin&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;neutral_y&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;mean&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;token keyword&#34;&gt;return&lt;/span&gt; actions&lt;span class=&#34;token punctuation&#34;&gt;.&lt;/span&gt;FunctionCall&lt;span class=&#34;token punctuation&#34;&gt;(&lt;/span&gt;_MOVE_SCREEN&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;token punctuation&#34;&gt;[&lt;/span&gt;_NOT_QUEUED&lt;span class=&#34;token punctuation&#34;&gt;,&lt;/span&gt; target&lt;span class=&#34;token punctuation&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;token punctuation&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The target is of course the beacon, and here we find the middle of that beacon by taking the mean value of the x and y coordinates where &lt;code&gt;3&lt;/code&gt;s were found. In the 84x84 matrix, the beacon covers around a 10x10 area I think.&lt;/p&gt;
&lt;p&gt;Finally, we return the action &lt;code&gt;_MOVE_SCREEN&lt;/code&gt; with the parameters &lt;code&gt;_NOT_QUEUED&lt;/code&gt; and the coordinates &lt;code&gt;target&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s it! Now we know how the scripted agent &lt;code&gt;MoveToBeacon&lt;/code&gt; works. More or less :)&lt;/p&gt;
&lt;p&gt;In the next post/chapter, we shall use what we learned to create an agent that learns how to solve this game without us specifying how it should do that. With the assumption that we basically only need the same few actions and observations that the &lt;code&gt;MoveToBeacon&lt;/code&gt; scripted agent uses, we will build or own bot using reinforcement learning. Maybe this assumption is wrong and we need more stuff, but whatever, we&#39;ll just hack that if/when we get there!&lt;/p&gt;
&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

          </description>
          <pubDate>Mon, 04 Sep 2017 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/building-bots-in-starcraft-2-for-psychologists/</link>
          <guid isPermaLink="true">https://gamescapad.es/building-bots-in-starcraft-2-for-psychologists/</guid>
          
          <category>starcraft</category>
          
          <category>pysc2</category>
          
          <category>python</category>
          
          <category>reinforcement learning</category>
          
          <category>bots</category>
          
          
          <category>tutorials</category>
          
        </item>
      
    
      
        <item>
          
            <title>why you should use duckduckgo</title>
          
          <author>foh@gamescapad.es (gamescapades)</author>
          <description>
            &lt;p&gt;see, they tell you it&#39;s about privacy. and sure, a search engine that doesn&#39;t track everything you do and cares about your privacy is great. but if you&#39;ve ever used it you know that the results are not always great.&lt;/p&gt;
&lt;p&gt;but you know what i just realized? &lt;a href=&#34;https://duckduckgo.com&#34;&gt;duckduckgo&lt;/a&gt; is better in some ways &lt;em&gt;because&lt;/em&gt; it doesnt always give you what you&#39;re looking for. at this point, you can likely press “i’m lucky” in google because it’s so personalized that it knows what you mean, even before you know you need it.&lt;/p&gt;
&lt;p&gt;not the case with duckduckgo. since the results are not always what you want, you may have to alter your query a few times. but if you look at the results, you can find weird things you find interesting that you wouldn’t have found otherwise. they may even give you new perspectives on things.&lt;/p&gt;
&lt;p&gt;the old interwebs was better because this was the experience everyone had. now we&#39;re all in our own information bubbles, never seeing anything unrelated to what we want.&lt;/p&gt;
&lt;p&gt;but you can still get a feel for how we used to search, thanks to duckduckgo.&lt;/p&gt;

          </description>
          <pubDate>Sun, 03 Sep 2017 02:00:00 +0200</pubDate>
          <link>https://gamescapad.es/why-you-should-use-duckduckgo/</link>
          <guid isPermaLink="true">https://gamescapad.es/why-you-should-use-duckduckgo/</guid>
          
          <category>search</category>
          
          <category>nostalgia</category>
          
          <category>makingyourlifedifficult</category>
          
          
        </item>
      
    
  </channel>
</rss>
