REBOL

 

Reblox - Source Code

Challenging stacking block game.
Author: Allen Kamp
File size: 9K
Return to index

 

REBOL [
   Title: "REBLOX"  
   Author: "Allen Kamp"
   Email: allen@aussieweb.com.au
   Version: 1.0.2
   Date: 20-Feb-2002    
   Purpose: {Fun & Addictive block-matching game}
   Thanks: {Thanks to Chris RG for introducing me to this game.
            thanks to Robert Condon for help with the scoring system 
            And thanks to Anop Boonthaveepath for writing the java applet version I played} 
    History: [2-mar-2004 1.0.2 "Modified for REBOL/Plugin"]
]

reblox: context [

types: reduce [
    [color: red text:    "R"]
    [color: blue text:   "E"]
    [color: green text:  "B"]
    [color: pink text:   "O"]
    [color: orange text: "L"]
]

rows: 10
columns: 20
tiles: rows * columns
tile-size: 30x30
grid-size: to-pair reduce [columns * tile-size/x rows * tile-size/y]
title-height: 28
tface: none

max-type: rows * columns / length? types
if not integer? max-type [alert "max-type must be an integer"]

random/seed now/precise
puzzle: random 30000


;--Game State
locked: off
game-over?: false
last-found: none

tile-set: copy []
selected: copy []
score-table: copy []
patterns: [0x-1 -1x0 1x0 0x1]

to-index: func [rc [pair!]][
    either all [rc/x <= rows rc/y <= columns rc/x > 0 rc/y > 0][
        return ((rc/y - 1) * rows) + rc/x
    ][
        return none
    ]
] 

make-tile-set: does [
    foreach type types [insert/dup tile-set context type max-type]
]

make-score-table: has [s1 s2 s3 table][
    s1: 0.0
    s2: 2.0
    table: copy [0 [0] 1 [0]]
    repeat i max-type - 1 [
        append table reduce [i + 1 reduce [s3: s1 + s2]]
        s1: s2
        s2: s3
    ]
    table
]

scores-obj: context [
    selected: 0 worth: 0 tally: 0 removals: copy [] 
]

scores: make scores-obj []

remove-tiles: does [
    foreach face selected [
        hide-tile face  
    ]
    show selected
    move-tiles
    clear selected
]

sort-cols: func [a b][a/1 < b/1]

move-tiles: has [cols col][
    cols: copy []
    foreach face selected [
        either col: select cols face/rc/2 [
            append col face/rc
        ][
            repend cols [face/rc/2 reduce [face/rc]]
        ]
    ]
    sort/skip cols 2
    move-down cols
    move-left cols  
]

move-down: func [cols /local bottom top][
    foreach [col rcs] cols [
        sort/compare rcs :sort-cols
        bottom: last rcs
        top: -1x0 + bottom
        top/1: max top/1 1
        while [top/1 > 0][
            either copy-tile top bottom [
                bottom: bottom + -1x0
                top: -1x0 + bottom
            ][top: -1x0 + top]
        ] 
    ]
]


move-left: func [cols /local face rc rc-from rc-to count][
    count: 0
    foreach [col rcs] cols [
        face: get-tile rc: to-pair reduce [rows col - count]
        if not face/text [
            count: count + 1
            for c rc/2 columns 1 [
                repeat r rows [
                    copy-tile rc-from: to-pair reduce [r c] rc-to: to-pair reduce [r c - 1]
                ] 
            ]
        ]
    ]
]

find-moves: has [face below right match][

    ;-- last found is still there?
    if all [
        last-found 
        last-found/1/text 
        last-found/2/text
        last-found/1/text = last-found/2/text
    ][return last-found]

    ;-- search for a new one
    moves?: false   
    repeat r rows [
        repeat c columns [
            face: get-tile to-pair reduce [r c]
            below: get-tile to-pair reduce [r + 1 c]
            right: get-tile to-pair reduce [r c + 1]
            if any [
                if all [face below face/text below/text][if face/text = below/text [match: below]]
                if all [face right face/text right/text][if face/text = right/text [match: right]]
            ][
                return reduce [face match]
            ]
        ]
    ]
    return none
]

get-tile: func [rc /local index][
    index: to-index rc
    if index [pick lay/pane index]
]

copy-tile: func [rc-from rc-to][
    rc-from: get-tile rc-from
    rc-to: get-tile rc-to
    if all [rc-from rc-from/text][
        rc-to/color: rc-from/color
        rc-to/edge: make rc-to/edge [size: 3x3 color: rc-from/color + 30]
        set-font rc-to 'color white
        rc-to/text: rc-from/text
        hide-tile rc-from
        true
    ]
]

hide-tile: func [face][
    face/edge: make face/edge [size: 0x0]
    face/color: white
    set-font face 'color white
    face/text: none
]

clear-selected: does [
    foreach face selected [
        face/edge: make face/edge [size: 3x3]
        face/color: face/font/color
        set-font face 'color white
    ]
    show selected
    clear selected
]

mark-selected: func [face][
    set-font face 'color face/color
    face/color: white
    face/edge: make face/edge [size: 0x0]
    append selected face
]

find-same: func [face target /mark /local f][
    if all [face face/text = target not find selected face] [
        mark-selected face
        foreach pattern patterns [
            if f: get-tile (face/rc + pattern) [find-same f target]
        ]
    ]
]

update-scores: has [value][
    tsel/text: scores/selected
    twth/text: to-integer scores/worth 
    tscr/text: join "Score: " to-integer scores/tally
    show [tscr twth tsel]
]

click-action: [
    if locked [exit]
    locked: true
    either face/text [
        either find selected face [
            append scores/removals length? selected
            remove-tiles
            scores/tally: scores/tally + scores/worth
            show lay
            if none? last-found: find-moves [
                update-scores
                game-over?: true
                game-msg/show?: true
                show game-msg
                locked: true
                exit
            ]
        ][
            clear-selected
            find-same face face/text
            scores/selected: length? selected
            scores/worth: first select score-table (scores/selected)
            either (1 < length? selected) [show selected][clear-selected] 
        ]
    ][
        clear-selected
        scores/selected: 0
        scores/worth: 0
    ]
    update-scores
    locked: false
]

lay: [
    style bx box tile-size :click-action font [size: 14 shadow: none] edge [size: 3x3 effect: 'bevel] with [id: 0 rc: 0x0]
    space 0x0 origin 0x0 across
]

lay: layout/size head insert/dup tail lay 'bx (rows * columns) grid-size

make-grid: has [count face][
    count: 0
    repeat column columns [
        repeat row rows [
            count: count + 1
            face: pick lay/pane count
            face/rc: to-pair reduce [row column]
            face/offset:  to-pair reduce [(column - 1) * tile-size/x (row - 1) * tile-size/y]
            face/offset/y: face/offset/y + title-height
            face/id: count
        ]
    ]
]

make-game-msg: does [
    game-msg: layout/offset [
        origin 0x0
        text font-size 18 bold "GAME OVER" red
    ] 0x2
    game-msg/color: none
    game-msg/offset/x: lay/size/x / 2 - (game-msg/size/x / 2)
    game-msg/offset/y: 30
    append lay/pane game-msg    
]

; Add a title area because plugin doesn't have one, and the original script used one
title-face: copy []
add-title: does [
    title-face: layout [origin 0x0 space 0x0 at 0x0 tface: label right " " 600x26 white silver effect [emboss gradcol 1x1 140.140.140 100.100.100]
    at 1x1 image logo.gif 
]
    append lay/pane title-face/pane
]

make-score-board: has [req][
    score-board: layout [
        style text text middle left
        origin 0x0 space 0x0
        across 
        at 0x0 box 600x26 silver effect [emboss gradcol 1x1 140.140.140 100.100.100]    
        at 2x2 btn "New Game" [puzzle: random 30000 new-game]
        btn "Replay Game" [new-game]
        btn "Select Game" [
            if req: request-text/title "Game Puzzle Number?" [
                if not error? try [req: to-integer req][puzzle: req new-game] 
            ]
        ]
        btn-help [show-help]
        pad 10
        text "Selected:" tsel: text "000" 
        text "Worth:"    twth: text "204668310"
        tscr: text "Score: 204668310" right bold 
    ]
    score-board/size/x: tile-size/x * columns
    score-board/size/y: score-board/size/y + 8
    score-board/offset/y: title-height + grid-size/y + 2
    score-board/offset/x: 0
    score-board/edge: make face/edge [size: 3x3 color: silver effect: 'ibevel]
    lay/size/y: title-height + lay/size/y + score-board/size/y + 1
]

help-lay: none

show-help: does [
if not help-lay [
help-lay: center-face layout [origin 5x5 backcolor silver
    text as-is black ivory - 20 {
Objective: To achieve a high score or Remove all the blocks.
 
Play: Remove blocks which touch each other either vertically or horizontally.
 
Controls: Click once to select, and once again to remove blocks.
(If you change your mind, click on another set of blocks to unselect)
 
Bonus Points: The more blocks selected/removed in one go, the higher the score. 
} 450 bold edge [size: 1x1 color: navy]
]
]
unview/only help-lay
view/new help-lay

]

new-game: has [type mixed][
    random/seed: puzzle
    scores: make scores-obj []
    locked: off
    game-over?: false
    game-msg/show?: false
    last-found: none
    selected: head clear selected
    update-scores
    mixed: random copy tile-set
    repeat i tiles [
        type: mixed/:i
        tile: lay/pane/:i
        tile/text: copy type/text
        tile/color: type/color
        tile/edge: make tile/edge [color: type/color + 30 size: 3x3]
        set-font tile 'color white
    ]
    lay/text: join " REBLOX - Puzzle " puzzle
    tface/text: lay/text
    lay/changes: 'text
    show lay

]

init: does [
    score-table: make-score-table
    make-tile-set
    make-grid
    make-score-board
    add-title
    make-game-msg
    new-game
    view/new center-face lay
    append lay/pane score-board
    show lay
    do-events []

]
]

reblox/init