.. post:: 2013-03-16 :tags: C64, Pygments, BASIC, Assembler, Reversi, HP Codewars :category: C64 :excerpt: 1 Pygments highlights CBM BASIC & ca65 assembler sources ====================================================== Since version 1.6 the syntax highlighter `Pygments`_ has support for CBM BASIC V2 and assembler sources in ``ca65`` format. ``ca65`` is the macro assembler of the `cc65 C cross compiler`_ package. The `language list`_ does not have entries for them, but the lexer list in the documentation knows about *Ca65Lexer* in the `lexers for assembly languages`_ section and *CbmBasicV2Lexer* in the `lexers for other languages`_ section. .. _`Pygments`: http://pygments.org/ .. _`cc65 C cross compiler`: http://www.cc65.org/ .. _`language list`: http://pygments.org/languages/ .. _`lexers for assembly languages`: http://pygments.org/docs/lexers/#lexers-for-assembly-languages .. _`lexers for other languages`: http://pygments.org/docs/lexers/#lexers-for-other-languages Examples -------- Let's see the highlighter in action. Both examples solve `assignment 3 of the HP Codewars 2012`_. It is about interpreting a sequence of given `Reversi`_ moves and printing the resulting board state. .. _`assignment 3 of the HP Codewars 2012`: http://www.hpcodewars.org/past/cw15/problems/2012ProblemsFinalForPrinting.pdf .. _`Reversi`: https://en.wikipedia.org/wiki/Reversi Example of BASIC… .. code-block:: cbmbas 10 cp$="w":op$="b":dimb$(7,7):fori=0to7:forj=0to7:b$(i,j)=".":next:next 20 b$(3,3)="w":b$(4,3)="b":b$(3,4)="b":b$(4,4)="w":dimtx(7),ty(7):goto140 30 inputl$:ifl$="end"then end 40 y=asc(left$(l$,1))-asc("a"):x=val(right$(l$,1))-1:b$(y,x)=cp$ 50 forxd=-1to1:foryd=-1to1:if(xd or yd)=0then130 60 xt=x:yt=y:tc=0 70 xt=xt+xd:yt=yt+yd 80 ifxt<0orxt>7oryt<0oryt>7thentc=0:goto120 90 t$=b$(yt,xt):ift$<>op$then110 100 tx(tc)=xt:ty(tc)=yt:tc=tc+1:goto70 110 ift$<>cp$thentc=0 120 iftc>0then fori=0totc-1:b$(ty(i),tx(i))=cp$:next 130 next:next:t$=cp$:cp$=op$:op$=t$ 140 fori=0to7:forj=0to7:printb$(j,i);:next:print:next:print:goto30 …and Assembler (yes I know, it is loooong)… .. code-block:: ca65 chrout := $ffd2 getchr := $ffe4 .enum WHITE = 'w' BLACK = 'b' EMPTY = '.' .endenum .zeropage zp0 := $02 current_player := $b0 other_player := $b1 zp1 := $b2 zp2 := $b3 zp3 := $b4 zp4 := $b5 .bss board: .res 64 .proc start .code jsr init_game jmp print loop: jsr get_coordinate bcs exit jsr move print: jsr print_board jmp loop exit: rts .endproc ;-------------------------------------- ; Init the board with empty fields and the four pieces in the middle. ; Set `current_player` & `other_player` to `WHITE` & `BLACK`. ; ; Changes: `board`, `current_player`, `other_player` .proc init_game ldy #63 lda #EMPTY loop: sta board,y dey bpl loop lda #WHITE sta current_player sta board + 3*8+3 sta board + 4*8+4 lda #BLACK sta other_player sta board + 3*8+4 sta board + 4*8+3 rts .endproc ;-------------------------------------- ; Print the board. .proc print_board ldy #0 loop: tya ; index divisible by 8 ? and #%00000111 bne skip lda #13 ; print newline. jsr chrout skip: lda board,y jsr chrout iny cpy #64 bne loop lda #13 jmp chrout .endproc ;-------------------------------------- ; Gets the coordinate from the user. ; ; User input is not validated! ; ; In: - ; Out: ; X/A: x and y coordinate if Carry=0 ; Carry: if 1 then user entered "end" or pressed RUN/STOP. .proc get_coordinate .rodata end_txt: .byte "end", 13 end_txt_length := * - end_txt .bss buffer_length: .res 1 buffer: .res 16 .code lda #0 ; Read line into buffer. sta buffer_length @L1: jsr getchr beq @L1 ldy buffer_length sta buffer,y inc buffer_length cmp #3 ; RUN/STOP beq exit jsr chrout cmp #13 ; RETURN bne @L1 ldy #end_txt_length - 1 ; buffer == "end\n" ? @L2: lda buffer,y cmp end_txt,y bne continue dey bpl @L2 exit: sec rts continue: lda buffer ; convert coordinate sec sbc #'a' tax lda buffer+1 clc sbc #'0' clc rts .endproc ;-------------------------------------- ; Checks a line of tiles which should be turned. ; ; In: ; `check_line::x_`, `check_line::y_`: start coordinates ; X/Y: delta x and y between -1 and 1 for the direction ; in which the check is done. ; Out: ; `check_line::turn_coordinates`: the indices into `board` ; of the tiles to turn. ; A: count of indices in `check_line::turn_coordinates`. ; Changes: `zp0`, `zp1`, `zp2` .proc check_line x_ := zp1 y_ := zp2 turn_length := zp0 .bss turn_coordinates: .res 7 .code stx xd sty yd lda #0 sta turn_length loop: clc ; x += xd lda x_ xd := * + 1 adc #0 sta x_ clc ; y += yd lda y_ yd := * + 1 adc #0 sta y_ ;lda y_ ; check if x and y between 0 and 7 ora x_ and #%11111000 bne no_turns lda y_ ; Y = y*8+x asl asl asl ora x_ tay lda board,y ; board(x,t) == other_player ? cmp other_player bne line_end tya ; store index into board in turn_coordinates. ldy turn_length sta turn_coordinates,y inc turn_length bne loop line_end: cmp current_player ; board(x,y) == current_player ? bne no_turns lda turn_length rts no_turns: lda #0 rts .endproc ;-------------------------------------- ; Make a move and then switch players. ; ; In: ; X/A: coordinates of the move. ; Changes: `board`, `current_player`, `other_player`, ; `zp0`, `zp1`, `zp2`, `zp3`, `zp4` .proc move xd := zp3 yd := zp4 .code stx x_ sta y_ asl ; Set new player tile. asl asl ora x_ tay lda current_player sta board,y ; ; Two nested loops to check all 8 directions. ; lda #< -1 ; for xd = -1 to... sta xd outer_loop: lda #< -1 ; for yd = -1 to... sta yd inner_loop: ;lda yd ; if (xd | yd) = 0 then continue. ora xd beq inner_loop_continue x_ := * + 1 lda #0 sta check_line::x_ y_ := * + 1 lda #0 sta check_line::y_ ldx xd ldy yd jsr check_line cmp #0 ; turns ? beq skip_turn_loop tay ; do turns. lda current_player turn_loop: ldx check_line::turn_coordinates-1,y sta board,x dey bne turn_loop skip_turn_loop: inner_loop_continue: inc yd ; next yd lda yd cmp #2 bne inner_loop inc xd ; next xd lda xd cmp #2 bne outer_loop lda current_player ; swap players. ldx other_player sta other_player stx current_player rts .endproc