Jump to content
IGNORED

Minesweeper


Andrew Davie

Recommended Posts

I was thinking that the tile engine would be pretty good for implementing Minesweeper.

The scrolling board would give a pretty huge playing area, and I think the graphics would mostly look OK.

As far as I know.... numbers 0 1 2 3, tile, exposed square, bomb, question mark, that's about it....

I might get a mockup done in a day or two.

  • Like 5
Link to comment
Share on other sites

Tricky to get tiles looking good in 4 pixels across x 24 scanlines deep.  Each vertical pixel itself being 3 scanlines of RGB format, thus the real character size being just 4 pixels by 7 pixels. Here's my "worksheet" looking at basic visuals. Ignore the colours; those are worked out later! I'm going to make a quick-n-dirty tool to convert images to the character graphic format - previously this was done by hand, but stuff that, it's time for a tool.

My general feeling at the moment is that it's going to look OK, not great.  I plan to get to the point of a mockup screen using the tile engine, that can be scrolled around... and see how it all looks. This is project #3 I'm juggling (Sokoboo, 2P Go, Minesweeper), so expect me to abandon one or more of those at any time!

I thought with this one, it would be interesting to share the actual processes I go through to make it happen.

 

 

worksheet.png

Link to comment
Share on other sites

Next I need to write a tool to convert the graphics into data for the game.

In particular, these are all characters in a "character set".

 

A character is 4 PF pixels wide and 24 scanlines deep.

 

The character *definition* in the data actually has the left-side and right side of a PF byte defined together. So the character definition consists of the left-character and right-character pair combined into one byte (8 bits).  And now the tricky bit... because PF bytes are mirrored (PF0 and PF2), we also define mirrored characters. And now the really tricky bit... because the tile engine displays scanlines in RGB RGB RGB triplets, each character is actually defined as 3 sets of colour planes (1 red, 1 green 1 blue).  So we need to pick the 'red' on line 1, the 'green' on line 2, the 'blue' on line 3, the 'red' on line 4, etc. RGB RGB.  But don't think of it as red as in the colour red.  It's just colour #1 of the 3 defined colours.  Now in the graphics shown earlier, I have deliberately drawn them with a palette consisting of 8 colours (black = BG = colour 0).

 

The 8 bit patterns for pixels are therefore 000 001 010 011 100 101 110 111.  And the position of those bits are considered to be the presence OR NOT of one of the RGB colours. So, numbering the bits D2 D1 and D0, then for colour #5 (in this case it happens to be the dark blue in the images shown)... well that ACTUALLY becomes D2 + D0 ==> . uses colours "R" and "B" in terms of which RGB triplet scanline is used.

 

So, the tool just needs to grab an image, then iterate the pixels. Whatever the pixel colour, we know if the bit for each of the scanline triplet lines (i.e., the RGB) is on or off based on the bit pattern of the pixel.  Colour 5, as noted, will have on pixels for the R and B lines.  Colour 1 will have on pixel for only the R line, and colour 7 will have on pixels for all three RGB lines. Makes sense, I hope. It's tricky.

So, the tool needs to produce the output data for 4 pixels across (represented as two 4-pixel characters side-by-side), and three RGB triplet planes, each being 8 scanlines deep.  Here's an example from another game...

 

    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_BOX", LINES_PER_CHAR
CHARACTERSHAPE_BOX
 .byte %11111111,%11111111,%10011001,%10011001,%10011001,%11111111,%11111111,%0 ;R
 .byte %11111111,%11111111,%10011001,%10011001,%10011001,%11111111,%11111111,%11111111 ;G
 .byte %0,%0,%0,0,%0,%0,%0,0 ;B

    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_BOX_MIRRORED", LINES_PER_CHAR
CHARACTERSHAPE_BOX_MIRRORED
  .byte %11111111,%11111111,%10011001,%10011001,%10011001,%11111111,%11111111,%0 ;R
  .byte %11111111,%11111111,%10011001,%10011001,%10011001,%11111111,%11111111,%11111111 ;G
  .byte %0,%0,0,0,%0,%0,%0,0 ;B

The "OPTIONAL_PAGEBREAK" is a macro that inserts a page break, if required, to ensure that the data following does not cross a page boundary. Page boundary crossing is bad for the engine.

So, in the above, we have a character named "BOX" which has a normal and mirrored version.

Each consists of three colour fields - nominally named R G and B - but in fact the actual colours used can be anything.

Each of those fields consists of eight bytes, actually drawn on every third line.

Each of those bytes consists of a pair of character definitions for a line, a left-half and a right-half.

 

Consider the first non-mirrored definition. Lets chop off the left character of the pair so we're actually dealing with just a single character.

I'll replace 1's with R G or B depending on which field it's in, and 0 with a _

 

First chop off the left character definition

 1111 1111 1001 1001 1001 1111 1111 0000  ;R
 1111 1111 1001 1001 1001 1111 1111 1111 ; G
 0000 0000 0000 0000 0000 0000 0000 0000 ; B

Now replace 1's with the colour and 0's with _

 RRRR RRRR R__R R__R R__R RRRR RRRR ____ ; R
 GGGG GGGG G__G G__G G__G GGGG GGGG GGGG ; G
 ____ ____ ____ ____ ____ ____ ____ ____ ; B

Now instead of grouping as colour planes (RGB), show them as successive RGB scanlines. So, byte 0 from R, byte 0 from G, byte 0 from B...
byte 1 from R, byte 1 from G, byte 1 from B... etc.  I'll put the scanline # alongside...

RRRR		0
GGGG		1
____		2
RRRR		3
GGGG		4
____		5
R__R		6
G__G		7
____		8
R__R		9
G__G		10
____		11
R__R		12
G__G		13
____		14
RRRR		15
GGGG		16
____		17
RRRR		18
GGGG		19
____		20
____		21
GGGG		22
____		23

 

OK, and THAT is why doing characters by hand is a right royal pain in the butt. I definitely am way way overdue on getting a tool written for this.

 

Edit: I forgot to mention.. the data is also stored upside-down :) . So in fact those scanlines should be flipped.
In any case, that actual shape, when used in the engine, looks like this....

1697926539_ScreenShot2019-08-20at2_41_01pm.png.61eda72f3cd8156b581c0c442ac6ce75.png

 

It might seem like an excessively complex character format - but it is very efficient for the engine being able to draw stuff to the screen - both L and R character definitions in one byte, so no shifting to draw is required. And the colour planes are separated out, so each of the 3 line drawing parts can use simple indexing to retrieve. It's all very historical, but the end result is that it is next to impossible to look at a character definition and "see" what it represents. And it's very very difficult to get the shapes looking good when you are modifying code by hand.

 

So, I'll get to work writing the tool and I should have that done quickly. Python is excellent for this sort of quick conversion stuff.
 

Edited by Andrew Davie
because i can
Link to comment
Share on other sites

17 minutes ago, root42 said:

What's the maximum amount of tiles that you will be able to handle? You need to store 1 bit per tile (0=covered, 1 uncovered). You might be able to use RLE to compress it fairly efficiently.

 

I'm using the existing tile engine, not rewriting things. So it is working within the limitations of the engine. It can handle about 64 x 64, give or take. The larger the size, the bigger the RAM requirements. There's no compression involved, other than representing as characters.  The number of *different* tiles is somewhat limited by the available space in the fixed bank, and the 'tile' bank (which also contains the drawing code).  It's not huge, maybe 16. That's one severe limitation of the system.  Currently I have $223 bytes spare in the fixed bank, and $1B0 free in the draw bank. That's roughly $400 bytes, and a character/tile takes 48 ($30) bytes to define. So I make that just on 20 characters. Maximum.

 

Link to comment
Share on other sites

I wrote the conversion utility (icc.py) which takes as input all of the image files (of any format) in the current directory, and processes those that are 4 x 8 pixels in size (which is the size for ICC characters). It then creates the appropriate data tables for that character...

 

from PIL import Image
import os


# grab a plane and produce paired character bytes
# plane_offset = 0, 1, 2 representing both scanline offset AND the bit # to use
def fetch(bitmap, plane_offset):

    plane = []
    for scan_line in range(0, 8):
        byte = 0
        for pixel in range(0, 4):
            byte = (byte << 1) + (17 if bitmap[pixel, scan_line] & (1 << plane_offset) > 0 else 0)
        plane.append(byte)
    plane.reverse()
    return plane


# mirror (left/right) a plane
def mirror(plane):
    mir = []
    for byte in plane:
        mir.append(int('{:08b}'.format(byte)[::-1], 2))  # !!!
    return mir


def develop(filename):

    try:
        im = Image.open(filename)
    except IOError:
        return

    file_prefix = filename.rsplit('.', 1)[0]
    if im.size[0] == 4 and im.size[1] == 8:
        pix = im.load()

        print('    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_' + file_prefix + '", LINES_PER_CHAR')
        print('CHARACTERSHAPE_' + file_prefix)
        for plane in range(0, 3):
            print(' .byte ' + ','.join(map(str, mirror(fetch(pix, plane)))))

        print('\n    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_' + file_prefix + '_MIRRORED", LINES_PER_CHAR')
        print('CHARACTERSHAPE_' + file_prefix + '_MIRRORED')
        for plane in range(0, 3):
            print(' .byte ' + ','.join(map(str, fetch(pix, plane))))


for entry in os.scandir('.'):
    develop(entry.name)


I really like programming in Python - a concise and easy to use language.
Anyhow, given an input image like this...

338472838_ScreenShot2019-08-20at9_43_24pm.png.aa02ab10fca6bd4d121376917a510a19.png

 

.. that is, a 4 x 8 pixel (any image format) with only 8 colours, in the previously discussed interleaved colour usage, then the tool outputs the following (for this case, filename = 'char_mine.png')...

 

    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_char_mine", LINES_PER_CHAR
CHARACTERSHAPE_char_mine
 .byte 0,136,0,204,238,102,136,0
 .byte 0,17,102,51,17,0,17,0
 .byte 0,0,0,0,0,0,0,0

    OPTIONAL_PAGEBREAK "CHARACTERSHAPE_char_mine_MIRRORED", LINES_PER_CHAR
CHARACTERSHAPE_char_mine_MIRRORED
 .byte 0,17,0,51,119,102,17,0
 .byte 0,136,102,204,136,0,136,0
 .byte 0,0,0,0,0,0,0,0

I've taken that data directly into the tile engine, and confirmed it displays correctly.
So, that job is done!  Next thing I'll do is convert all the characters, install them into the engine, and display them on the screen just to see what they look like, and have a play with the 3 available colours and see what various combinations look like. That will determine if the system would be workable for a minesweeper.

 

Link to comment
Share on other sites

4 hours ago, Andrew Davie said:

 

I really like programming in Python - a concise and easy to use language.

 

 

Amen. ?

 

(Some people are weirded out by the whole "whitespace has significance" thing, but to me that just enforces the sort of stylistically-correct formatting readable code should have anyway, even if Python did require curly braces.)

Edited by JeffJetton
Link to comment
Share on other sites

  • 1 month later...

Well just taking a short break from Sokoboo, I did a sort of mockup - that is, changed the sokoboo charatcter shapes to the minesweeper character shapes, just to see how things might look. Here are a couple of screen grabs....

752010239_ScreenShot2019-09-21at11_37_34pm.thumb.png.89410f1d5d039e3e2d5585c3da2415c3.png

 

1355972824_ScreenShot2019-09-21at11_34_42pm.thumb.png.dd6838a8474d181b60465b878fe1a1d6.png

 

In principle, I think this could work.

 

  • Like 5
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...