
/*
 * Puzzle v1.73
 *
 * Written July 1989 By Mark Everingham
 *
 * (C) Copyright 1989 Amiga Computing
 *
 * Compiled under Aztec C V3.6a Developer
 *
 * Machine Requirements: A500/1000/2000 KickStart 1.2 256k RAM
 *
 * System Compatibility: NSTC, PAL, Interlace & Any Fast RAM
 *
 * Compile Process: CC Puzzle.C
 *                  LN +Cdb Puzzle.O -LC
 *
 * Library Useage: Integer Math, Intuition, Graphics, Text
 *
 */

/* Specify Include Files For Intuition, Graphics & Text */

#include <stdio.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>

/* Specify Custom Identifier For Close Gadget */

#define GDGCLOSE GADGETUP


/* Declare Global Structures & Function Types */

struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct Window        *windo, *OpenWindow();
struct RastPort      *raster;
struct IntuiMessage  *idcmpmsg;
struct Message       *GetMsg();
struct TextFont      *fontptr, *OpenFont();

/* Setup Initialized Font Structure */

struct TextAttr fontattr = {
        (STRPTR) "topaz.font", 8, 0, 0
};

/* Setup Graphics For Close Gadget Image */

UWORD closegraphic[] = {
        0xFFE0, 0xE0E0, 0xCE60, 0xCFE0, 0xCE60, 0xE0E0, 0xFFE0,
        0x0000, 0x1F00, 0x3180, 0x3000, 0x3180, 0x1F00, 0x0000
};

/* Setup Graphics For Window-To-Back Gadget Image */

UWORD backgraphic[] = {
        0xFFE0, 0xC0E0, 0xCE60, 0xC0E0, 0xCE60, 0xC0E0, 0xFFE0,
        0x0000, 0x3F00, 0x3180, 0x3F00, 0x3180, 0x3F00, 0x0000
};

/* Setup Graphics For Window-To-Front Gadget Image */

UWORD frontgraphic[] = {
        0xFFE0, 0xC060, 0xCFE0, 0xC1E0, 0xCFE0, 0xCFE0, 0xFFE0,
        0x0000, 0x3F80, 0x3000, 0x3E00, 0x3000, 0x3000, 0x0000
};

/* Setup Graphics For Puzzle Tiles */

UWORD tilegraphic[] = {
        0x0000, 0x0000,
        0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0,
        0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0,
        0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0, 0x3FFF, 0xFFF0,
        0x3FFF, 0xFFF0,
        0x0000, 0x0000,
        0xFFFF, 0xFFFC,
        0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C,
        0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C,
        0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C, 0xC000, 0x000C,
        0xC000, 0x000C,
        0xFFFF, 0xFFFC
};

/* Setup Image Structures For Gadgets */

struct Image closeimage = {
        0, 0, 11, 7, 2, &closegraphic[0], 3, 3, NULL
};

struct Image backimage = {
        0, 0, 11, 7, 2, &backgraphic[0], 3, 3, NULL
};

struct Image frontimage = {
        0, 0, 11, 7, 2, &frontgraphic[0], 3, 3, NULL
};

/* Setup Image Structure For Puzzle Tiles */

struct Image tileimage = {
        0, 0, 30, 15, 2, &tilegraphic[0], 3, 3, NULL
};

/* Setup Gadget Structures For System Gadgets */

struct Gadget closegadget = {
        NULL, 3, 2, 11, 7, GADGIMAGE | GADGHCOMP, RELVERIFY,
        BOOLGADGET, (APTR) &closeimage, NULL, NULL, NULL, NULL, 0,
        NULL
};

struct Gadget draggadget = {
        &closegadget, 15, 0, 89, 11, GADGHNONE, GADGIMMEDIATE,
        SYSGADGET | WDRAGGING, NULL, NULL, NULL, NULL, NULL, 0,
        NULL
};

struct Gadget backgadget = {
        &draggadget, 106, 2, 11, 7, GADGIMAGE | GADGHCOMP, RELVERIFY,
        SYSGADGET | WDOWNBACK, (APTR) &backimage, NULL, NULL, NULL, NULL, 0,
        NULL
};

struct Gadget frontgadget = {
        &backgadget, 120, 2, 11, 7, GADGIMAGE | GADGHCOMP, RELVERIFY,
        SYSGADGET | WUPFRONT, (APTR) &frontimage, NULL, NULL, NULL, NULL, 0,
        NULL
};

/* Setup Initialized NewWindow Structure */

struct NewWindow windef = {
        0, 0, 134, 77, 2, 2, MOUSEBUTTONS | GADGETUP,
        SMART_REFRESH | RMBTRAP, NULL, NULL, NULL,
        NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
};

/* Setup Pseudo-Random Array Of Starting Positions */

UBYTE randomtile[32][8] = {
        {123,241,64,162,232,198,147,93},  {248,228,25,118,5,188,210,163},
        {103,253,165,200,20,46,155,48},   {9,101,132,125,186,62,31,44},
        {219,160,21,131,126,47,196,150},  {125,62,20,86,248,156,42,11},
        {134,76,158,2,58,93,247,27},      {80,67,134,113,210,186,158,207},
        {165,124,177,100,143,222,57,32},  {183,37,222,134,156,1,163,79},
        {26,190,131,36,205,80,150,247},   {185,124,175,40,94,65,13,99},
        {132,185,230,202,83,240,215,18},  {191,13,198,116,229,41,129,163},
        {203,122,25,38,143,53,14,77},     {193,122,248,105,62,91,208,66},
        {69,206,41,120,208,166,241,59},   {182,240,81,138,211,46,116,156},
        {167,146,198,8,237,180,83,241},   {116,92,2,57,246,27,173,142},
        {123,213,224,207,100,41,131,161}, {71,177,106,128,63,41,222,92},
        {178,89,100,48,167,193,223,142},  {123,252,4,21,41,232,106,61},
        {70,190,57,162,8,95,23,205},      {128,125,161,54,43,197,79,233},
        {186,134,31,205,89,36,224,115},   {120,237,101,243,177,156,164,2},
        {14,61,175,137,91,39,20,108},     {230,11,165,248,151,44,67,209},
        {139,103,92,58,78,2,253,25},      {158,196,38,167,80,59,29,248},
};

/* Setup Working Array Of Tile Numbers */

UBYTE tilearray[4][4] = {
        {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}
};

int arraynum, emptyx, emptyy;

main()
{
        ULONG  idcmpclass;
        USHORT idcmpcode;

        /* Open Relevant Libraries & Window */

        if (OpenAll() == FALSE) goto abort;

        /* Draw Title, Background & Puzzle Tiles */

        raster = windo->RPort;
        DrawTitleBar();
        SetAPen(raster, 3L);
        RectFill(raster, 2L, 11L, 131L, 75L);
        NewTiles();

        /* Wait For IDCMP Message & Process */

        while (idcmpclass != GDGCLOSE) {
                Wait (1L<<windo->UserPort->mp_SigBit);
                idcmpmsg = (struct IntuiMessage *) GetMsg(windo->UserPort);
                ReplyMsg(idcmpmsg);
                idcmpclass = idcmpmsg->Class;
                idcmpcode = idcmpmsg->Code;
                windo->FirstGadget = NULL;
                if (idcmpcode == SELECTUP) ProcessMove();
                if (idcmpcode == MENUUP) NewTiles();
                windo->FirstGadget = &frontgadget;
        }

        /* Abort Program - Close Libraries, Window & Font */

abort:  CloseAll();
}

/* Function To Open Libraries & Window */

OpenAll()
{
        char *OpenLibrary();

        /* Open Intuition & Graphics Libraries */

        if (!(IntuitionBase = (struct IntuitionBase *)
                OpenLibrary ("intuition.library", 1L))) {
                return (FALSE);
        }
        if (!(GfxBase = (struct GfxBase *)
                OpenLibrary ("graphics.library", 1L))) {
                return (FALSE);
        }

        /* Open Puzzle Window */

        if (!(windo = (struct Window *)
                OpenWindow (&windef))) {
                return (FALSE);
        }
}

/* Function To Close Font, Libraries & Window */

CloseAll()
{
        /* Close Current Font */

        if (fontptr) {
                ChangeFont(8);
                CloseFont(fontptr);
        }

        /* Remove Window Gadgets */

        RemoveGadget(windo, &draggadget);
        RemoveGadget(windo, &backgadget);
        RemoveGadget(windo, &frontgadget);

        /* Close Puzzle Window */

        if (windo) {
                windo->FirstGadget=&closegadget;
                CloseWindow(windo);
        }

        /* Close Graphics & Intuition Libraries */

        if (GfxBase)       CloseLibrary(GfxBase);
        if (IntuitionBase) CloseLibrary(IntuitionBase);
}

/* Function To Setup Working Array With Tile Numbers */

SetUpArray()
{
        int tilenum, tilex, tiley;

        tilenum = 0;
        for (tiley = 0; tiley<4; ++tiley) {
                for (tilex = 0; tilex < 4; tilex += 2) {
        tilearray[tiley][tilex] = randomtile[arraynum][tilenum] & 15;
        tilearray[tiley][tilex+1] = (randomtile[arraynum][tilenum]) >> 4;
        ++tilenum;
                }
        }
}

/* Function To Draw Puzzle Window Title-Bar */

DrawTitleBar()
{
        /* Select Topaz 8 Font & Draw Title-Bar */

        ChangeFont(8);
        SetAPen(raster, 2L);
        RectFill(raster, 2L, 1L, 132L, 10L);
        SetAPen(raster, 1L);
        SetBPen(raster, 2L);
        Move(raster, 36L, 8L);
        Text(raster, (UBYTE *) "Puzzle", 6L);

        /* Draw Window System Gadgets */

        windo->FirstGadget = &frontgadget;
        RefreshGadgets(&frontgadget, windo, NULL);
        ChangeFont(9);
}

/* Function To Change Current Font To Topaz 8/9 */

ChangeFont(fonttype)

int fonttype;
{
        /* Open Font */

        if (fontptr) CloseFont(fontptr);
        fontattr.ta_YSize = fonttype;
        fontptr = OpenFont(&fontattr);
        SetFont(raster, fontptr);

        /* If Topaz 9 Font, Select Bold Style */

        SetSoftStyle(raster, fonttype == 9 ? 2L : 0L, 2L);
}

/* Function To Setup & Draw New Tile Grid */

NewTiles()
{
        int tilex, tiley;

        SetUpArray();
        for (tiley = 0; tiley < 4; ++tiley) {
                for (tilex = 0; tilex < 4; ++tilex) {
                        DrawTile(tilex, tiley);
                }
        }
        arraynum = (arraynum + 1) % 32;
}

/* Function To Draw Tile Image & Number */

DrawTile(tilex, tiley)

int tilex, tiley;
{
        UBYTE tilenum, numtext[2];
        long  scrx, scry;

        tilenum = tilearray[tiley][tilex];
        scrx = tilex * 32 + 4;
        scry = tiley * 16 +12;

        /* Draw Occupied Tile Space */

        if (tilenum) {
                numtext[0] = '0' + (tilenum > 9);
                numtext[1] = '0' + tilenum % 10;
                DrawImage(raster, &tileimage, scrx, scry);
                SetAPen(raster, 2L);
                SetBPen(raster, 1L);
                Move(raster, scrx + 9 - 5 * (tilenum > 9), scry + 10);
                Text(raster, &numtext[tilenum < 10], tilenum > 9 ? 2L : 1L);
        }

        /* Draw Empty Tile Space */

        else {
                SetAPen(raster, 3L);
                RectFill(raster, scrx, scry, scrx + 29, scry + 14);
                emptyx = tilex;
                emptyy = tiley;
        }
}

/* Function To Check For Validity & Perform Move */

ProcessMove()
{
        int  msx, msy;
        long deltax, deltay, deltasum, xlo, ylo, xhi, yhi;

        /* Obtain Tile Number In Grid & Check */

        msx = idcmpmsg->MouseX;
        msy = idcmpmsg->MouseY;
        if (msx < 4 || msx > 129 || msy < 12 || msy > 74)
                return();
        msx = (msx - 4) / 32;
        msy = (msy - 12) / 16;

        /* Calculate Offsets From Empty Square & Check */

        deltax = (long) msx - emptyx;
        deltay = (long) msy - emptyy;
        deltasum = deltax + deltay;
        if ((deltax && deltay) || deltasum != 1 && deltasum != -1)
                return();

        /* Swap Tile Number With Empty Square */

        tilearray[emptyy][emptyx] = tilearray[msy][msx];
        tilearray[msy][msx] = 0;

        /* Setup Scroll Area & Empty Square */

        xlo = (msx * 32) + 4 + (deltasum >= 0 ? 29 : 0);
        ylo = (msy * 16) + 12 + (deltasum >= 0 ? 14 : 0);
        xhi = (emptyx * 32) + 4 + (deltasum < 0 ? 29 : 0);
        yhi = (emptyy * 16) + 12 + (deltasum < 0 ? 14 : 0);
        emptyx = msx;
        emptyy = msy;
        if (xlo > xhi) {
                msx = xlo;
                xlo = xhi;
                xhi = msx;
        }
        if (ylo > yhi) {
                msy = ylo;
                ylo = yhi;
                yhi = msy;
        }

        /* Smoothly Scroll Chosen Tile Into Empty Square */

        deltax = deltax * 2;
        SetBPen(raster, 3L);
        for (msy = 0; msy < 16; ++msy) {
                ScrollRaster(raster, deltax, deltay, xlo, ylo, xhi, yhi);
        }
}
