whydoitweet

I'm a Lecturer in Computer Science at Brunel University London. I teach games and research simulations. Views are my own :).

I wish you all an enjoyable holiday! But enough relaxation now, time for the Holiday Excellence Framework...

I was planning to pull out a few nice programming posts, but getting Brython to work in an interactive context turned out to be a bit trickier than I expected. I am trying to rebuild the walkabout town setting using it, but because it's a partial Python implementation in JavaScript, it has a couple of tricky caveats. Most notably, I frequently get JavaScript errors when I make mistakes in my Python code, which are much harder to diagnose than Python errors. In addition, some aspects like rendering images and handling controls are more unwieldy than in PyGame.

And yet the superior performance and the advantage of being able to use Coil does make me feel it's worthwhile to keep pursuing it. I just need to establish a strong and stable base library for the parts that I already presented in the previous GameWorld installments.

I will keep working on it, and you can see my current status here.

What does this mean for my code postings?

Well, inevitably my game package is not quite oven-ready and we're going to have to face a little bit more dither and delay. I could turn around and revoke my decision to use Brython, return to PyGame and perform a Brexit so to speak, but as you all know I am predominantly Remain.

So I'll have to go with some light-hearted non-code postings for the time being, and fortunately the Christmas holiday is not the worst time to have to do that. I can always look back, look forward, look sideways, look inwards, look outwards. Go meta on the meta posts, sprinkeled with an infusion of reflective abstraction.

Okay, bring on the meta!

Allright. Now, during work-time I am regularly confronted with immersive experiences like the Research Excellence Framework (best experienced through the incessant recital of their key mantra: Importance, Rigour, Originality), as well as the Teaching Excellence Framework (which doesn't have a mantra, but if it had one it could be: Strive for Excellent Student Satisfaction).

But enough about work, it's holiday! So I present to you, the Holiday Excellence Framework, funded of course by the Holiday Excellence Framework Council of England:

It's a pretty logo, they have a website too..

Now, as with the REF, we'll have to rank holidays on a scale from 0 to 4*. This is useful because it allows us to see what we need to have true holiday excellence!

So get our your holiday plans, work your way from top to bottom, and let's see how high you score on the Holiday Excellence Framework!

  • Right... if you're reading this but you have your work e-mail open in a tab next to this one, then I'm sorry, but your submission won't be eligible for the HEF, so an N/A.
  • If you're (a) celebrating Christmas on the 28th so that you can cram some work out, or (b) decided to replace work-related stress with household-work-related stress then you can do a token submission to the HEF. It'll be registered as 0 stars, and you may have concerns that you'll come out of the holiday any better than you came into it?
  • If you decided to take actual time off work (you know, taking at least a day of actual annual leave, not just doing a 'home day'), and have at least one non-weekend day without work, then congratulations! You are doing a excellent holiday that is Nationally Recognized! 1 star.
  • If you took time off work and actually bothered to set an auto-responder then you're up to an Internationally Recognized holiday! 2 stars. I know, the bar is high because can't all be excellent*
  • And if you actually made a plan in your holiday that includes an overnight stay outside of your house, then I can happily tell you that your holiday is Internationally Leading (3*).
  • To qualify for the highest ranking, you'll have to showcase that your holiday has importance, originality,** and rigour. If you think your holiday warrants the highest rating of being World-Leading (4*)***. Just for entertainment's sake, feel free to tweet to @whydoitweet your 4* holiday, and I'll gladly spread the word about your bleeding edge and world-shattering holiday!

Allright fellow HEFfers. Thank you for your time, and see you soon again!

Credits

Header image from pexels.com.

Footnotes

* Indeed, as you can see in the table here, 5 of the 128 universities in the UK rank below “internationally recognized” on average.

** Oxford comma deliberate, how can we be excellent without it?

*** Like 25% of all the REF paper submissions in 2014. Indeed, the World Leaders Lobby can be a little crowded at times in Excellence Framework land...

Read more...

Yes it does... having seen RileyQ's post about new Coil features, I noticed that there is now an integration for Coil with simmer.io, enabling people to monetize their Unity games.

(I edited this post to add information on how to clone this monetized Repl. I can't believe I forgot to include that!)

Now although I teach Unity as part of my work, I personally quite fancy coding my tutorials and games in Python 3, so I started looking whether I could get that working with repl.it on simmer.io.

The answer was unfortunately “not yet”. You can see the not-yet-at-all working example here.

But then I started looking further and further, trying to find means to get PyGame working in the browser. Now I found an abandoned library that could theoretically make it possible (here), but even the author warns against it's potential clunkiness.

However, during that search, I came across a toolkit called Brython, which enables the use of Python in the browser. In fact, I found a simple Repl.it template for it here.

So, using that I then started looking at the Brython examples, and was pleasantly surprised that it can handle graphics, controls, and even some 3D graphics quite smoothly in the browser!

Now this is disruptive for me, because with PyGame I never had been able to add a Coil pointer to my code examples. But with Brython it is now possible. I took the 2D breakout example, created a repl.it for it, added my coil pointer as a meta tag, and what I end up is now:

  1. A Fully-functioning Repl:

Which has the URL: https://repl.it/@djgroen/Monetized-brython-demonstration

2. A monetized web page that loads a playable game, using that same Repl:

Which has the following URL: https://Monetized-brython-demonstration.djgroen.repl.co

Edit: I forgot something very important!

You can find the Coil payment pointer in the index.html file of the Repl actually, on line 4:

Now if you want to make your own monetized game, simply fork my Repl, change the payment pointer address to match yours and you're all set!

So... what does this all mean?

Well, in a nutshell we can now create an open-source, freely forkable and monetized web-based game using Repl.it and Brython.

For my blog, I now face a sizable dilemma: will I stick with PyGame for future posts, or shall I go with Brython:

  • The Pro: Monetized games fit particularly well with Coil, so I think my tutorials might become more relevant to the Coil/XRP community if I go down this path.
  • The Con: Brython is a bit clunkier in coding than PyGame...

However, performance-wise Brython seems to do pretty well, while getting smooth performance has been a bit of a struggle with PyGame. So I think I'll have to take the red pill here and steam forward with Brython then! ;)

Read more...

Today, we are going to model a very simple explosion effect, which I think will be handy in future games. My platform of choice is still PyGame today, though I did like what I saw some others doing with Lua on Github (thanks go out to the staff picks here on Coil!)...

The Setup

To make a PyGame repl, you have to create a repl in the “Pygame” language (not Python, even though we're obviously writing Python):

Next up, we add three libraries to the top of our main file:

import pygame

import time

import random

We need the random library today, because I'd like to spawn objects in random places for this tutorial. Next up, we add the perhaps all-too-familiar initialization of the PyGame GUI:

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

Defining the explosions

To define what an explosion is, I created a simple class for it:

class Explosion:

def __init__(self, x, y):

self.x = x

self.y = y

self.F = 5000

def step(self):

self.F /= 2

Each explosion takes place on a given x and y coordinate, and has a certain intensity (F). Now since explosions are short-lived, I halve the intensity whenever a time step is taken.

This may look very simple, but please bear in mind that the actual exploding code is not in this class ;).

Defining the objects affected by the explosions

...instead, we'll incorporate that in the class that represents the objects that are pushed by any explosions. To have a few objects that bounce around in response to each explosion, I will reuse some code and materials from the Bouncy Ball tutorial. For starters, I'll use the basket ball images, and this familiar ball class:

class Ball:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.radius = 32

The location of this ball is at x and y, while the velocity in either direction is given by vx and vy. Our ball has a radius of 32, but you could easily change that if you use a differently sized image...

The part that gets a bit more complicated is the code to update the position of the ball by a time step. Here, we need to account for the following:

  • We need to make sure that each ball is pushed out by any effects from the explosion.
  • We need to make sure that each ball gradually slows down due to air resistance.
  • And lastly, we don't want balls to disappear, so we need to add code that makes them bounce of the edges of the screen.

All this leads to a chunky step function:

def step(ball):

..where we first update the positions based on the current velocities:

ball.x = ball.x + ball.vx

ball.y = ball.y + ball.vy

Next, we model the effect of each explosion (yes, you will be able to do multiple explosions :)):

for expl in explosions:

More distant explosions should have less effect on a ball, so we calculate a distance and put that in the denominator of any push effect.

dist = ((ball.x - expl.x)**2.0 + (ball.y - expl.y)**2.0)**0.5

temp = expl.F / dist**2.0

I chose to put the square of the distance in the denominator. I'm not so sure that that is physically realistic, but at least it creates a decent visual effect. Next, we update the velocities of the ball, given the force effect of our particular explosion.

ball.vx -= (expl.x - ball.x) * temp

ball.vy -= (expl.y - ball.y) * temp

Note that we use '–=' because every ball may be affected by multiple explosions! Next, we apply some air resistance, which I set to 0.9 in this code.

#apply air resistance

ball.vx *= e

ball.vy *= e

Just as a reminder, air resistance indicated the drag that any object has, and should be a number close to 1.0, but ideally less than 1.0. Lastly, I provide four code pieces to make sure the ball bounces off the sides of the screen:

# bounce bottom

if ball.y + ball.radius > height:

ball.vy = -ball.vy

ball.y = float(height) - ball.radius

# bounce top

if ball.y - ball.radius < 0:

ball.vy = -ball.vy

ball.y = float(ball.radius)

# bounce right

if ball.x + ball.radius > width:

ball.vx = -ball.vx

ball.x = float(width) - ball.radius

# bounce left

if ball.x - ball.radius < 0:

ball.vx = -ball.vx

ball.x = float(ball.radius)

I *think* this code is pretty simple and readable, but if not please do let me know as I'll be happy to add more explanations to it then!

Generating the objects

I'm keeping it simple by just randomly generating 3 balls within the confinements of the screen:

balls = []

for i in range(0,3):

balls.append(Ball(random.randint(32, width-32), random.randint(32, height-32), 5.0, 0.0))

...and loading the corresponding ball image for later use:

ball_img = pygame.image.load('ball.png')

Constructing the main time loop

As you will recall, almost every simulation needs a time loop, and this one is getting quite advanced. What we will need is:

  • means to add new explosions, by clicking the mouse somewhere.
  • explosions, which we advance in time (using step()) and which we display as yellow circles.
  • balls, which we also advance in time and which we display using the ball images.

So this is what it looks like. We make an infinite loop first:

while True:

and then capture any event that involves a mouse click in the game screen:

ev = pygame.event.get()

for event in ev:

if event.type == pygame.MOUSEBUTTONUP:

if we get such a click, then we record the position:

pos = pygame.mouse.get_pos()

and add an explosion on that position:

explosions.append(Explosion(pos[0], pos[1]))

Next, we will move to the first bit of drawing, so we clear the screen:

screen.fill(backgroundColor)

only to fill it up with circles, representing our explosions,

for k, expl in enumerate(explosions):

pygame.draw.circle(screen, (255, 255, 0), (expl.x-12, expl.y-12), 12, 0)

we also advance our explosions in time while we're at it anyway,

expl.step()

and remove any explosions that are too weak to be of any relevance to our simulation:

if expl.F < 1:

explosions.pop(k)

For our balls, we simply advance them in time, and then display them in the graphics buffer.

for b in balls:

step(b)

screen.blit(ball_img, (b.x-b.radius, b.y-b.radius))

And lastly, we render the whole thing to screen, and sleep for 25 milliseconds just to prevent the frame rate from getting too high:

pygame.display.flip()

time.sleep(25 / 1000)

Once you've done all that, your tutorial should be working, and you should have a screen like this:

When you click anywhere in the screen, a yellow circle will apear and the balls will move away from it (unless they bounce back). And if you click rapidly, then more circles appear and the balls will move more frantically!

Closing thoughts

The explosion code here is admittedly quite simple, and more geared towards use in games than for scientific animations. In particular, I thought it would be nice to add an interactive component to it, so that you can easily incorporate this code into simple games you may be working on.

Although Small Sims are self-sustaining, I may revisit this topic later on though, as explosions can come in many styles! For instance, one could consider adding structural damage to the objects, incorporating shock waves, create better color effects or resolve the physics of all this in a more realistic manner.

Below I'll provide the source code and a Repl as usual. Also, for subscribers I'll expand a bit more on why I decided to cover explosions in this particular tutorial :).

(Back to Small Sims Index)

Credits

Header image courtesy of pixabay.com.

Appendix A: Source code and Repl

The source code is here:

import pygame

import time

import random

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

e = 0.9 # air resistance coefficient

class Explosion:

def __init__(self, x, y):

self.x = x

self.y = y

self.F = 5000

def step(self):

self.F /= 2

explosions = []

class Ball:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.radius = 32

def step(ball):

ball.x = ball.x + ball.vx

ball.y = ball.y + ball.vy

for expl in explosions:

dist = ((ball.x - expl.x)**2.0 + (ball.y - expl.y)**2.0)**0.5

temp = expl.F / dist**2.0

ball.vx -= (expl.x - ball.x) * temp

ball.vy -= (expl.y - ball.y) * temp

#apply air resistance

ball.vx *= e

ball.vy *= e

# bounce bottom

if ball.y + ball.radius > height:

ball.vy = -ball.vy

ball.y = float(height) - ball.radius

# bounce top

if ball.y - ball.radius < 0:

ball.vy = -ball.vy

ball.y = float(ball.radius)

# bounce right

if ball.x + ball.radius > width:

ball.vx = -ball.vx

ball.x = float(width) - ball.radius

# bounce left

if ball.x - ball.radius < 0:

ball.vx = -ball.vx

ball.x = float(ball.radius)

balls = []

for i in range(0,3):

balls.append(Ball(random.randint(32, width-32), random.randint(32, height-32), 5.0, 0.0))

ball_img = pygame.image.load('ball.png')

while True:

ev = pygame.event.get()

for event in ev:

if event.type == pygame.MOUSEBUTTONUP:

pos = pygame.mouse.get_pos()

explosions.append(Explosion(pos[0], pos[1]))

screen.fill(backgroundColor)

for k, expl in enumerate(explosions):

pygame.draw.circle(screen, (255, 255, 0), (expl.x-12, expl.y-12), 12, 0)

expl.step()

if expl.F < 1:

explosions.pop(k)

for b in balls:

step(b)

screen.blit(ball_img, (b.x-b.radius, b.y-b.radius))

pygame.display.flip()

time.sleep(25 / 1000)

And the Repl is available here.

Read more...

Due to jet-lag, work pressures and the election the days started to blend into the nights. But the election result was a wake-up call.

On Day 3 (Wednesday) in Washington DC, the exhaustion started to kick in properly. I spent the day recovering, though I had a lot of work to catch up as well and the conference was still ongoing. With all the election drama around it was hard to focus, but in terms of what to expect I braced for the worst. I did meet a well-known ex-LibDem leader on the way back at the airport, which was a nice coincidence as my wife was delivering leaflets to support them at the very time I met him. So I went for a somewhat sleep-deprived pic:

Shortly after that, I conked out in the plane for 5.5 hours, dropped by at home to hang out with the family for half an hour, went straight into my project meeting, and then straight onto an election party that night. The wake-up call was only then.

The UK election result and my take on it

Quite quickly it became clear that the Conservatives won by a landslide, and indeed they now have an 80 seats majority. Here are some expert reactions, if you feel interested in reading those. And below I'll share my take:

Boris Johnson got 60% of the seats and now has a clear mandate to push through his Brexit deal. I am not a Brexit supporter, but this outcome may not be as bad is it could have been. Quite importantly, the Brexit party got stuck with 0 seats, while Johnson has such a large majority now that the extreme right wing of the Tories has largely lost their ability to sabotage deals that are overly soft.

At the same time, Labour got a terrible result which caused Corbyn to bail out of leadership in a future election. I think this is a good thing, because he was very polarizing as a leader, much more so than his party as a whole. His slogan “for the many not the few” became a bit of a double-entendre as I think both remainers and leavers felt disenfranchised by his confusing Brexit stance (negotiate a deal that he then would not back himself in a referendum). The controversy about his inconsistent handling of anti-semitism further indicated that there were more than just “the few” that he was not taking care of.

The Lib Dems came unstuck, losing a seat to stick to 11, which was surely lower than I expected. The vote share did go up by 4.2% (more than twice the growth of the Tories and the SNP combined), and the party racked up nice wins in St Albans and Richmond Park, but massive campaign resources have been sunk into key battlegrounds with prestigious ex-Tory and ex-Labour candidates, of whom none made it first past the post. It's a painful lesson, and I think many will find that it's far too simplistic to purely attribute these failures to any mistakes Jo Swinson may have made.

As for the other parties, the SNP made an impressive sweep if seats, I was a little bit disappointed that the Greens are still stuck to 1 seat, and there were interesting swaps in Northern Ireland for sure.

Closing thoughts

This is the last post I will make about the election / politics for a while. Boris Johnson is now PM with a big majority, and Brexit will happen in one form or another, irrespective of anyone's current opinion of it. Also, making these posts can be challenging for me at times, as I'm not that much of an expert in politics...

There are other areas to cover from this special week in December, and I may make a separate post about that in the coming days. Or I might just make a new edition of Small Sims or Game World again. We'll see what I will feel like by then! ;)

For the subscribers I share a little insight from my personal campaigning experience in this election.

Credits

Header image courtesy of bbc.co.uk.

Read more...

Today I gave my own talk, and I joined a panel to discuss about hybrid simulation and the data science / ML hype. I'll also cover a paper that came out just today and share a bit about the election again. Let's see if it's of any interest to you :).

Rise and shine

Another early start for me, courtesy of the jet-lag, but at least the 3:30-8:30 time frame gave me a nice period to finish all my slides and catch up (at least partially) with my e-mails...

Meanwhile, on the home front, my oldest daughter joined in for a nativity play, which I only partially missed out on because Moqi

(my wife) sent over quite a few videos of it :).

Bring me a panel

Later that morning, I featured in a panel about Hybrid Simulation (see yesterday's post about what that is). The panel was lively and we all had 10 minutes to present our viewpoints.

Picture of Nav Mustafee from the University of Surrey presenting his viewpoint.

My viewpoint is that individual models should be small (hence e.g. the Small Sims series!), and that we need very simple and flexible tools to combine many of them. In that way, it's easy to replace unnecessary or outdated models, and to experiment with different variations of your simulation. Others had often complementing viewpoints, for instance about the benefits of creating hybrids of simulation with machine learning models, or to ensure that any hybrid model is documented sufficiently so that it can be reproduced. There were no huge disagreements throughout the discussion, but it was good to see that one point retained broad support, which is that (and I paraphrase):

Machine learning and AI will never fully conquer the simulation world, because there will always be areas where the underlying training data has unknown bias, insufficient quality or is lacking altogether.

What was interesting though, is that at that very same morning, our second journal article on forced migration modelling finally made it to the press...

Paper hot off the press

It took us a while to publish it, but our paper on modelling forced migration in the South Sudan conflict got published today. We chose to publish in the Journal of Artificial Societies and Social Simulation (JASSS), which is particularly interesting because it does not charge anyone for reading the article, nor for writing the article. This model is called “Diamond open access”, and it normally relies on some rich organization bank-rolling the whole effort. However, in the case of JASSS they try to survive on voluntary author fees, which we plan to pay actually :).

The paper is a bit different from our previous ones in that we try to model the effect of some policy decisions, like closing a border or changing the size of a particular camp. Also, we made some progress in automating the execution and analysis of it all :). Now, I can't quite wrap up this topic without sharing at least the location graph, which I think is always interesting to look at:

Courtesy of our paper in JASSS of course.

UK Election Developments

Less drama today than yesterday, though the pessimism and gloominess seems to have spread. The Labour shadown health minister Jonathan Ashworth was caught in a leaked document mocking the chances of a Labour victory to a “close Tory friend”.

Jonathan Ashworth. Photograph: Peter Summers/Getty Images

Meanwhile, the bookies are turning ever gloomier, giving about equal odds now on Labour getting about 230 seats and the Lib Dems about 20, while the Conservatives have equal odds around the 350 mark. If that “poll” becomes reality then Boris Johnson will have little to fear, and the nightmare of Brexit (including the threat of a no-deal crashout) will once more proceed. Many people are now urging many other people to vote tactically, but the actual uptake of that appears to be quite limited. So, no reason to get our hopes up now in that area.

Also, a gem is this article from the BBC about fake ads. In it, it's mentioned that “for the Conservatives, it said that 88% (5,952) of the party's most widely promoted ads either featured claims which had been flagged by independent fact-checking organisations including BBC Reality Check as not correct or not entirely correct.”.

That's 12% of true advertisement for you: arguably a randomly typing monkey could do better?

Source: *Scotland Herald*.

And lastly, just when I am about to post this, Boris Johnson is caught dodging an interview by unsubtly hiding in a fridge. It's not a good look at all, but will it have any effect on Thursday?

For subscribers, I'll talk a bit about what comes tomorrow, and a few smaller aspects that I feel would perhaps be a bit too much for the main article.

Previous: Day 1

Read more...

Welcome to my Day 1 report of the Special Week in December (SWiD). Today I will cover my arrival at WinterSim, talk about a few definitions and cover some tidbits about the upcoming nightm... I mean election!

(note, my pictures are without filters. I'm trying to bring life as it is, not as it should be I suppose)

Arrival at WinterSim

The first morning of my first attendance ever at WinterSim started at a whopping 2:30 AM, as I was severely jet-lagged and still had to finish some marking for my games coursework. After doing that, I slept some more an went for a bit of a walk in National Harbor:

Yup... it's pretty deserted at 5:30 AM on a Monday morning. Having a jet-lag isn't so bad if you're in need of some peace and quiet ;).

The conference takes place in the Gaylord National Resort and Convention Center, and focuses squarely on simulation, which makes it interesting for this blog. In particular, they touch a lot upon agent-based simulations, which a main research interest of mine and which I also touched upon in e.g. this incredibly unpopular bar tutorial.

The conference has a special track on “hybrid simulation”, and as part of that we all had a big discussion on what hybrid simulation actually means. At other conferences (including ICCS, which I visit very often) people talk about multiscale simulation, multiphysics simulation or even coupled simulation. Now even senior academics are confused about all this, but actually it's really simple and I'll use this occasion to explain it.

The Multi-* Venn Diagram

Simply put, these terms relate to each other as follows in a Venn diagram:

Here, coupled simulations imply any simulation being combined (“coupled”) with something else. Technically, that something else doesn't even have to be a simulation, but could be a sensor network, a data source, or perhaps even a validation framework.

Within the coupled simulation definition, there are three subsets, which can all overlap. These are:

  • Multiscale simulations, where you have two or more models, each of which operates on a different length or time scale. Think of e.g. a grativy model of planets in the solar system coupled with a model stars in the Milky Way.
  • Multiphysics simulation, where you have to or more models, each of which captures different types physical phenomena. Think of e.g. a model of the air temperature in different areas of a living room combined with a model of people moving through that room.
  • Hybrid simulation, where you have to or more models, each of which uses a different computational technique. For instance, I could model people dropping pints in a bar by coupling my aforementioned horrible bar model with a bouncy ball model of a pint bouncing on the ground. It's a silly example, but it is a hybrid because the bar uses an agent-based modelling technique, while the bouncing model uses a particle-based gravity modelling technique.

Anyway, that is how I think they relate, and many people I spoke to yesterday were inclined to agree, once I explained it.

Other WinterSim tidbits

Aside from that, I chaired a session on Hybrid modelling, where for instance Christopher Davis from Portland State University explained how you can combine fuzzy cognitive maps with agent-based models:

Now that sounds very abstract, but cognitive maps are usually represented as a Causal Loop Diagram, with arrows simply implying which things have an influence on each other. Here's a simple example:

Courtesy of FCMappers.net, where they also *explain fuzzy cognitive maps in depth*.

There was also a very applied talk about modelling the terminal of the Eurostar train, to help prevent excessive queuing for passengers:

This guy, William Jones from Kent Business school, used a commercial software package called AnyLogic to model passengers moving through the terminal, and managed to help improve the speed of access for passengers by about 20% in one particular case. It's an example where simulation can make a very big different, in part because Eurostar does an excellent job collecting data to help construct and test these simulations.

Later that day, there was a very interesting talk about modelling kidney transplantations, and we finished the evening with a reception, where my jet-lag began to kick in and my senses diminished...

Monday in Election World

Meanwhile, in the UK the polls are starting to look grimmer and grimmer. If I am to believe the polls, places where Labour had a foothold are starting to slip away, the LibDems are struggling in many areas as well while the Conservatives are en-route for an enormous majority.

A lot of the news coverage focuses on tactical voting, but the pink elephant in the room is of course those masses of Tory voters who need to realize that Boris Johnson doesn't keep his word.

Should we believe the polls? Well, often they are biased in unknown directions and they have terrible sample sizes. Also, national percentages translate very poorly to seat numbers in Britain's First Past the Post system (see the Small Sims post about modelling that here), so the uncertainty is enormous.

But at the same time, the polls altogether are painting a consistently grim picture over the last week, and we should take into account that the reality could actually be worse, not better, than these polls indicate.

And yet it's not election day yet, and surprising things can and do still happen. For example, Boris Johnson made a monumental gaffe in this interview by refusing to view a picture of a boy forced to sleep on the floor of a hospital, and then even pocketing the phone of the journalist (!).

The gaffe is painful to watch, but whether it's a big game changer remains to be seen. For the time being it may be the best for all our peace of mind not to expect too much positive news on this week's election.

Closing thoughts

Well, that wraps up Day 1. For subscribers I'll add a quick preview of Day 2!

Previous: Introduction

Next: Day 2

Read more...

This week is an unusual week for me. I am travelling to National Harbor in Maryland this week to attend the Winter Simulation Conference, then I will be attending a large meeting of the research project that I'm managing the technical activities of (VECMA), and lastly we'll have the actual General Election here in the UK on Thursday.

I truly doubt this will be a week like any other, so contrary to my normal habits I intend to give you an update every day over the next five days. There'll be a bit of simulation, a bit of politics, a bit of random stuff, and hopefully a lot of interesting insights for you guys :).

Enjoy and speak to you very soon!

Next: Day 1

Don't expect anything overly educational: I just feel like sharing some personal experiences on this topic...

...primarily because we wrote a media article this week, and the responses were, well...interesting.

Science for the general public

A lot of scientific research is funded by (a) student tuition fees, (b) public taxpayer money or © a combination of both. As such, most academics feel that they should give something back to the people that made their research to begin with. And I think that's a healthy sentiment :).

One way to do that is by writing a general interest article. That is, a write-up that includes some parts of our research work, but in a way that (hopefully) makes it interesting to a wider audience. I've written such articles on a range of topics, and this week we published one in the Conversation on modelling forced migration.

How is it done (the non-expert version)

I am no expert on this, but I feel compelled to share my personal experience on it anyway, as I've done a few :). Usually there are three ways that general interest articles emerge:

  1. The researchers issue a press release, which is then taken up by the media.
  2. The researchers write an article together with an editor of a particular news source.
  3. The researchers are interviewed by the media directly, which is then put in an article and spread around.

The three ways can result in very different articles, and the quality can differ greatly. Approach (1) tends to be heavily influenced by the researchers, so it often leads to articles that are often thoroughly checked, but might not have such widespread appeal. Approach (2) can vary a lot in quality and accessibility, because some news sources involve the researchers to a large extent, while others just take a blurb of text and make an article out of it. And approach (3) usually has little involvement with the researcher, other than checking if the statements in the resulting news item are at least reasonably correct (on live media like radio of course, that check can't really be done).

In our case, we've had articles go all across the board after one of us got interviewed. For instance, when we were modelling composite materials containing clay and polymers and my colleague James Suter got interviewed by it, the resulting article was this:

(Source: the Register, though the image comes from our Advanced Materials paper)

But there are also cases where the interviewer stayed much close to the content, e.g.:

Source: BNR news radio (apologies for the Dutch!)

It is very rare that a news item is a 100% complete and accurate representation of the underlying research project. Equally it's very rare that a particular piece of research appeals to the broad audience if it's presented in unaltered form. And that paradox is one of the reasons why it can be so hard to write a strong research article for the general public.

That all being said, sometimes we're not interviewed directly about the science at all, but about other matters such as combining work and private life. I've had that happen once:

Source: HPCWire (or was it my own camera? I honestly forgot...)

How is it received?

Quite frequently, academics appear in the media, continue with their work, and that's it for the time being. Sometimes, other journalists come back, ask for an interview or to help with an article, and the item gradually evolves and lives on for a while.

This week in our case we were encouraged by The Conversation to respond to comments made on our article, so I decided to do that. Our Conversation article got 8 or so comments, I responded to a bunch of them and overall I think it led to a reasonable sensible conversation.

However, in the meantime our article was also picked up by Yahoo News UK, where a whopping 173 comments appeared underneath it, mostly actually by people who deny climate change (either as a joke, seriously, or half of both), and even a couple who appear to believe in a flat earth! You can find that version of the article here, but be warned the comments are pretty extreme...

Before we move on, let's at least set the flat-earth myth straight here:

Source: *Vox.com article on arguing with flat-earthers*.

*(Global warming and climate change is here to stay too of course)*

I chose to respond briefly to the most popular comment, and time will tell whether that was wise or foolish (I'll keep you updated here...).

Closing thoughts

So as you can see, general articles about researchers and academics can go all over the place, and the reactions too can be all over the board. Often the reactions have very little (if anything) to do with the article itself, and I know that many articles from other academics have been misinterpreted in much more serious and harmful ways.

I do think the goal of sharing new findings with the wider audience justifies the potential misinterpretations that we all experience along the way. But it's tricky to decide whether it is also our responsibility to respond to all the misinterpretations that we may sollicit when we publish our articles. Especially for articles that get huge swathes of comments, that may be a little too much to ask for...

Read more...

The time has come to refactor our code! Okay, please don't fall asleep here, I can't keep things simple on this blog unless we refactor stuff together (!)...

In our previous tutorial, we made a game town with a sprite that could walk around and talk to people. Now I could build further and further on this, but this will lead to a mess of a code. So before we take more steps forward, we need to take a few steps back and refactor our code.

In this edition, we will focus on:

- Spinning off bits of code into separate libraries, to simplify main.py and especially the main loop in it.

- Reworking the background image into something more extensible.

Our starting point is the GameWorld-Town repl.it that we made in the last tutorial. Because we are going to modify quite a lot of code, I'm going to keep my explanations a bit higher level than before, but I hope you can take along some key refactoring tricks from all this :).

Spinning off the NPCs into a separate library

In our previous tutorial we created and visualized a set of three NPCs, and even created a class for it in the main file. However, there is still a lot of technical details in the main repl.it, which I'd like to have separate. To do so, I make a new NPC.py file with the following contents first:

import pygame

class NPC:

def __init__(self, x, y, txt, img):

self.x = x

self.y = y

self.txt = txt

self.img = img

self.sprite = pygame.image.load(img)

def collides(self, x, y):

"""

Return: True if sprite overlaps with (x,y),

False otherwise.

"""

if self.x - 24 < x < self.x + 24 and self.y - 48 < y < self.y + 48:

return True

return False

This class defines the NPC object in more detail. In addition to having the original fields, I also incorporated the code which detects whether the NPC collides (overlaps) with an object that's located at coordinates (x,y). That way, we can leave out those details (which are not likely to change anytime soon) out of the main file.

For convenience I also want to make a class to run functions on all the NPCs in the town at the same time. To do that, I developed this NPCs class:

class NPCs:

def __init__(self):

self.npcs = []

def add(self, x, y, txt, img):

self.npcs = self.npcs + [NPC(x, y, txt, img)]

def detect_collision(self, px, py):

for k, e in enumerate(self.npcs):

if e.collides(px, py):

return k

return -1

def show(self, screen, x, y, width, height):

for i in self.npcs:

screen.blit(i.sprite, (i.x-x, i.y-y), area=(0, 100, 48, 48))

def txt(self, index):

return self.npcs[index].txt

This class has the following functionalities:

  • It can create an empty array of NPCs.
  • It can add an NPC easily, with a direct add() function.
  • It can detect whether an object at (x,y) collides with any of the NPCs with a single function.
  • It can render all the NPCs to the screen.
  • It can pass back the text that corresponds to a given NPC ID number (this is passed back by the detect_collision() function).

Another big chunk of code in our original file was dedicated to the keypresses for movement, so let's spin that out to a separate file next!

Move Controls

To do this, I make a new file called MoveControls.py. Instead of making a class (which seems unnecessary), I simply make one large function that handles all the controls here. So the file then contains the following:

import pygame

def GetUpdatedMove(x, y, map_width, map_height):

keys = pygame.key.get_pressed()

newx = x

newy = y

newf = 0

if keys[pygame.K_LEFT]:

newx -= 5

newx = max(0, newx)

newf = 3

if keys[pygame.K_RIGHT]:

newx += 5

newx = min(newx, map_width)

newf = 1

if keys[pygame.K_UP]:

newy -= 5

newy = max(0, newy)

newf = 0

if keys[pygame.K_DOWN]:

newy += 5

newy = min(newy, map_height)

newf = 2

return newx, newy, newf

Now what I did here is remove the collision part (we refactored that in NPCs.py), but instead just return intended locations and facings whenever keys are pressed. We will only accept the new locations if there is no collision occuring, which we will check for in the main file.

Although I intended to just simplify the code, I actually improved it because the previous version allowed players to move diagonally into obstables, whereas this one doesn't. Sometimes simplifying code indeed can come with side-benefits :).

Next up is that background image...

Tiles

“Hey, where did your cool background image go? :(”

Yes, it's gone. Background images are nice, but it'll be very tedious to draw complete towns time and time again. What is much easier is to draw tiles (say of 48x48 pixels) and then to stitch them together to form a map (see above). Now, I kept the tiles super-simple (they're just colored squares) because I want to do a separate Coil tutorial on that later on. But at least as part of this refactoring, I can get some essential data structures for it in place :).

So the file is called Tiles.py, and I'll go through it in a bit more detail as it is new code. First we need two simple imports:

import numpy as np

import pygame

Next, we declare a class to contain all the tiles, with a constructor function:

class Tiles:

def __init__(self, xsize=40, ysize=40):

This function will construct a tilemap of xsize, ysize, that we can render to the screen, and that will contain an ID for each tile:

self.tiles = np.zeros((xsize, ysize), dtype=int)

Later on, the ID may map to all sorts of cool tile objects, but to keep it simple we now just map the ID numbers to a small color map:

self.tile_colors = [(0,255,0),(128,128,0),(0,0,255)]

Oh, and we want to have the tilesize defined as a constant too:

self.tilesize = 48

Now we can construct a Tiles object, we should also have a function to easily render it to the screen. This we will call show():

def show(self, screen, x, y, width, height):

First we calculate which tiles we actually need to show on the screen. This is based on the screen resolution (width x height) as well as the x and y position in world coordinates of the top left corner of the screen:

txstart = int(x/self.tilesize)

txend = int(np.ceil((x + width) / self.tilesize))

tystart = int(y/self.tilesize)

tyend = int(np.ceil((y + height) / self.tilesize))

Next, we build a loop to go through those tiles:

for i in range(txstart, txend):

for j in range(tystart, tyend):

In the loop, we calculate the starting x position (xtile) and y position of each tile, as well as its corresponding color:

xtile = i * self.tilesize - x

ytile = j * self.tilesize - y

color = self.tile_colors[self.tiles[i, j]]

And finally, we create a rectangle and draw it!

rect = pygame.Rect(xtile, ytile, self.tilesize, self.tilesize)

pygame.draw.rect(screen, color, rect)

With all that in place, we can now go back to the main file.

Main File Revamped!

Our revamped main.py file now looks as follows. We start with some imports:

import pygame

import time

import numpy as np

from NPC import NPCs

from Tiles import Tiles

import MoveControls

, followed by some initializations we've done before:

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

pl_img = pygame.image.load('seolean.gif')

map_width = 1920

map_height = 1920

tilesize = 48

Now, I've added some code to create a few colored tiles to the map. It's very basic, just for adding some slight variety...

# We add stuff!

tiles = Tiles(40, 40)

tiles.tiles[4, 4] = 2 # a small pond

tiles.tiles[:, 19] = 2 # a straight river

tiles.tiles[23:27, 23:27] = 1 # a dirt patch

tiles.tiles[6:7, 33:35] = 2 # a small lake

and of course, we want to add the NPCs again, which we now do like this (I hope this is more readable than the old code...).

npcs = NPCs()

npcs.add(400, 600, "Hello!", "seolean.gif")

npcs.add(900, 600, "Stay on your guard.","guard.png")

npcs.add(500, 1100, "I am doing archery, watch out for my arrows!", "archer.png")

We have some more constants for the Player and the font (which we didn't spin off in a separate file...yet).

x = 0

y = 0

px = 0

py = 0

f = 2 # 0 up, 1 right, 2 down, 3 left

show_text = False

npc_text = ""

pygame.font.init()

myfont = pygame.font.SysFont('Comic Sans MS', 30)

And I also made separate drawing functions for both the player and the text box, just to make the main loop look even simpler:

def DrawTextBox(screen, text):

pygame.draw.rect(screen, [136,136,136], pygame.Rect(100,520,600,75))

text_surface = myfont.render(text, False, (0, 0, 0))

screen.blit(text_surface, (105,525))

def DrawPlayer(screen, x, y, px, py):

screen.blit(pl_img, (px - x, py - y), area=(0, f * 50, 48, 48))

Now, here is the main loop. The old one was 59 lines, but you'll find this one is a lot shorter and simpler. And because many complicated things will be added around the main loop, I especially wanted to simplify this part in my refactoring :). Here is what it looks like:

while True:

for event in pygame.event.get():

if event.type == pygame.QUIT:

break

# 1. movement and collision

newx, newy, f = MoveControls.GetUpdatedMove(px, py, map_width-tilesize+1, map_height-tilesize+1)

coll = npcs.detect_collision(newx, newy)

if coll == -1:

px = newx

py = newy

show_text = False

else:

show_text = True

npc_text = (npcs.txt(coll))

# 2. calculate screen offset

x = max(0, min(px - int(width/2), map_width-width))

y = max(0, min(py - int(height/2), map_height-height))

# 3. draw and render

tiles.show(screen, x, y, width, height)

DrawPlayer(screen, x, y, px, py)

npcs.show(screen, x, y, width, height)

if show_text:

DrawTextBox(screen, npc_text)

pygame.display.flip()

time.sleep(20 / 1000)

It's 30 lines in total (about half the size), and if you have followed the previous tutorial as well as this one, you'll find that it's now pretty much self-explanatory.

Closing thoughts

Making a more modular code and a simpler main loop was exactly what I intended to achieve, and I hope you spotted some nice refactoring tricks along the way.

When refactoring, there are a few simple aspects to keep in mind:

  • Make sure that you spin off parts of the code that are relatively self-contained.
  • Make sure you simplify that part of the code that you think you will be interacting with / developing on the most.
  • Always test as you refactor, don't wait until the end.
  • There's no need to be wedded to conventions. Object orientation is often useful, but sometimes a single method (like with the MoveControls) can do the trick to. Also, because of the layout of repl.it, I actually find that 2-space indentation gives more readable code, even though coding convention enforcement plugins keep shouting at me to do 4-space indentation ;).

With all that being said, all that remains from me is a link to the Repl (see below), and a bit of a preview about future editions for the subscribers. See you next time! :)

Credits

Header image courtesy of Wikipedia user Xarawn, showcasing the role of refactoring.

Appendix A: The Repl

Here it is :).

Read more...

Read more...