How to Learn Python the Competitive Way Part 11

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want a simple example of having to do some extra thinking to solve a problem against a timer.

The solution concepts were to follow on from Part 10 but with a more complex building task and compare manual and automated solutions. The automated solution wouldn’t be quite so obvious.

Background/Setup

Please see Part 1 for the Minecraft server set up.

The solution in practice…

We found a valley with steep sides that would make building more awkward than on flat land, and picked a side each. One side for manual building houses, the other side for automated build. We wanted to see how we would do with automating something more involved than the setting of blocks in a single simple shape that we were doing in Part 10.

Building manually got off to a quick start, though with some inconsistencies between the houses.

For the automated solution, we broke the problem of making lots of houses into three parts:

  1. Making a single house

  2. Working out what height the ground was for a given x, z coordinate so we could place the house on the ground rather than weirdly in the air or underground

  3. Looping through an x, z grid, and making use of the above to make a house on the ground at each x, z coordinate.

Working out how to do this breakdown was the first non-trivial aspect of this solution - we had an interesting conversation which started with The Apprentice saying, this is going to be super easy, though the houses will all be weirdly in the air. We confirmed that we had a requirement for the houses to be on the ground, with the justification that otherwise it would be too easy. This is probably the first of very many conversations about requirements in this programme.

Solving for making a single house was quick when we made use of the pattern we had from Part 4 where rather than build the walls individually, we built a solid block and then hollowed it out, this trick is the second non-trivial aspect of this solution and it was neat that a pattern from a previous session helped us out:

def make_house(x, y, z):
    mc.setBlocks(x, y, z, x + 5, y + 5, z + 5, 5)
    mc.setBlocks(x + 1, y + 1, z + 1, x + 4, y + 4, z + 4, 0)
    mc.setBlocks(x, y + 1, z + 3, x, y + 2, z + 3, 0)

Then to find the height of the ground, we decided to start high in the air and check downwards until we found a block that wasn’t of air type, the simplicity of this was the third non-trivial aspect of this solution:

def find_ground(x, z):
    for i in range(0, 200):
        y = 100 - i
        if mc.getBlock(x, y, z) != 0:
            return (x, y, z)

Looping through a grid to call the above was then essentially trivial:

def build_grid(x, z, spacing, house_count):
    for a in range(0, house_count):
        for b in range(0, house_count):
            l, m, n = find_ground(x + a * spacing, z + b * spacing)
            make_house(l, m, n)

There were a couple of limitations of our simple solution which we saw straight away - firstly because we started in the same place, we built another house on top of the first one:

And because our solution counted trees as not air and therefore a valid place to build, we got ourselves a treehouse:

In total it took about 5 minutes to realise how to break down the problem, 5 minutes to make the first house, then 5 minutes to put it together to make many houses. We’d expect with 5 more minutes we could have added an extra feature to solve for the weird placement of the houses, so for order of 9 houses we were well behind manual creation if we didn’t care about consistency of shape of the houses, but ahead if we did.

How to Learn Python the Competitive Way Part 10

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want a simple demonstration of the time benefits of using automation vs doing the work manually.

The solution concepts were to perform the same task manually and then automatically.

Background/Setup

Please see Part 1 for the Minecraft server set up.

The solution in practice…

Create a line of blocks as a player and time how long it takes, and then do the same using Python. Try different sizes. Then do the same for a square, then a cube. We asked The Apprentice how he thought he’d do, he thought anything less than about four blocks he’d be faster as a player.

Visualising the above on a linear scale is not very helpful:

Using log scales is a bit better but the diagram is still noisy:

Changing the x axis to be the total number of blocks rather than the length of a side gives us a clearer picture - if there are more than about 30 blocks in a simple shape, you’re better off using Python.

Other Considerations…

With the larger shapes, manual creation also introduced some accidental inaccuracies, for example creating a line 110 blocks long rather than 100 in the first attempt.

It’s very quick to change the block type of a large shape, for example from wood to TNT, where the command has already been written there’s an even bigger advantage to doing this using Python.

How to Learn Python the Competitive Way Part 9

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want a simple demonstration of coordinates from a first person point of view.

The solution concepts were to use two computers and see the live effect on the point of view of the player when changing the coordinates programmatically from another computer.

Background/Setup

Please see Part 1 for the Minecraft server set up.

The solution in practice…

Connect one computer to the server in the Python session, and connect the other using the Minecraft client.

Take a look at the current view of the player:

Get the current position of the player:

x, y, z = mc.player.getPos()

Type the following to change the position of the player vertically, but don’t press enter:

mc.player.setPos(x,y+50,z)

While looking at the Minecraft first person view, press enter on the above command to see the effect of changing position:

Increate the vertical position further:

mc.player.setPos(x,y+100,z)

To get an understanding of the effect of the x and z coordinates, look down:

Change the x and/or z coordinates and see the effect:

mc.player.setPos(x+100,y+100,z+10)

How to Learn Python the Competitive Way Part 8

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want to crank up the pressure on an easy task.

The solution concepts were to add the graphical aspects back in on the concept from Part 7.

Background/Setup

Please see Part 1 for the Minecraft server set up.

The solution in practice…

In Part 7 we had the server ask a question and we had to execute a simple command in response before the time ran out. In Part 8 we use a similar question/response approach and we visualise the time running out as blocks disappearing from a platform we are standing on, and if we don’t answer in time we get dropped into a pool of lava.

import time
import random
from mcpi.minecraft import Minecraft
mc = Minecraft.create("localhost", 4711)
(x, y, z) = mc.entity.getPos(mc.getPlayerEntityIds()[0])
# create lava
mc.setBlocks(x-5,y-4,z-5,x+15,y-4,z+5,11)
score = 0
qcount = 10
for n in range(0, qcount):
    a = random.randint(1,5)
    b = random.randint(1,5)
    c = a * b
    mc.postToChat("Question " + str(n+1) + " of " + str(qcount) + ": " + str(a) + "x" + str(b))
    # recreate platform
    mc.setBlocks(x, y - 1, z, x + 10, y - 1, z, 1)
    for q in range(0,11):
        points = (10-q)
        # remove a block from the end of the platform
        mc.setBlock(x+10-q,y-1,z,0)
        time.sleep(3)
        if mc.getBlock(0,0,0) == c:
            score += points
            mc.postToChat("Correct! " + str(points) + " points! Your score is now " + str(score))
            break

In the session used for giving the responses, we set up a simple function to make giving the answer more efficient.

from mcpi.minecraft import Minecraft
mc = Minecraft.create("localhost", 4711)
def answer(answer_value):
    mc.setBlock(0,0,0,answer_value)





How to Learn Python the Competitive Way Part 7

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want to crank up the pressure on an easy task.

The solution concepts were to set aside the graphical aspects and get The Apprentice to read instructions and type responses at short notice.

Background/Setup

Please see Part 1 for the Minecraft server set up.

The solution in practice…

Start the server and run the following program.

import time
import random
from mcpi.minecraft import Minecraft
mc = Minecraft.create("localhost", 4711)
score = 0
qcount = 10
for n in range(0, qcount):
    a = random.randint(1,5)
    b = random.randint(1,5)
    c = a * b
    mc.postToChat("Question " + str(n+1) + " of " + str(qcount) + ": " + str(a) + "x" + str(b))
    for x in range(0,10):
        points = (10-x)
        mc.postToChat(str(points))
        time.sleep(5)
        if mc.getBlock(0,0,0) == c:
            score += points
            mc.postToChat("Correct! " + str(points) + " points! Your score is now " + str(score))
            break

Have The Apprentice read the posted chat messages from the above script and submit the responses.

The Apprentice kept up fine with the fairly slow rate set on the program, though he managed to cause some error messages by accidentally setting the block ids negative, and the typing got messy towards the end. He was using the up arrow and editing the previous command.

[21:31:49] [Server thread/INFO]: Question 1 of 10: 2x3
[21:31:49] [Server thread/INFO]: 10
[21:31:54] [Server thread/INFO]: 9
[21:31:59] [Server thread/INFO]: 8
[21:32:04] [Server thread/INFO]: 7
[21:32:09] [Server thread/INFO]: Correct! 7 points! Your score is now 7
[21:32:09] [Server thread/INFO]: Question 2 of 10: 2x3
[21:32:09] [Server thread/INFO]: 10
[21:32:14] [Server thread/INFO]: Correct! 10 points! Your score is now 17
[21:32:14] [Server thread/INFO]: Question 3 of 10: 5x1
[21:32:14] [Server thread/INFO]: 10
[21:32:19] [Server thread/INFO]: 9
[21:32:24] [Server thread/INFO]: Correct! 9 points! Your score is now 26
[21:32:24] [Server thread/INFO]: Question 4 of 10: 5x4
[21:32:24] [Server thread/INFO]: 10
[21:32:29] [Server thread/INFO]: 9
[21:32:30] [Server thread/WARN]: [RaspberryJuice] Error occured handling command
[21:32:30] [Server thread/WARN]: java.lang.IllegalArgumentException: Material cannot be null
[21:32:30] [Server thread/WARN]: 	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:145)
[21:32:30] [Server thread/WARN]: 	at org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.setType(CraftBlock.java:182)
[21:32:30] [Server thread/WARN]: 	at org.bukkit.craftbukkit.v1_19_R1.legacy.CraftEvil.setTypeIdAndData(CraftEvil.java:69)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RemoteSession.updateBlock(RemoteSession.java:504)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RemoteSession.updateBlock(RemoteSession.java:493)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RemoteSession.handleCommand(RemoteSession.java:164)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RemoteSession.handleLine(RemoteSession.java:133)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RemoteSession.tick(RemoteSession.java:113)
[21:32:30] [Server thread/WARN]: 	at net.zhuoweizhang.raspberryjuice.RaspberryJuicePlugin$TickHandler.run(RaspberryJuicePlugin.java:167)
[21:32:30] [Server thread/WARN]: 	at org.bukkit.craftbukkit.v1_19_R1.scheduler.CraftTask.run(CraftTask.java:82)
[21:32:30] [Server thread/WARN]: 	at org.bukkit.craftbukkit.v1_19_R1.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:415)
[21:32:30] [Server thread/WARN]: 	at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1245)
[21:32:30] [Server thread/WARN]: 	at net.minecraft.server.dedicated.DedicatedServer.b(DedicatedServer.java:394)
[21:32:30] [Server thread/WARN]: 	at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:1197)
[21:32:30] [Server thread/WARN]: 	at net.minecraft.server.MinecraftServer.v(MinecraftServer.java:1013)
[21:32:30] [Server thread/WARN]: 	at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:293)
[21:32:30] [Server thread/WARN]: 	at java.base/java.lang.Thread.run(Thread.java:833)
[21:32:34] [Server thread/INFO]: 8
[21:32:39] [Server thread/INFO]: Correct! 8 points! Your score is now 34
[21:32:39] [Server thread/INFO]: Question 5 of 10: 4x3
[21:32:39] [Server thread/INFO]: 10
[21:32:44] [Server thread/INFO]: 9
[21:32:49] [Server thread/INFO]: 8
[21:32:54] [Server thread/INFO]: Correct! 8 points! Your score is now 42
[21:32:54] [Server thread/INFO]: Question 6 of 10: 4x5
[21:32:54] [Server thread/INFO]: 10
[21:32:59] [Server thread/INFO]: 9
[21:33:04] [Server thread/INFO]: Correct! 9 points! Your score is now 51
[21:33:04] [Server thread/INFO]: Question 7 of 10: 5x3
[21:33:04] [Server thread/INFO]: 10
[21:33:09] [Server thread/INFO]: 9
[21:33:14] [Server thread/INFO]: Correct! 9 points! Your score is now 60
[21:33:14] [Server thread/INFO]: Question 8 of 10: 3x1
[21:33:14] [Server thread/INFO]: 10
[21:33:19] [Server thread/INFO]: 9
[21:33:24] [Server thread/INFO]: 8
[21:33:30] [Server thread/INFO]: 7
[21:33:35] [Server thread/INFO]: 6
[21:33:40] [Server thread/INFO]: 5
[21:33:45] [Server thread/INFO]: 4
[21:33:50] [Server thread/INFO]: Correct! 4 points! Your score is now 64
[21:33:50] [Server thread/INFO]: Question 9 of 10: 5x4
[21:33:50] [Server thread/INFO]: 10
[21:33:55] [Server thread/INFO]: 9
[21:34:00] [Server thread/INFO]: 8
[21:34:05] [Server thread/INFO]: 7
[21:34:10] [Server thread/INFO]: 6
[21:34:15] [Server thread/INFO]: 5
[21:34:20] [Server thread/INFO]: Correct! 5 points! Your score is now 69
[21:34:20] [Server thread/INFO]: Question 10 of 10: 5x4
[21:34:20] [Server thread/INFO]: 10
[21:34:25] [Server thread/INFO]: Correct! 10 points! Your score is now 79

How to Learn Python the Competitive Way Part 6

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you want a live demonstration of ranges and coordinates.

The solution concepts were following on from Part 5, specifically we realised when drawing the chessboard that it would be fun to see it build up rather than have it appear, and speculated that might give a better understanding of what the computer was doing.

Background/Setup

Please see Part 1.

The solution in practice…

Start the server and have a Minecraft player join on one computer, and then on another computer connect the Python client. This allows you to see what the script is doing as soon as it starts.

Run the following and watch the output:

# First example - viewed from above
for i in range(0, 10):
    c = {'red': 14, 'orange': 1, 'yellow': 4, 'lime': 5, 'lightblue': 3, 'blue': 11, 'magenta': 2}
    j = 0
    for k in c:
        mc.setBlock(x + i, y, z + j, 35, c[k])
        time.sleep(0.5)
        j += 1

You can see it progress to build up the shape and look around it while it does.

Changing y instead of z to change the orientation:

# Second example - viewed from the side
for i in range(0, 10):
    c = {'red': 14, 'orange': 1, 'yellow': 4, 'lime': 5, 'lightblue': 3, 'blue': 11, 'magenta': 2}
    j = 0
    for k in c:
        mc.setBlock(x + i, y - j, z, 35, c[k])
        time.sleep(0.5)
        j += 1

Looping through x, y and z to create a block:

# Third example - block
for i in range(0, 10):
    c = {'red': 14, 'orange': 1, 'yellow': 4, 'lime': 5, 'lightblue': 3, 'blue': 11, 'magenta': 2}
    j = 0
    for k in c:
        for m in range(0, 10):
            mc.setBlock(x + i, y - j, z + m, 35, c[k])
            time.sleep(0.5)
        j += 1

Once the block has been put by the script, it can be interacted with in the usual way, allowing you to remove blocks…

… or cut into the shape to reveal the structure inside.

How to Learn Python the Competitive Way Part 5

You may find the following useful if you need to train up a colleague/employee/apprentice/student or yourself to be good under pressure at simple coding activities, and you need a simple demonstration of ranges and coordinates.

The solution concepts were following on from Part 4.

Background/Setup

Please see Part 1.

The solution in practice…

Start the server and have a player join as in Part 1.

We want to build a chessboard, so we make a function:

def make_board():
   (x, y, z) = mc.entity.getPos(1013)
   for a in range(0, 7):
       for b in range(0, 7):
           if (a + b) % 2 == 0:
               mc.setBlock(x + a, y, z + b, 49)
           else:
               mc.setBlock(x + a, y, z + b, 155)

Sometimes it’s more efficient to make something and see what’s wrong and fix it than to slow down and think some more and remember that the Python range function is half open, so we need to use (0,8) rather than (0,7) to get 8 squares wide. Or that actually we can use (8) instead of (0,8).

 def make_board():
   (x, y, z) = mc.entity.getPos(1013)
   for a in range(8):
       for b in range(8):
           if (a + b) % 2 == 0:
               mc.setBlock(x + a, y, z + b, 49)
           else:
               mc.setBlock(x + a, y, z + b, 155)

The main points to make are

  • The for loop over a range

  • Nesting one for loop inside another

  • Adding the coordinates and calculating mod 2 as a convenient way to alternate b between two options (setting a square to black versus to white)

It was then possible to play a game of draughts: