2
\$\begingroup\$

This is for a plugin I am making for the game called Minecraft. The code is responsible for finding out the blocks placed by the player and if they are in the following sequence as shown in the picture then create an Antenna. block in block.getType() returns the block placed by the player. Also, it doesn't matter in what order the player places the blocks.

enter image description here

// if block placed was a jukebox and block directly above is a diamond block
// and the block above the diamond block is an iron fence
if(block.getType() == Material.JUKEBOX 
        && block.getRelative(BlockFace.UP, 1).getType() == Material.DIAMOND_BLOCK
        && block.getRelative(BlockFace.UP, 2).getType() == Material.IRON_FENCE){
    System.out.println("Antenna Created");
    player.sendMessage("Antenna Created");
}

// if block placed was a diamond block and block directly above is a iron fence
// and the block below is a jukebox
if(block.getType() == Material.DIAMOND_BLOCK 
        && block.getRelative(BlockFace.UP, 1).getType() == Material.IRON_FENCE
        && block.getRelative(BlockFace.DOWN, 1).getType() == Material.JUKEBOX){
    System.out.println("Antenna Created");
    player.sendMessage("Antenna Created");
}

// if block placed was an iron fence and the block directly below is a diamond block
// and the block below that is a jukebox
if(block.getType() == Material.IRON_FENCE 
        && block.getRelative(BlockFace.DOWN, 1).getType() == Material.DIAMOND_BLOCK
        && block.getRelative(BlockFace.DOWN, 2).getType() == Material.JUKEBOX){
    System.out.println("Antenna Created");
    player.sendMessage("Antenna Created");
}

I am not happy with the following code and I get the feeling there is a better way to do this? I'm also wondering how would I go about designing these if Statements to allow for future extendibility?

\$\endgroup\$
  • \$\begingroup\$ Aren't you creating three antennas there? \$\endgroup\$ – kaoD May 29 '12 at 2:22
  • \$\begingroup\$ @kaoD no the three "Antenna Created" messages is duplicate code which I want to get rid of with a better design. \$\endgroup\$ – Jonathan May 29 '12 at 2:38
  • \$\begingroup\$ You just need ONE of those ifs, so actually the way to get rid of duplicated code is removing it. \$\endgroup\$ – kaoD May 29 '12 at 2:43
  • \$\begingroup\$ @kaoD It's a requirement to allow the antenna to be repaired, so say the middle block (diamond block) is destroyed replacing that block should re-create the antenna. The three if statements is to allow the player to build from any point and still create an antenna as long as the blocks are in that sequence. Also I plan on making the antenna longer so I'd like to know how to go about coding something that's scalable. \$\endgroup\$ – Jonathan May 29 '12 at 2:50
  • \$\begingroup\$ I have a feeling that you want to build some sort of shape map setup, with the ability to navigate from any placed block. When a block is placed, it looks up all 'shapes' that contain that block, then uses them as the 'root' to search from. You should then need to only store one 'map' of the completed object (although you'll probably want indexing for root search). Ideally, you could do something with repeating patterns or ranges, and possibly proportions (difficult). Since this should be query-only, it's also decently parallelizable. \$\endgroup\$ – Clockwork-Muse May 29 '12 at 17:56
3
\$\begingroup\$

As it is mentioned in the comments, It seems your code is exactly same as the below. So that is the first suggestion.

main = block.getType();
up1 = block.getRelative(BlockFace.UP, 1).getType();
up2 = block.getRelative(BlockFace.UP, 2).getType();
down1 = block.getRelative(BlockFace.DOWN, 1).getType();
down2 = block.getRelative(BlockFace.DOWN, 2).getType();


if ((main == Material.JUKEBOX && up1 == Material.DIAMOND_BLOCK && up2 == Material.IRON_FENCE)||
   (main == Material.DIAMOND_BLOCK && up1 == Material.IRON_FENCE && down1 == Material.JUKEBOX) ||
   (main == Material.IRON_FENCE && down1 == Material.DIAMOND_BLOCK && down2 == Material.JUKEBOX)) {
    System.out.println("Antenna Created");
    player.sendMessage("Antenna Created");
}

Now, as far as extendibility goes, You need to add newer conditions, it is not a good idea. What you have coded here is just an FSM (A state machine).

The easiest method to capture a state machine is to turn that into a regular expression. In this case, Say, the ordering is

up1 up2 main down1 down2

The conditions are

DIJ.. | I.DJ. | ..IDJ

So this captures your state machine fully. Adding future conditions is just as simple as adding to the above regular expression.

The code would look like

first(var) {
  return first_char(var)
}
string = { first(up1.toS()), first(up2.toS()),
           first(main.toS()),
           first(down1.toS()), first(down2.toS())};
re = new Regexp('DIJ..|I.DJ.|..IDJ')
if (re.match(string)) {
  player.send('Antena Created');
}
\$\endgroup\$
  • \$\begingroup\$ Hi thanks for your answer it's been very helpful. I also have been playing around trying to figure out a way (see my answer below). I got something working but I am wondering which of our solutions would be better to implement? \$\endgroup\$ – Jonathan May 29 '12 at 13:03
  • \$\begingroup\$ This FSM concept looks very intriguing. Looks very similar to something else that is implemented in the ModLoader library for this game. Definitely a +1. Now to figure out this awesome new toy. Shame its REGEX though :( \$\endgroup\$ – mseancole Aug 14 '12 at 0:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.