Re: [stella] Thinking like a computer (harder than it sounds)

Subject: Re: [stella] Thinking like a computer (harder than it sounds)
From: Erik Mooney <emooney@xxxxxxxxxxxxxxxx>
Date: Thu, 27 May 1999 10:19:24 -0400 (EDT)
> Hey, gang.  This is one of my more technical questions here.  I'm still
> working on getting the hang of the (for lack of a better phrase)
> graphics engine, but it's coming along.

Engine?  More like a twenty-year-old BMX with no brakes :)

>      First, the control layout, so you can follow my logic.  The
> joystick moves the pointer between the spots for cards, empty or not. 

This, all in all, sounds like a carbon copy of the control scheme for
Windows solitaire.  That can easily be played with one pointing device and
one button, so don't worry about that :)

> whatever card is there and holds it (whether I'll do this by having the
> card flash or have it graphically moved somewhere else on the screen

Make it flash.  It's gonna be tough enough as-is to display all the
cards.. never mind trying to show one moving aorund the screen.

>      When the computer powers up, I put at memory location FFFC and
> FFFD the memory address it is to start running from (since it's a 6502,
> I put the last two bits of the location in the first register and the
> first to bits in the second register, right?).  At that location, I

It's little-endian ("little end first"), like Intel processors.  You've
got the general idea, but you put the low byte in FFFC and the high byte
in FFFD (dunno where you got "two bits" from.)  Also, the code doesn't
"put" the address into those locations... you hardcode that location (it's
ROM).  Odds are that you'll just put F000 at that location (00 in FFFC, F0
in FFFD) which will make the cart start running from the beginning of the
ROM address space (which is F000.)

>      I then start the VSYNC command stuff.  Since the computer will
> come back here once it is done drawing the screen, this is where to put
> the bulk of the commands.  First, I check for controller input,

Just to clarify... the "VSYNC command stuff" is holding the VSYNC bit high
for three scanlines worth of time.  Then, you have 37 scanlines worth of
time (2812 CPU cycles, around 800-1000 assembly instructions) before the
electron beam gets to the visible area of the TV screen.  During those
2812 cycles is where most game logic usually happens.

>      (Deep breath.)  This is where I hit the wall.  The computer needs
> to keep track of, among other things, what all the cards are in the
> deck of cards, the discard deck, the four stacks you start with the
> aces, and the seven stacks you start the game with.  Take the last
> stack, the one with seven cards, one up, six down at the start.  I'm
> thinking I'll need a pair of memory cells for each card, one to tell
> the denomination, the other to tell what suit it is.  That's twelve for

"Memory cells"?  You're way too high-level here, boy.  In 2600-land, we
have bits and bytes.  Nothin' else. :)  And one byte (256 possible values)
is plenty to keep track of one card (52 possible values).. you don't need
two "cells" for it.

> the face down cards so far.  I would also need at least another
> twenty-four for the face up cards, assuming there is a King on top and
> the person keeps building off of it until he hits a two--an Ace would
> have to be moved up to the top, it can't be placed on the stack. 
> That's 210 memory locations so far, since you can never tell which
> stack will be empty so a King can be placed there.  I suppose the
> stacks at the top would be a little easier to manage.  I image one
> memory cell to denote the suit, and then another thirteen cells for
> each stack.  Since the cards in the discard deck never change order, I
> would probably set up forty-eight memory cells for twenty-four cards
> and their suits.

You're thinking too physically.  Compress it into _exactly_ what the
computer needs to keep track of.  One byte (actually one nibble (4 bits))
is all you need for each top stack - the computer only needs to keep track
of the *highest* card on each stack; the lower cards may as well not
exist.  Similarly, you can cheat with the face-down stacks.  Just keep an
array of "cards yet to be seen".. whenever the player flips one over, pull
a card out of that array.  That'll be transparent to the player and
require less storage space.  Carrying this further yet, for each of the
face-up stacks, you only need to keep track of the value and suit of the
*highest* card on the stack and only the *suit* for the others, since the
value of any lower card is determined by the card it's on.

So I count total memory requirements of 24 bytes for the deck, 21 bytes
for "cards yet to be seen", 6 bytes to keep track of how many cards in
each face-down stack (could be 3 if you use nibbles instead of bytes), 4
bytes for the foundations (could be 2 with nibbles), and for the face-up
stacks, one byte for the top card, one byte for the number of cards, and 3
bytes to hold the suits of all lower cards (you only need 2 bits per card
to hold the suit.  Counting carefully, that even allows aces to be on
face-up stacks.)  5 bytes * 7 stacks = 35 bytes for the face-up stacks. 
Grand total to keep track of the deck: 90 (could be 85) bytes, well within
the 2600's 128 bytes and leaves you plenty of room for scratch space for
the pointer, the "move" stack, and so on.

>      I'm wondering if this is too much to put in that space of time
> between when the computer starts the VBLANK and it hits the imagery
> seen on TV.

Not if you code it efficiently.  Loops are the big killer of CPU time
here... without many big loops, you'll fill the 4k of ROM before you fill
the 2812 cycles of CPU time.  And this logic doesn't look like it needs
much looping.  But Columns on the other hand...

>      That's the problem for Solitaire, and it gets more complicated
> with a game like Columns.  To make a long idea short, I am envisioning
> a series of 208 registers,  two spots for each square in the 8 by 13
> well.  One of the pair would tell if there is a jewel there, the other
> will denote it's color.  Since the idea is to match the colors in three

Again, quit it with the "spots" and separate present/color storage.  Each
location could be described in three bits, which would be 8 possible
values - zero means empty, six values for colors.  To make the code a lot
simpler, though, I'd go ahead and use one nibble per square, so you'd have
one bit for present or not and three bits for colors.

BTW, I thought Columns was 6-wide, not 8... but either way 128 bytes of
RAM is still enough if you use one nibble per square.

> in a row or more, all I can imagine is the computer comparing each
[snip game logic]

Again, cheat and don't do unnecessary work.  Whenever the player drops a
piece, you only need to check for lines formed by the pieces that just
dropped.  3 squares times 8 directions means you have probably 80-100
cycles per square/direction and still fit in VBLANK, which should be
enough.  (remember that you'll never have to go more than 2 squares in any
direction)

> jewels fall to fill in the holes.
>      I'm having trouble seeing how to make this work for the Atari
> without slowing it down, screwing up the count, whatever.  Is this the

However, here, you do need to check the entire screen for combinations,
which probably wouldn't be doable within VBLANK.  So, here's another
trick.  When the player completes a group of three, make the group flash
and disappear or whatever, then *don't draw the next frame*.  Just make
the entire screen flash white for a frame, and use that time to look for
combinations.  If that's not enough, do it for two or three frames
instead.  It'll make for a pretty neat effect, actually.  The NES uses
this trick in light-gun games - when you pull the trigger, it draws an
entire frame of white while looking for the light-gun position.
Clever, no?


--
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/

Current Thread