/*---------------------------------------------------------*/
/* */
/* Turbo Vision Puzzle Demo */
/* */
/*---------------------------------------------------------*/
/*
* Turbo Vision - Version 2.0
*
* Copyright (c) 1994 by Borland International
* All Rights Reserved.
*
* Modified by Sergio Sigala <sergio@sigala.it>
* Modified by Max Okumoto <okumoto@ucsd.edu>
*/
#define Uses_TRect
#define Uses_TEvent
#define Uses_TKeys
#define Uses_TDrawBuffer
#define Uses_TStreamableClass
#define Uses_TStreamable
#define Uses_TView
#define Uses_TWindow
#include <tvision/tv.h>
__link( RView )
__link( RWindow )
#include "puzzle.h"
#include <string.h>
#include <stdio.h> /* SS: for sprintf(...) */
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#define cpPuzzlePalette "\x06\x07"
//
// TPuzzleView functions & static variables
//
const char * const TPuzzleView::name = "TPuzzleView";
void TPuzzleView::write( opstream& os )
{
TView::write( os );
os.writeBytes(board, sizeof(board));
os << moves << solved;
}
void *TPuzzleView::read( ipstream& is )
{
TView::read( is );
is.readBytes(board, sizeof(board));
is >> moves >> solved;
return this;
}
TStreamable *TPuzzleView::build()
{
return new TPuzzleView( streamableInit );
}
TStreamableClass RPuzzleView( TPuzzleView::name,
TPuzzleView::build,
__DELTA(TPuzzleView)
);
static char boardStart[16] =
{ 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L',
'M', 'N', 'O', ' '
};
static char map[15] =
{ 0, 1, 0, 1,
1, 0, 1, 0,
0, 1, 0, 1,
1, 0, 1
};
TPuzzleView::TPuzzleView(TRect& r) : TView(r)
{
srand(time(NULL));
options |= ofSelectable;
memset( board, ' ', sizeof(board) );
for(int i = 0; i <= 3; i++)
for(int j = 0; j <= 3; j++)
board[i][j] = boardStart[i*4+j];
scramble();
}
void TPuzzleView::draw()
{
char tmp[8];
char color[2], colorBack;
TDrawBuffer buf;
color[0] = color[1] = colorBack = getColor(1);
if (!solved)
color[1] = getColor(2);
/* SS: little change */
short i;
for(i = 0; i <= 3; i++)
//for(short i = 0; i <= 3; i++)
{
buf.moveChar(0, ' ', colorBack, 18);
if(i == 1)
buf.moveStr(13, "Move", colorBack);
if(i == 2)
{
sprintf(tmp, "%d", moves);
buf.moveStr(14, tmp, colorBack);
}
for(short j = 0; j <= 3; j++)
{
strcpy(tmp, " ");
tmp[1] = board[i][j];
if(board[i][j] == ' ')
buf.moveStr( (short)(j*3), tmp, color[0]);
else
buf.moveStr( (short)(j*3), tmp, color[map[board[i][j]-'A']]);
}
writeLine(0, i, 18, 1, buf);
}
}
TPalette& TPuzzleView::getPalette() const
{
static TPalette palette( cpPuzzlePalette, sizeof(cpPuzzlePalette)-1 );
return palette;
}
void TPuzzleView::handleEvent(TEvent& event)
{
TView::handleEvent(event);
if (solved && (event.what & (evKeyboard | evMouse) ) )
{
scramble();
clearEvent(event);
}
if(event.what == evMouseDown)
{
moveTile(event.mouse.where);
clearEvent(event);
winCheck();
}
else if(event.what == evKeyDown)
{
moveKey(event.keyDown.keyCode);
clearEvent(event);
winCheck();
}
}
void TPuzzleView::moveKey(int key)
{
/* SS: little change */
int i;
for(i = 0; i <= 15; i++)
// for(int i = 0; i <= 15; i++)
if(board[i/4][i%4] == ' ')
break;
int x = i % 4;
int y = i / 4;
switch(key)
{
case kbDown:
if (y > 0)
{
board[y][x] = board[y-1][x];
board[y-1][x] = ' ';
if(moves < 1000)
moves++;
}
break;
case kbUp:
if (y < 3)
{
board[y][x] = board[y+1][x];
board[y+1][x] = ' ';
if(moves < 1000)
moves++;
}
break;
case kbRight:
if (x > 0)
{
board[y][x] = board[y][x-1];
board[y][x-1] = ' ';
if(moves < 1000)
moves++;
}
break;
case kbLeft:
if (x < 3)
{
board[y][x] = board[y][x+1];
board[y][x+1] = ' ';
if(moves < 1000)
moves++;
}
break;
}
drawView();
}
void TPuzzleView::moveTile(TPoint p)
{
p = makeLocal(p);
/* SS: little change */
int i;
for(i = 0; i <= 15; i++)
// for(int i = 0; i <= 15; i++)
if(board[i/4][i%4] == ' ')
break;
int x = p.x / 3;
int y = p.y;
switch( (y*4 + x - i) )
{
case -4: // Piece moves down
moveKey(kbDown);
break;
case -1: // Piece moves right
moveKey(kbRight);
break;
case 1: // Piece moves left
moveKey(kbLeft);
break;
case 4: // Piece moves up
moveKey(kbUp);
break;
}
drawView();
}
void TPuzzleView::scramble()
{
moves = 0;
solved = 0;
do
{
switch( (rand() >> 4) % 4)
{
case 0:
moveKey(kbUp);
break;
case 1:
moveKey(kbDown);
break;
case 2:
moveKey(kbRight);
break;
case 3:
moveKey(kbLeft);
break;
}
} while (moves++ <= 500);
moves = 0;
drawView();
}
static char *solution = "ABCDEFGHIJKLMNO ";
void TPuzzleView::winCheck()
{
/* SS: little change */
int i;
for(i = 0; i <= 15; i++)
// for(int i = 0; i <= 15; i++)
if(board[i/4][i%4] != solution[i])
break;
if(i == 16)
solved = 1;
drawView();
}
//
// TPuzzleWindow functions
//
const char * const TPuzzleWindow::name = "TPuzzleWindow";
void TPuzzleWindow::write( opstream& os )
{
TWindow::write( os );
}
void *TPuzzleWindow::read( ipstream& is )
{
TWindow::read( is );
return this;
}
TStreamable *TPuzzleWindow::build()
{
return new TPuzzleWindow( streamableInit );
}
TStreamableClass RPuzzleWindow( TPuzzleWindow::name,
TPuzzleWindow::build,
__DELTA(TPuzzleWindow)
);
TPuzzleWindow::TPuzzleWindow() :
TWindow( TRect(1, 1, 21, 7), "Puzzle", wnNoNumber),
TWindowInit( &TPuzzleWindow::initFrame )
{
flags &= ~(wfZoom | wfGrow);
growMode = 0;
TRect r = getExtent();
r.grow(-1, -1);
insert( new TPuzzleView(r) );
}
syntax highlighted by Code2HTML, v. 0.9.1