mailto: blog -at- heyrick -dot- eu

Navi: Previous entry Display calendar Next entry
Switch to desktop version

FYI! Last read at 03:09 on 2024/11/24.

Winter Solstice

It's the Winter Solstice today (at 23:23 CET), and very nearly a Full Moon. Well, the days will be starting to get longer, so it's the long slog towards summer and the good weather. Remember that when the wind changes direction and it's -5°C outside...

 

Advent calendars

Have you been watching my Advent Calendar openings? There's a YouTube playlist link on the right. Or, click here if you're using the mobile view...
There're only three days to go! And some of the stuff uncovered so far has been a little... odd... Many many flags and a moose - when's the last time you saw a moose at a hockey game? Plus the comedic value of Celebrations putting the tiniest chocolate into the biggest hole. I guess "cutbacks" or "it's the economy stupid"? ☺

 

Drone pests

So some idiot (idiots?) seem to think it's a good idea to clog up Gatwick airport with drones. The government wants to use this as an excuse to have all drones licenced (which will work about as well as CB licences) while the Independent showed a picture of a large quad-copter carrying a DSLR under it. If that was a real photo and not a Photoshop job, it indicates that the sort of foaming-at-the-mouth headlines as published in Bloomberg ("Your Favorite Holiday Gift Is a Danger to the Public", subheading "Drones in the hands of hobbyists are a menace") are likely deliberately missing the point.
No, Bloomberg, drones in the hands of assholes are a menace.
But, then, one could say the same for cars and knives and bricks...

There are three types of aircraft calling themselves drones. The first are little drones like mine. These are the typical Christmas present drone and they offer a range typically less than 100 metres. In other words, incapable of making it to the runway from any of the boundary gates of most airports.
The second type are the long range semi-pro models. These cost rather more and offer the ability to pilot them over several kilometres, these days often with FPV cameras so the operator can see from the perspective of the drone. These sorts of craft ought to already require a licence because there's a fairly good chance that it will not be piloted with a nearby line-of-sight from the operator at all times.
The final type of drone are the ones that contain an onboard computer (Arduino, Pi, something of that nature) and a GPS receiver, and they move themselves to programmed way-points by themselves. I have no issue with these requiring a licence, a beacon, and insurance - because they control themselves.

Now, what the authorities should do when there is a definitive sighting is to try to sniff out common control radio frequencies. If a drone can receive radio frequencies, so can a scanner. When the frequency is known, blitz it (and tough crap if it disconnects every mobile conversation in a five mile radius) until the drone falls out of the sky. Then disable the thing using whatever method is the most satisfying.

If there is no control signal, if this thing is following a pre-programmed trajectory, then that's getting close to an act of terrorism. People do not send an autonomous drone into the airspace of a major airport as an "oops, my bad". That's intentional and designed to create havoc, as indeed is happening.
Having said that, it's happened enough now that there's little way that we can think of it as anything either than intentional.

 

"Stupid woman"

+1

That's all.

 

Designing software

On the ROOL forum, somebody asked about the process of creating software.

It's a reasonable question. I mean, one could think that programmers are weird people that go into a trance, start speaking gibberish, and working software is the result.

The process of creating software starts with an idea. For the purposes of this, I shall talk about my Koi-Koi (Hanafuda) game. The first idea is a simple to-the-point description. "Koi-Koi for RISC OS".

The next step is to refine the idea into something that is a rough specification. In the case of Koi-Koi, this was simple because it is a card game with known rules. All we need to do is imagine it in a window on the desktop rather than actual cards on a table.

 

From here, it's time to start thinking about the implementation. In the case of Koi-Koi, we can immediately break the project into sections:

Something like Arbitrator might not sound too hard, but one must remember that a player first tries to match a card in their hand with one on the table, then they take a card off the stack and try to match that, then they look to see if any Yaku were formed and decide what to do if they were.
Oh, and either player can go first so it needs to work regardless of who is first and who is second.

 

Whether you create the specification in your head, or write it down, it must be given due thought before a single line of code is written. You see, programming is a lot like baking. You need to have in mind your objective (Victoria Sponge), and then you have to know what is necessary (self-raising flour, sugar, eggs...) and the steps required in order to make it happen.
You can't just dump some random stuff into a bowl and hope for the best. Same with programming, you can't open an editor window and bang out some code without objectives in mind.

 

The next step is to flesh this out more. For example, think about what sort of data structures will be required to hold the various states, and about how the thing will look, feel, and behave. The card array was specified, and here is an excerpt of the outline of how the workarea was going to "be":

Window dimensions
=================

The main window size is 1780 x 980 OS units. It is set to require
application redraws, and to have a "blank" background. During the redraw
loop, the application will rectangle-fill the background exposed during
the redraw with the background green colour, and then the cards will be
drawn on top (possibly over existing cards). This minimises screen clearing
and should likewise minimise flicker. The redraw region is examined, and
only the zone(s) that need to be redrawn are redrawn, to further speed up
redrawing.

The window has scroll bars; both to allow it to be resized to suit the
user, and to permit the game to be playable on smaller (i.e. Beagle/RPi
analogue video) displays - for the window in pixels is 911 x 530 (including
furniture).


Card size
=========

The cards are represented with three different sizes:

  CARD_WID (62<<1) and CARD_HEI (106<<1) is the physical size of the card
  sprite.
  
  CARD_GRW (67<<1) and CARD_GRH (111<<1) is the size of the card with a
  small (approx 2px) black border. To keep eventual filesize of the card
  sprite data down, the black borders are drawn, not included as part of
  the sprite.
  
  The relationship between the X,Y position of the top left of the card
  and the position used by the sprite plot is X+6, Y+4. These offsets are
  defined as SPRITE_PUSHX (6) and SPRITE_PUSHY (4).
  
  The halfsize cards in the captured card areas are represented using
  similar constants - HCRD_WID (62), HCDR_HEI (106), HCRD_GRW (67) and
  HCRD_GRH (111). There are no half-sized sprites. The operating system
  plots the full size sprites scaled to 50% on the fly.
  The relationship between the X,Y position of the top left of the half
  size card and the sprite plot is X+4,Y+2; SPRITE_HPUSHX (4) and
  SPRITE_HPUSHY (2) provide these offsets.
  
  The two-thirds cards when a card has been "captured" and is shown as
  such on the table uses TCRD_OFF (22<<1) as an offset from the left side
  of the parent (full size) card. The card itself is then defined using
  TCRD_GRW (44<<1) and TCRD_GRH (74<<1) to supply its full size. The
  sprite is plotted using the same offsets as the parent card, only
  shifted to the left as defined by TCRD_OFF. Thus, the sprite dimensions
  do not need to be known, as the plotting already works as expected.



Zone definitions
================

The six zones, plus an "invalid" marker, are defined (in h.redraw) by:
  ZONE_INVAL (0) for an invalid zone
  ZONE_TABLE (1) for the table zone
  ZONE_STACK (2) for the card stack
  ZONE_PHAND (3) for the player's hand
  ZONE_OHAND (4) for the opponent's hand
  ZONE_PCAPT (5) for the player's captured cards
  ZONE_OCAPT (6) for the opponent's captured cards

Zones should be referred by definition, not magic values.


Zone 1 - Cards on the table
===========================

The cards on the table are arranged as two rows of seven cards. During game
play, it is usual to have two rows of four cards - and this is the layout
that Koi-Koi will favour. The additional three places in each row is for
"overflow" if there are more than eight cards on the table.
The game will stop with an error message upon a condition of more than 14
cards on the table at any given time. In numerous games with my mother, the
highest *real* number of cards in play at once was 12. I believe having >14
to likely be a deliberate action.

The width and height of the table are defined by TABLE_WIDTH (7) and
TABLE_HEIGHT (2).

The X,Y offsets of the top left of th UPPER row of cards is defined by the
values TABLE_X (86<<1) and TABLE_Y (134<<1). The horizontal spacing between
the cards is defined by LIST_SPC (70<<1).

Everything in CAPITALS refers to a definition in the "koikoi" header file. The C pre-processor will spot these in the code and replace them with the appropriate values prior to compilation (Google for "C preprocessor" if you don't know how this works).

 

The next thing I did was to design a set of templates (window definitions), create some generic Wimp code to get a basic program shell running, and then some Hanafuda cards. The cards were, originally, simply scans of a real Nintendo Hanafuda deck.

Following that, I wrote all of the code to draw the table, break it into zones, and to respond with a zone and card location based upon clicks in the window. There were no cards, only crossed boxes. You can actually see remnants of this if you go to the Settings window, expand it to full size, and select the "Show placeholders" option. A lot of work went into making the code that means I can click a place in the window, and the game will know that I just clicked the third card on the upper line of the cards "on the table".

It was necessary to write that harness and test it fully before anything else could be done.

So, fast forward six years (eek!) and I had a harness that displayed a layout suitable for a game of Koi-Koi. The next stage was to load and define the cards, deal them randomly, and have the game populate the work area according to what was happening. The game behaviour grew organically, aided by the fact that I played numerous games with my cat in order to get the game behaviour back into my mind. At first, the human player always went first and the computer player just chose cards semi-randomly by "what had the highest value". It stayed like this while numerous parts of the game behaviour were refined. Then arbitrator was modified so that either player could go first. And the rest of the changes (smarter computer player, yaku detection, scoring...) were eventually added.

Each step building upon the one before...
No point looking at gameplay until the work area works.
No point looking at the computer player until we've dealt with the human player.
No point looking at who-goes-first until the human-goes-first behaviour works.
No point looking at Yaku detection until gameplay happens correctly.
No point looking at scoring until Yaku detection works.
...and so on.

 

I'm not going to discuss algorithms. There are literally hundreds. Here is an example of the computer player's basic (simple level) selection of which cards to play:

   // Does something match this card?
   if ( cardhandler_whatmatches( cardid ) == 0 )
      return FALSE;

   // Scan the table looking for what matches
   for (recurse = TABLE_FIRST; recurse <= TABLE_LAST; recurse++)
   {
      if ( card[ table.table[recurse] ].state.is_matching )
      {
         // Note that the difficulty settings below are GREATER THAN
         // OR EQUAL TO in order to reduce code duplication.

         if ( config.difficulty >= 1 )
         {
            // DIFFICULTY : SIMPLE
            //
            // Simply get the points for the two cards
            ourcardpoints = card[cardid].points;
            tablecardpoints = card[ table.table[recurse] ].points;
         }
         
         
         // OTHER DIFFICULTY LEVELS (CODE HERE) BUILD UPON THIS.
         
         
         // Now add them together to see if this is our most valuable match
         thisscore = ourcardpoints + tablecardpoints;

         // Best scoring combination so far?
         if ( thisscore > highscore )
         {
            // Yes!
            highscore = thisscore;
            highcard = table.table[recurse];
         }
      }
   }

   // There will be a valid score and card, as something matches (already determined that)
   best.score = highscore;
   best.card = highcard;

   return TRUE;
}
This is called for a given card to match it against every card on the table to track the highest scoring match (highscore) and when all cards on the table have been examined, to assign the value to best.score. This, as it is, works for individual cards.
For picking a card from the computer player's hand, we simply call this function for each card in turn, and track which best.score (and associated best.card) gives us the highest value pairing.

The above function forms the basis of the computer player's intelligence. It represents the "simple" level of gameplay. Do you see where it says about other difficulty levels building upon this? Well, how the intermediate level works is to basically bias the card scores by applying a weighting. For example, all of the ribbons have the same points value, however poetry ribbons and the blue ones are weighted to be more valuable so if a match should be between a Plain and a Ribbon or a Plain and a Poetry Ribbon, it will choose the Poetry ribbon.
And, finally, the advanced level games the weightings depending upon what is in the capture areas. Yes, plural, it will look at what cards the human has captured, so if the human has two blue ribbons it'll put a weighting on getting the third (to block the human getting a Yaku for all three).

Many algorithms. :-)

 

Advice:

And remember, this is not official programming advice. There are plenty of books, tutorials, teachers, and websites that will instruct you on the proper way to program. I'm writing this from the point of view of somebody who had an idea, worked out the steps necessary to make the idea become, then went and did it.

At any rate, if you've just opened your editor window with the idea of writing a program, then it's time to go put the kettle on. Before you write one single line of code, make a cup of tea and wander around. Walk around the house/block or up the road and back. What do you want? Prime Directive right there - know your end result. Then start thinking about how to make it happen.

 

 

Your comments:

GAVIN WRAITH, 22nd December 2018, 13:54
+1. Happy Christmas.
Carl Johnson, 22nd December 2018, 23:32
Hi, sorry that this comment isn't related to your post, but I wanted to ask. Are you planning on doing any more stories with photos of playmobil figures? I thought those were pretty cool. 
 
By the way, merry christmas!
David Pilling, 23rd December 2018, 15:47
Forget regulating drones - you can buy the bits and make your own, and go back 60 years people were making model planes. I have a book showing the wonderful planes being made behind the iron curtain by individuals in the 60s. 
David Pilling, 24th December 2018, 16:00
How can they regulate drones that only exist in people's minds - no law can stop flights of fancy - seeing one's fears.
David Pilling, 24th December 2018, 16:02
"Why isn't Bob coding", if you were being paid by the line you'd not be wasting all this time. Man plans, God laughs.

Add a comment (v0.11) [help?]
Your name:

 
Your email (optional):

 
Validation:
Please type 70580 backwards.

 
Your comment:

 

Navi: Previous entry Display calendar Next entry
Switch to desktop version

Search:

See the rest of HeyRick :-)