Pixelated Puzzle

Copyright © 2018-2019 by Víctor Parada

Pixelated Puzzle

This is a little game for the 2019 NOMAM's BASIC 10-liners Contest. This program fits in the PUR-120 category, and it was written using TurboBasic XL 1.5 for the 8-bits ATARI XL/XE. Development started on 2018-06-11, and it took 3+21 days. The final version's date is 2019-02-24.

UPDATE: It obtained the 1st place of 18 entries in the category.

Description

Identify the missing piece and solve the classic sliding puzzle in the minimum amount of moves.

Instructions

PIXPUZ step1 The game starts showing the complete image to memorize.
PIXPUZ step2 When you press the button, the puzzle will be shuffled.
PIXPUZ step3 Identify the missing piece to select which side you must complete first.
PIXPUZ step4 Slide a piece into the space moving the joystick to that direction.
PIXPUZ step5 When the last piece is moved to its position, the missing piece appears in its place and the game ends. The number of required movements that were done is displayed at the bottom of the image.

Development of the game

Three years ago I wrote a sliding puzzle called MxN Puzzle for the PUR-80 category that allowed a player to select the size of the puzzle from 2x2 up to 6x6, defaulting to the standard 4x4 size, but the pieces were letters and numbers, sorted in alphabetical order. I wanted to write another one with a graphical image and made some calculations on how many bytes should be required to represent a nice image for a puzzle and how should be stored and managed. Alternatives where two colors (B/W) and 4 colors images.

A black and white or any other two color image requires 512 bytes of data for a 64x64 pixels image, and that is more than 4 lines in a PUR-120 category. That might leave about 600 bytes for the coding. MxN Puzzle required 800 bytes, where 240 bytes were used by the size selection, so the code for initialization and the game routine requires at least 560 bytes. As it is very different to manage a text screen to a graphical screen, probably 40 bytes could not be enough to change that without moving to the EXTREM-256 category.

A 4 color image would use almost all available space in that category for a 64x64 pixels image, because it requires 2 bits per pixel, or 1024 bytes in total. But... what if I reduce the size to a 32x32 pixels image? That is only 256 bytes or 3 lines for the puzzle image, giving at least 7 lines to the code. Of course, 32x32 is a very low res image, but it is enough for any 8 bit sprite, so let's try it.

I decided to use graphics mode 5, 80x48 pixels, and adapted the code from MxN Puzzle to manage the puzzle in a text buffer, and then map it to the graphical screen with the bitmapped pieces. The first image to try in order to do the tests was the same alphabet than MxN in a 4x4 mode, but in inverse video, so I added a temporary code to draw it, but instead of locate the missing piece in the lower-right position, I decided to randomly remove any of the pieces before shuffling. Identifying the missing piece from the alphabet to decide how to solve the puzzle could be easy, but it could be challenging to identify the missing piece from a shuffled bitmap.

PIXPUZ mnpuzzle

MxN Puzzle at the default 4x4 size

PIXPUZ alphabet

Alphabet Pixelated Puzzle

After deciding how to store the bitmap image in the setup string, the next step was to change the alphabet with an image, and the selected one was an 8 bit version of Mario. I cropped him from an image and saved it as a 32x32 pixels, 4 colours BMP file, which I converted into my own format using a perl script I wrote. The resulting data string was appended to the game algorithm and the result was nice.

PIXPUZ mario1

Sprite of Mario

PIXPUZ mario2

Shuffled Mario!

I had to do many code optimizations to fit all in 10 lines of 120 chars each, but it worked OK and it was flexible enough to change the bitmap just by replacing the last 3 lines of code. During the process, I tried scaling down and dithering in just 4 colors some real photos in a PC using an image viewer (IrfanView), saving them in BMP and using my script to generate the binary string. At this stage, with all that pixelated images in a folder, the name of the game was defined. Anyway, as the result of the converts required some tweaks, I decided to write a small puzzle editor, also in TurboBasic XL, to be run in the Atari.

The editor could load the binary data and display them in a graphics 5 mode screen, put a cursor that could be moved over the pixels, change the pixels color register and save it back to disk. Then it could also change the colors of the palette, shift the whole image a pixel in any of the 4 directions, swap color registers by swapping pixels for a better selection of the background, margin and moves colors combination, and more. For simplicity, the editor could only manage files named "0.DAT" to "9.DAT" in drive "D1:", and it could generate the corresponding 3 lines of initialization code in BASIC list (LST) format, just to append to the first 7 lines with the game code and play.

PIXPUZ edit1

My pixelated version of Andy Warhol's picture of Marilyn Monroe

PIXPUZ edit2

Adjusting a dithered image of Rihanna

With the constantly improved editor, many puzzles were created, and there was a challenge to find the right ones and make them fit in just 4 unique colours, but also to identify pieces that could be identical in the puzzle, because if one piece is not placed in the right location, the puzzle could not be solved. That forced me to add designs in the background to make all of them different.

A simple way to test all of the images without the need of loading each of them, one at a time, was to add a special initialization code that allowed to select between all the available ones, so the 3 lines turned into a simple menu which, after the selection of an option, jumps to the corresponding 3 lines of code from line 100. Of course, this special version of the game was not a tenliner, but as I added many other images in my free time, I also decided to write a menu creator that supports up to 63 images identified from the current folder.

PIXPUZ menu

Menu with many puzzles

PIXPUZ shuffled

Shuffled puzzle of Rihanna!!!!!

I used this menu version in a local meetup and let the attendants to play and vote for three images as the best ones for the tenliners contest. Two puzzles got the 1st place with the same number of points: Pikachu and Kirby. I choose Kirby because it was easier to identify every piece, including the missing piece.

PIXPUZ winner1

Pikachu

PIXPUZ winner2

Shuffled Kirby

Current puzzles in chronological order

PIXPUZ abc

ABC

PIXPUZ mario

Mario

PIXPUZ warhol

Warhol

PIXPUZ rihanna

Rihanna

PIXPUZ yoshi

Yoshi

PIXPUZ pikachu

Pikachu

PIXPUZ hulk

Hulk

PIXPUZ kirby

Kirby

PIXPUZ wally gator

Wally Gator

PIXPUZ pink panther

Pink Panther

PIXPUZ iexplore

IExplorer

PIXPUZ quick draw mcgraw

Quick Draw McGraw

PIXPUZ scooby doo

Scooby Doo

PIXPUZ mcdonald's

McDonald's

PIXPUZ waze

Waze

PIXPUZ smile

Smile

PIXPUZ kojak

Kojak

PIXPUZ kiss

Kiss

PIXPUZ condorito

Condorito

PIXPUZ megaman

Megaman

PIXPUZ mona lisa

Mona Lisa


Editor Instructions


Menu Maker Instructions


Download and try

Get the PIXPUZ.ATR file and set it as drive 1 in a real Atari (or emulator). Turn the computer on and the game should start after the loading completes. A joystick in port 1 is required.

The code

The abbreviated BASIC code is the following:

The full and expanded BASIC listing is:

graphics 21
Enables graphics mode 5 without text lines, 80x48 pixels, 4 colors.
dim d(4),l(16),a$(24),b$(24),c$(24),x$(600)
Defines the arrays and strings:
- D(): stores the delta (number of bytes) to identify the piece to move on each 4 directions.
- L(): stores the delta to identify the piece to move on each joystick direction.
- A$: stores the current order of the puzzle.
- B$: stores the target order of the puzzle.
- C$: stores the default order of the puzzle.
- X$: bitmap for each piece.
c$="{binary data}"
Map of pieces in the ordered sequence. Bytes 0 to 15 for the respective piece and 16 for a border. It represents the following map:
{} [] [] [] [] []
()  1  2  3  4 []
()  5  6  7  8 []
()  9 10 11 12 []
() 13 14 15 16 []
() () () () () {}
As a way to save bytes, borders are reused between rows and columns in this way: [] are real borders, () actually are the same byte than the previous, and {} do not exist because they are never reached. Note that the bottom border bytes are the same top border bytes from the next string map in the DIM order.
e=adr(a$)
E is the memory address of the current puzzle.
m=e+72
M is the memory address of the pieces' bitmap. Each piece requires 8x8 pixels and the sequence is 2 bytes for each row of pixels from top to bottom, 16 bytes in total.
s=$BBF0
Memory address of screen data: dpeek(88)+4*20
t=$B000
Screen buffer.
r=640
Size of the screen data to move each time: 32 rows x 20 bytes per row.
a$=c$
Initializes the current map like the default one.
gosub 7
Calls the subroutine initialize the bitmap and the color palette, and then draws the full puzzle.
for i=0 to 3
  read u,v
  d(i)=u
  l(v)=u
next i
Initializes the deltas.
do
MAIN LOOP
  while strig(0)
  wend
Waits for the fire button.
  ? #6;"\7D"
Cleans the screen.
  p=int(rand(16)*1.25)+5
  poke e+p,16
Randomly selects a piece to remove.
  b$=a$
Saves the target map.
  v=p
Saves current missing piece.
  for i=0 to 99
    repeat
      q=p+d(rand(4))
      u=peek(e+q)
    until u<16 and q<>v
    poke e+q,16
    poke e+p,u
    v=p
    p=q
  next i
Shuffles the puzzle performing 100 random movements.
  gosub 6
Draws the current shuffled puzzle.
  n=0
  text 36,40,n
N is the number of current movements. This initializes the counter and prints it under the board.
  p=q
Position of the current missing piece (empty space).
  repeat
GAME LOOP
    repeat
      j=stick(0)
      q=p+l(j)
      u=peek(e+q)
    until u<16
Waits until the joystick is moved to a valid position and it is possible to slide a piece.
    poke 77,0
Disables the ATRACT mode.
    sound 0,20+j,8,8
Makes a sliding sound.
    poke e+p,u
Puts the moved piece in the current empty position.
    gosub 5
Calls the subroutine to draw the current piece in position P over the screen buffer.
    poke e+q,16
Sets the new empty space in the place where it was the moved piece.
    p=q
    gosub 5
Draws the empty space in the screen buffer.
    move t,s,r
Copies the screen buffer over screen memory, showing all the changes at the same time.
    n=n+1
    text 40-len(str$(n))*4,40,n
Increases the number of movements and displays it.
    sound
Stops the sliding sound.
    while stick(0)<15
    wend
Waits until the joystick is released.
  until b$=a$
The game ends when the current map is the same than the target map.
  a$=c$
Sets the current map as the default map to draw the missing piece.
  gosub 5
Draws the piece in the screen buffer.
  move t,s,r
Draws the full puzzle.
  for i=1 to 9
    sound 0,82-i*5,12,9-i
    pause 5
  next i
Bells and whistles.
loop
End of MAIN LOOP.
5
LINE 5: Subroutine to draw a piece in the screen buffer.
u=int((p-4)*.8)
Identifies the piece to draw.
v=peek(e+p)*16+m
Gets the memory address of the bitmap for that piece.
w=t+6+u mod 4*2+u div 4*160
Finds the position in the screen buffer for the upper-left corner of the piece.
k=v-m<256
Checks if it has to draw a piece or a space.
for j=0 to 7
  dpoke w+j*20,dpeek(v+j*2)*k
next j
return
Draws the piece or space in the screen buffer.
6
LINE 6: Subroutine to draw the whole puzzle.
color 2
plot 23,3
drawto 56,3
move s-20,s,r+20
Draws the board (margins of the puzzle) on screen.
move s,t,r
Copies the empty board from screen memory to the screen buffer.
color 1
Sets the default color for text (number of moves)
for i=0 to 15
  p=int(i*1.25)+5
  gosub 5
next i
Calls the subroutine to draw each piece in the screen buffer.
move t,s,r
Copies the screen buffer with all the pieces to the screen memory.
return
Back to the caller.
data -5,13,1,11,-1,7,5,14
Movement deltas and corresponding joystick positions.
7
LINE 7: 3 lines for pieces' bitmap and palette initialization. The actual code depends on the bitmap for the designed puzzle.
x$="{binary data}"
x$(115)="{binary data}"
x$(224)="{binary data}"
Initialization data splitted in 3 lines: 256 bytes for bitmap, 5 bytes for color palette, and some bytes as pointers for EOL ($9B=155) bytes in bitmap if required. The split position depends on the existence of quotes ($22=34) in data, and a sequence of two quotes is required to represent each of them.
move m+256,708,5
Sets the screen colors.
for i=0 to {num}
  poke m+peek(m+261+i),155
next i
(Optional) If more than one byte has an EOL value, this loop sets them. This skips EOL at position 155, because it cannot be put in the pointers table for the same reason.
poke m+{pos},155
(Optional) If only one byte has an EOL value, this statement sets it. An extra copy of this statement is required if the EOL is at position 155.
goto 6
Jumps to the puzzle drawing routine.


Return to my 10-liners page.

© 2018-2019 by Víctor Parada - 2019-02-16 (updated: 2019-04-16)