Jump to content

Zach's Projects

  • entries
    53
  • comments
    535
  • views
    67,106

Alternate Chess Kernel Solved

Sign in to follow this  
Guest

1,478 views

post-2572-1091144615_thumb.jpg

post-3928-1098333398_thumb.jpg

post-2572-1091144616_thumb.jpg

 

In my last attempt at a chess kernel with playfield graphics, I came up with a technique that would only work with about 27K of code. Since then I've made some advances that make a 4K kernel possible. One trick I developed was a new 32 pixel asymmetrical playfield configuration that takes four loads and six stores. (I believe it's new at least.)

 

The playfield remains transposed rather than reflected, but unlike before I load the same byte for the right PF0 and PF2 data. The high nybble goes to PF0 and the low nybble goes to PF2. The byte is stored to PF0 first, is AND'ed with #$0F and then stored to PF2. Setting X to #$0F and using the SAX instruction, which stores the value A & X, saves a couple cycles. I already had set X to white for my color changes, and by a fortunate coincidence white is #$0F. In additon, this value can be used to clear PF0 on the left side. This playfield configuration uses a few more cycles than the simple 32 pixel reflection, but the timing is more flexible and frees time to do all the color changes.

 

; X = #$0F (White) 
; Y = #$00 (Black)
;dynamic_code; starts on cycle 3 
  pla			 ; load PF2 left side			
  sta PF2-15,X	; left side. Use index to spend a cycle
  pla			 ; load PF0 and PF2 for right side				
  stx PF0,Y	   ; clears PF0 on left side
  sta temp-15,X   ; use indexed addressing to spend an extra cycle
  stx COLUPF	  ; color piece 1
  sta PF0		 ; right side
  stx COLUPF	  ; color piece 2
  lda pf1_right   ; load PF1 right side. The operand is inc'd below.
  stx COLUPF	  ; color piece 3
  sta PF1		 ; right side  
  stx COLUPF	  ; color piece 4
  stx COLUPF+64,Y ; color piece 5; COLUPF+64 mirrors COLUPF
  lda #$00		; <-- temp is the address of the operand here.		  
  sty COLUPF+64-15,X; color piece 6   
  sax PF2		 ; right side
  stx COLUPF	  ; color piece 7
  stx COLUPF+64,Y ; color piece 8
  pla			 ; load PF1 left side	  
  sta PF1		 ; left side   
  inc pf1_right_addr		
  bne dynamic_code; last byte for pf1_right must be $ff	   
  brk					 

 

The RAM can be allocated as follows:

32 bytes to store the board position (1 nybble for each square)

42 bytes of self-modifying code (includes temp variable)

52 bytes for temporary storage of playfield data

2 bytes for everything else

Sign in to follow this  


29 Comments


Recommended Comments



I think it's a real challenge to represent the chess pieces well enough that you don't get confused distinguishing them from eachother. In your set, the king and queen are almost indistinguishable, for instance.

 

Here is my take: (top to bottom, rook, knight, bishop, pawn, king, queen).

 

pieces7kd.gif

 

Is there any way to use an extra pair of scanlines on these pieces to help give them some added height?

Share this comment


Link to comment
Is there any way to use an extra pair of scanlines on these pieces to help give them some added height?

 

Thanks for the contribution. I forgot to mention that the pieces can be drawn with full scanline resolution, so you can design pieces with more detail. The dimensions are 3x12. The data for the chessmen graphics is stored in RAM so it can be retrieved quickly, and the 128 bytes limit their height.

 

EDIT: The new dimensions are 3x13.

Share this comment


Link to comment
Thanks for the contribution. I forgot to mention that the pieces can be drawn with full scanline resolution, so you can design pieces with more detail. The dimensions are 3x12. The data for the chessmen graphics is stored in RAM so it can be retrieved quickly, and the 128 bytes limit their height.

 

In that case, here are a couple other approaches.

 

This one may look a little too busy:

 

pieces20qt.gif

 

This one below might be the best compromise.

 

pieces38mi.gif

Share this comment


Link to comment

Nice job. I like the knight, rook, and king. I've posted a mockup with them, plus some new designs for the bishop, pawn, and queen.

Share this comment


Link to comment

One thing serious chess players will probably want is a similarity between all the pieces on the board and proper heights in relation to each other. Not only that, but they should be able to distinguish any one piece from another without seeing the rest of the pieces. With that in mind, here is my take on the Jacques set with the exception of the knight which I think looks much better in mos's version than the Jacques version does.

 

pfchess8fr.gif

 

The rook and queen are not completely distinguishable when viewed seperately, but put together are quite obvious. For help in recreating them in code, the piece heights are: pawn = 6, knight = 8, rook = 9, bishop = 10, queen = 11, king = 12.

 

-JD

 

EDIT: After posting and seeing the image again, the ring around the queen and king should be closer together... probably by adding a pixel to the horizontal part of the king's cross to lower his one and removing the bottom row of the queen's crown to move her's up one.

 

EDIT 2: Like so...

 

pfchess27jf.gif

 

base size also doubled, as you can tell.

Share this comment


Link to comment

That looks really good, Mayday! I went ahead and programmed the full board with your set, slightly modified. I made the queen less rookish, and made all the pieces taller. I was able to free 4 bytes from the self-modifying code and put them towards an extra line on the pieces. Now the dimensions are 3x13. The new screenshot and binary are in the first post. :|

Share this comment


Link to comment
That looks really good, Mayday! I went ahead and programmed the full board with your set, slightly modified. I made the queen less rookish, and made all the pieces taller. I was able to free 4 bytes from the self-modifying code and put them towards an extra line on the pieces. Now the dimensions are 3x13. The new screenshot and binary are in the first post. :|

 

I download the binary because I thought your mockup may not be exactly accurate... I don't understand how you have both the board and pieces displayed with the playfield, or am I missing something? It seems as if there are more pixels displayed than should be allowed...

 

I agree your crown for the queen is better than the one I designed. I also think you should leave the ring in the middle of the piece though so it matches against the king. Speaking of the king, I don't really like his crown either, but can't think of any better way to display the cross. Anyone with ideas?

 

Chess logic coming anytime soon? I can tell you what it's rated! :|

Share this comment


Link to comment

Looks nice. My earlier pessimism may have been unwarranted.

 

Using 32 bytes for the board may be excessive. Since there are only 32 pieces on the entire board, it may be possible to do something like using 8 bytes to keep track of which squares are occupied, and then use 16 bytes (32 nybbles) to say what's in the occupied squares from top to bottom. Not sure you'd have enough time for the unpacking, though. My guess would be that average case time would be improved, but worst-case time would be made worse. But I don't know what you're doing at present, so I can't say how the change would affect things.

 

Otherwise, I must say I'm pretty impressed with your ability to eke out some cleverly-compact code. It took awhile to figure out how the self-modifying parts work since it's not very clear. It would be much more elegant if there were some way to use a fourth PLA.

Share this comment


Link to comment
I don't understand how you have both the board and pieces displayed with the playfield, or am I missing something?  It seems as if there are more pixels displayed than should be allowed...

That's quite a compliment that the screenshot doesn't look realistic. :| Actually the way the board is drawn is simple. The darker squares are made of players and missiles. (Can you imagine how it works?) The pieces are all done with the PF.

I agree your crown for the queen is better than the one I designed.  I also think you should leave the ring in the middle of the piece though so it matches against the king.  Speaking of the king, I don't really like his crown either, but can't think of any better way to display the cross.  Anyone with ideas?

I tried to keep the queen's ring, but that made it harder to distinguish between the queen and king. I'm open to suggestions.

Chess logic coming anytime soon?  I can tell you what it's rated!  :|

Still working on Four-Play, and possibly another game for the 2006 1K contest.

Share this comment


Link to comment

Hi there!

 

Still working on Four-Play, and possibly another game for the 2006 1K contest.

 

What is it? :|

 

Greetings,

Manuel

Share this comment


Link to comment
Looks nice.  My earlier pessimism may have been unwarranted.

Thanks! That means a lot coming from the author of Strat-O-Gems.

Using 32 bytes for the board may be excessive.  Since there are only 32 pieces on the entire board, it may be possible to do something like using 8 bytes to keep track of which squares are occupied, and then use 16 bytes (32 nybbles) to say what's in the occupied squares from top to bottom.  Not sure you'd have enough time for the unpacking, though.  My guess would be that average case time would be improved, but worst-case time would be made worse.  But I don't know what you're doing at present, so I can't say how the change would affect things.

Yeah, freeing more bytes without compromising the height of the pieces would be nice. Right now there are 17 bits free (2 bytes of RAM plus overflow flag), and I think that is barely enough for a playable chess game. However, it would be nice to have more memory for difficulty levels and chess variants. (I'd like to include Losing Chess at least.)

 

I'll post some code to show how the unpacking is done. Right now there is barely enough time to unpack everything. A few more cycles and I think it'd go over 262 lines.

Otherwise, I must say I'm pretty impressed with your ability to eke out some cleverly-compact code.  It took awhile to figure out how the self-modifying parts work since it's not very clear.  It would be much more elegant if there were some way to use a fourth PLA.

Thanks again. Sorry if the code was hard to follow. I put in some more comments to help clear things up. I think the solution came more from refusal to give up than cleverness. I can't tell you how many ideas I tried. Like I said, I was able to take an advantage of a lucky coincidence that #$0F could be used both for the color white and for masking the right side PF2.

 

The obstacle to a 4th PLA was the number of cycles between color changes. I tried a lot of things, but couldn't squeeze four cycles in. Your right that it would have been more elegant.

Share this comment


Link to comment
What is it? :|

Might it be related to my new avatar? I'll post details when I either get it working, or I decide it's not feasible.

Share this comment


Link to comment

Hi there!

 

What is it? :|
Might it be related to my new avatar?

 

No kidding, I already suspected that... ;)

 

I'll post details when I either get it working, or I decide it's not feasible.

 

The avatar could be from a night scene of a racing game... :|

 

Greetings,

Manuel

Share this comment


Link to comment
I'll post details when I either get it working, or I decide it's not feasible.

The avatar could be from a night scene of a racing game... :|

 

Or another attenpt at a Juno First kernel :|

 

Chris

Share this comment


Link to comment
Yeah, freeing more bytes without compromising the height of the pieces would be nice. Right now there are 17 bits free (2 bytes of RAM plus overflow flag), and I think that is barely enough for a playable chess game.

 

Well, presumably you're not going to be displaying the board while you're 'thinking'. During 'thought', the RAM used by the kernel could be used for other things.

 

Looking through your self-modifying code, I think I see space to store about 16 bits "within" it. Each indexed STA can be done using either X or Y (adjust the operand as needed), and every TIA store can be done with the normal address or with address+64. Further, you might be able to use the ball horizontal position and size to store 9 bits, eleven collision registers to store 11 bits(*), the RIOT timer to store 8 bits, and two bits of SWCHB and SWBCTL to store 4 bits. See--I just saved you six bytes.

 

(*) The playfield is going to collide with both players and both missiles, but no other collisions would have to occur, leaving eleven collision registers available for use.

 

The obstacle to a 4th PLA was the number of cycles between color changes. I tried a lot of things, but couldn't squeeze four cycles in. Your right that it would have been more elegant.

 

It might be helpful if you offer a version of the demo in which a row of pieces alternates between white and black, and in which the PF data is all $FF, so as to show exactly when the color changes are taking place.

Share this comment


Link to comment

Oh, for six more bits, use bits 8, 10, 11, 13, 14, and 15 of PC. Not sure the most effective way to do that since I don't think you can afford a computed jump, and if you don't use a computed jump the code size will double with each bit you want to save, but here's how to save three bits:

; Assume we want to save the three MSBs of WOWZO
 lda #32
 bit WOWZO
 bmi b1xx
b0xx
 bvs b01x
b00x
 bne b001
b000
 jmp ZPCODE
b001
 jmp ZPCODE+$2000
b01x
 bne b011
b010
 jmp ZPCODE+$4000
b011
 jmp ZPCODE+$6000
b1xx
 bvs b11x
b10x
 bne b101
b100
 jmp ZPCODE+$8000
b101
 jmp ZPCODE+$A000
b11x
 bne b111
b110
 jmp ZPCODE+$C000
b111
 jmp ZPCODE+$E000

The MSBs of the program counter can easily be retrieved after the BRK instruction.

 

Another spot you may be able to save a bit is in bit 0 of Y. You'd have to adjust the operands of indexed instructions, but it might be doable.

 

Another spot to save 4.5 bits (a one-of-24 selection) would be the horizontal positions of P0, P1, M0, and M1. You can permute them any which way without affecting the on-screen appearance. Not sure you could avoid HMOVE lines if you did that, though, since you'd have to HMOVE the squares back and forth.

Share this comment


Link to comment

Hope you don't mind my snooping around in your code, but you've got a slight problem.

 

To generate your indexed stx/sty instructions, you use

  lda #$4A
 adc #$00
 asl
 sta opcode
 lda #$48
 bcs skip1
 sec
 sbc #$0F
skip1:
 bcc skip2
 nop
 nop
skip2:
 sta operand

This doesn't work. The opcode is generated correctly, but carry is always clear after the asl and set after the sbc, so the operand is always $39.

 

How about

  lda #255
 adc #$00; Make acc. hold 0 or 255
 and #$F1; (COLUPF ^ (COLUPF -15)) & 255
 eor #$08; COLUPF
 sta operand; Acc now holds $08 or $F9
 asl
 and #$02  ; The bit that's different between STY,x and STX,y
 eor #$96  ; If acc. was $08 we want STX,y
 sta opcode

That's a fixed 20 cycles (17 bytes). If you want to reverse the meaning of the carry flag, change the first "EOR" to "EOR #$F9". Alternatively, since Y is not not "live" there:

  bcs color2
color1:
 lda #$96 ; STX,Y
 ldy #COLUPF
 bcc colorstore
color2:
 lda #$94; STY,X
 ldy #[COLUPF-15] & 255
 nop
colorstore:
 sta opcode
 sty operand

That's a fixed 15 cycles (17 bytes) but as mentioned it does use the Y register; it also relies upon branches not to cross a page. If you didn't want to use the Y register, you could make the code 2 bytes longer while preserving the cycle count.

 

Another approach:

 rol
 and #1
 tay
 lda opcodes,y
 sta opcode
 lda operands,y
 sta operand

A fixed twenty cycles, BUT if you had things formatted differently you could do many squares at once:

; Assume bits 0-3 of accumulator hold color of four squares (the second and third of which need indexed addressing)
 and #15
 tay
 lda opcodes0,y
 sta opcode0
 lda opcodes1,y
 sta opcode1
 lda operands1,y
 sta operand1
 lda opcodes2,y
 sta opcode2
 lda operands2,y
 sta operand2
 lda opcodes3,y
 sta opcode3

 

Requires a few 16-byte tables, but manages a slight speedup.

Share this comment


Link to comment
I tried to keep the queen's ring, but that made it harder to distinguish between the queen and king. I'm open to suggestions.

 

This is what I was meaning... I slightly altered both the king and queen using the new dimensions you listed.

 

queenking6wj.gif

 

Chess logic coming anytime soon?  I can tell you what it's rated!  :)

Still working on Four-Play, and possibly another game for the 2006 1K contest.

 

Travesty!! ;) Your setup is awesome, much better than the striped version the original is. I know this game isn't your primary concern right now, but have you given any thought to having your engine contain opening lines or endgames? Or will it play entirely based on logic? I think at least a few of the most popular opening lines would help immensly to strengthen it's playing ability. Most high-level games today go 15-25 moves "by the book" with several games having followed each line for the players/computer to reference.

 

-JD

 

EDIT- also, have you given thought to the most important part, which is what you're going to name the game? :D How about Deep Fuji or X3D Fuji? ;)

Share this comment


Link to comment
I tried to keep the queen's ring, but that made it harder to distinguish between the queen and king. I'm open to suggestions.

 

How about (turned sideways)

-###--#--##
#-#-#######
-###--#--##

 

I think that's visually distinct from all the other pieces.

Share this comment


Link to comment

From supercat's suggestion in the previous post, in picture form. His version had one less line (11 instead of 12) so I just added one pixel to the top of each row.

 

queenking5ai.gif

 

EDIT- also changed the king to match the queen's new design.

Share this comment


Link to comment

I've played around with trying to see if I could do better on a chess kernel and seem to keep hitting dead ends. A few ideas I tried:

 

-1- Use VBLANK to truncate the left and right of the screen. This might be workable, but I haven't been able to get the start and end of the screen to really end at 'nice' spots; it's important that the sides end in such fashion as to allow the playfield and/or Ball to mask out the black areas during the "preload" lines.

 

-2- Reverse COLUPF and COLUBK, use HMOVE to blank the first two pixels of left-PF0, and the Ball to blank the other two. This would allow PF0 to be loaded at the same time as the right-hand PF2 is stored in temp.

 

-3- If fetching actions can be reduced entirely to PLA, the 'inc' can be eliminated; POPping a negative value (or positive, if colors are inverted) can signal an end condition (the colision latch at address 0 can be forced on or off as appropriate to ensure that stack underflow will exit).

 

All those ideas seem like they should have promise, but I couldn't get them to quite work.

Share this comment


Link to comment

Wow, there's a lot to reply to here.

 

The avatar could be from a night scene of a racing game... icon_ponder.gif

My new custom status should suggest that it's not a racing game.

 

It might be helpful if you offer a version of the demo in which a row of pieces alternates between white and black, and in which the PF data is all $FF, so as to show exactly when the color changes are taking place.

I'll PM you such a version.

 

Hope you don't mind my snooping around in your code, but you've got a slight problem.

I found that problem yesterday too. My fix was adding TXA and ASL to restore the carry bit, but I'll definitely look at your solutions too.

 

See--I just saved you six bytes.

Thanks for all the ideas for squeezing out memory. I made a quick list of information that would need to be saved during the kernel. It's possible I overlooked something.


  •  
  • 1 bit for current player
     
  • 6 bits for cursor position
     
  • 4 bits for piece under cursor (assuming cursor will blink)
     
  • 4 bits for castling conditions (for example, one bit is cleared if the black queen's rook moves)
     
  • 4 bit for en passant condition (At most one en passant capture can be done at a time. One bit will indicate whether en passant is legal and 3 bits will indicate where.)
     
  • 3 bits for up to 8 skill levels
     
  • 3 bits for up to 8 chess variants
    Total: 25
     

 

Travesty!! icon_razz.gif Your setup is awesome, much better than the striped version the original is. I know this game isn't your primary concern right now, but have you given any thought to having your engine contain opening lines or endgames?

Thanks. Yeah, if I ever get around to doing the logic it'd start with a standard opening and then use a minimax search to select moves.

 

From supercat's suggestion in the previous post, in picture form. His version had one less line (11 instead of 12) so I just added one pixel to the top of each row.

Looks good. You'll see these pieces in the next version.

Share this comment


Link to comment
Thanks for all the ideas for squeezing out memory. I made a quick list of information that would need to be saved during the kernel. It's possible I overlooked something.

  • [*]1 bit for current player

[*]6 bits for cursor position

[*]4 bits for piece under cursor (assuming cursor will blink)

[*]4 bits for castling conditions (for example, one bit is cleared if the black queen's rook moves)

[*]4 bit for en passant condition (At most one en passant capture can be done at a time. One bit will indicate whether en passant is legal and 3 bits will indicate where.)

[*]3 bits for up to 8 skill levels

[*]3 bits for up to 8 chess variants

 

You'll need some sort of timer to allow the person to move the cursor at reasonable (controllable) speed. If possible, handling the cursor in-kernel would eliminate the need to save underneath it. Alternatively, you could make the cursor flash a piece between white and black if a piece was underneath it (or flash an "X" if there was no piece there). Then you'd only need 1 bit to hold the flash count.

 

Three bits will suffice for en passant since a given board position can accommodate at most five possibilities.

 

Skill levels and/or variations could be set via difficulty switches.

 

To actually comply with tournament rules, you'd need a lot more memory than the 2600 has, even if the display kernel weren't a hog, because if a position occurs three times at any point in a game that yields a draw; tracking that would require logging all positions that have occurred. Even if you can't do that, something to watch for directly-repeated positions would be good.

Share this comment


Link to comment
Three bits will suffice for en passant since a given board position can accommodate at most five possibilities.

 

Skill levels and/or variations could be set via difficulty switches.

 

To actually comply with tournament rules, you'd need a lot more memory than the 2600 has, even if the display kernel weren't a hog, because if a position occurs three times at any point in a game that yields a draw; tracking that would require logging all positions that have occurred.  Even if you can't do that, something to watch for directly-repeated positions would be good.

 

I have played chess for a long time and only seen the 3 move repetition rule used once. As long as people know it's not part of the game's makeup I don't think it's a huge deal if you leave it out. Maybe you could spit out notation as you go along (not to be stored) that a serious player could write down and refer back to if they cared that much.

 

Interestingly enough, I think it's no big deal, but it was part of the Fischer/Spassky world championship match in Reykjavich. During game 17, in the midst of a potential Spassky comeback, Fischer conferred with the official who declared a draw from a game where he was down a rook for a knight. Following Fischer's draw, many western "experts" pointed to that moment as the momentum swing back to Fischer, and thought the draw crushed Spassky's spirit.

 

A quick google, you can find that game here if you want to click through it.

 

EDIT- it would help (some) that anytime a piece is captured, everything before that move can be reset (as they will not occur again). But, then there is also the 50 move rule, at which point you are way out of memory to track again.

Share this comment


Link to comment

Guest
Add a comment...

×   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...