Click here to Skip to main content
13,146,402 members (48,080 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

4K views
37 downloads
6 bookmarked
Posted 30 Apr 2016

Squares Puzzle using RingAllegro

, 1 May 2016
Rate this:
Please Sign up or sign in to vote.
This Article is about 2D games programming simplicity using RingAllegro Library.

The Source Code

Introduction

Squares puzzle game is a very known and popular game that almost all of you have played using different platforms or tools. The very recent sample that I used was "Shuffle 'n Slide Brain Game" on android. This game is all about slicing an image into 9 pieces that plotted randomly on a board so you are supposed to reorganize them to get the correct image.

Background

RingAllegro is a very powerful and simple extension of the Ring Programming Language that is based on Allegro library specialized in creating 2D games easly and fluently with high interaction capacity in a reasonable way of 2D game development ideas.

The Ring Programming Language is a recently released innovative and practical general-purpose multi-paradigm scripting language that can be embedded in C/C++ projects, extended using C/C++ code and/or used as standalone language. The supported programming paradigms are Imperative, Procedural, Object-Oriented, Functional, Meta programming, Declarative programming using nested structures, and Natural programming. The language is portable (Windows, Linux, Mac OS X, Android, etc.) and can be used to create Console, GUI, Web, Games and Mobile applications. The language is designed to be Simple, Small, Flexible and Fast. Its Dynamic Language (Dynamic Typing and Weakly Typed) that compile the source code to byte code then execute it by the Ring Virtual Machine, which is integrated with the Ring Compiler in one program.

Coding Principles in Ring

The coding process in Ring Programming Language has special principles, that we have to follow, which have been built to achieve high range of programing convenience between different programmers and developers, and to be easly used with its multi-paradigm philosophy. For now, I have to show some of them as necessary to disclose points that are important for reading to become smoother.

Ring Programming Language doesn't consider Main method essential so that the written code will be executed from the first line to the end. In this case all of code parts should be organized in a special manner following the next sequence:

1- Files Loading.

2- Statements and global variables.

3- Functions.

4- Packages and classes.

* Other things that we should consider about Ring coding are:

1- Not case sensitive.

2- No explicit end for statements (No ; or ENTER is required).

3- Call Function before definition.

4- No keyword to end Functions/Classes/Packages.

Code Overview

The code is kind of self explanatory if you have some knowledge about RingAllegro and Allegro Library functions, so that I will try to walk through its main sections with some comments.

Initialization and board preparing:

As a lot of programming language, Ring programming language starts its code with inclusions then variables definition.

Load "gamelib.ring"

BoardDim = 398      # Board dimension
SquarePostions = [[0,0],2,3,4,5,6,7,8,9] # Each position contain x,y
SquareDim = 0       # Square dimensoin
Moves = 0           # To count number of moves as to estimate the level of solving strategies
Squares = ["square",1]  # Each square combined with its current position during playing

Then we have to initialize RingAllegro library and create/prepare the main window that will contain playing board, sliced images and labels on and below the board.

# Initialization ===========
al_init()
al_init_image_addon()
al_init_font_addon()
al_init_ttf_addon()
font = al_load_ttf_font("pirulen.ttf",14,0 )

display = al_create_display(406,500)
al_clear_to_color(al_map_rgb(255,255,255))

Board = al_create_bitmap(boarddim,boarddim)
al_set_target_bitmap(board)
al_clear_to_color(al_map_rgb(220,220,220))
al_set_target_bitmap(al_get_backbuffer(display))
al_draw_bitmap(board,al_get_display_width(display) / 2 - boarddim /2,al_get_display_height(display) / 2 - boarddim / 2,0)

Image = al_create_sub_bitmap(al_load_bitmap("palace.jpg"),0,0,boarddim - 8 ,boarddim - 8)

MoveLabel = al_create_bitmap(al_get_display_width(display),30)
al_set_target_bitmap(movelabel)
al_clear_to_color(al_map_rgb(220,220,220))

al_set_target_bitmap(al_get_backbuffer(display))
al_draw_text(font, al_map_rgb(0,0,0), 150, 20,ALLEGRO_ALIGN_LEFT, "Squares :)")

al_flip_display()  # This function is very important after each change to be displayed

Then We have to initialize event listening mechanism of Allegro library which composed of event queue and input registration like this;

# Events Initialization ===============================
event_queue = al_create_event_queue()
ev = al_new_allegro_event()
al_register_event_source(event_queue, al_get_display_event_source(display))
al_install_mouse()
al_register_event_source(event_queue, al_get_mouse_event_source())
al_install_keyboard()
al_register_event_source(event_queue, al_get_keyboard_event_source())

Then we have to determine the exact x,y of each position should squares assume, followed by slicing squares from all over the picture.

# SetSquaresPositionsAndDimensions =======================
squaredim = (boarddim - 8) / 3
boardx = al_get_display_width(display) /2 - boarddim /2
boardy = al_get_display_height(display) /2 - boarddim /2
SquarePostions[1] = [boardx +2 , boardy +2]
SquarePostions[2] = [boardx + squaredim + 4, boardy +2]
SquarePostions[3] = [boardx + squaredim * 2 + 6, boardy +2]
SquarePostions[4] = [boardx +2 , boardy + squaredim + 4]
SquarePostions[5] = [boardx + squaredim + 4, boardy + squaredim + 4]
SquarePostions[6] = [boardx + squaredim * 2 + 6, boardy + squaredim + 4]
SquarePostions[7] = [boardx +2 , boardy + squaredim * 2 + 6]
SquarePostions[8] = [boardx + squaredim + 4, boardy + squaredim * 2 + 6]
SquarePostions[9] = [boardx + squaredim * 2 + 6, boardy + squaredim * 2 + 6]

# CreateSquares ==========================
squares = list(9)
ind = 1
for j = 0 to 2
    for i = 0 to 2
        squares[ind] = [al_create_sub_bitmap(image,i * squaredim, j * squaredim,squaredim,squaredim),-1]
        ind += 1
    next
next
squares[9] = [al_create_sub_bitmap(board,1,1,squaredim,squaredim),-1]

Playing and Interaction:

Before starting the game challenge we have to give the player a shot to make solving strategy easer.

# Draw full Pic with timer ===========
al_draw_bitmap(image,al_get_display_width(display) /2 - boarddim /2 + 4,al_get_display_height(display) /2 - boarddim /2 + 4,0)
al_flip_display()

timer = al_create_timer(1)
al_register_event_source(event_queue, al_get_timer_event_source(timer))
al_start_timer(timer)

moves = 3
while true
    al_wait_for_event(event_queue, ev)
    al_draw_bitmap(movelabel,0,al_get_display_height(display) - 30,0)
    al_draw_text(font, al_map_rgb(0,0,0), 200, al_get_display_height(display) - 20,ALLEGRO_ALIGN_LEFT, string(moves))
    moves -= 1
    al_flip_display()
    if moves = -1 moves = 0 exit ok
end
al_destroy_timer(timer)
al_rest(1)
al_draw_bitmap(movelabel,0,al_get_display_height(display) - 30,0)
al_draw_text(font, al_map_rgb(0,0,0), 150, al_get_display_height(display) - 20,ALLEGRO_ALIGN_LEFT, "Moves : " + moves)
al_flip_display()

Now its time to bring the player into the challenge by randomizing squares positions and draw them on the board.

# RandomizePositions ================================
for i = 1 to 9
    while true
        Ind = LimitRandom(1,9)
        found = false
        for s in squares
            if ind = s[2] found = true ok
        next
        if found = false squares[i][2] = ind exit ok
    end
next

# DrawRandomizedSquares ===============
al_set_target_bitmap(al_get_backbuffer(display))
al_draw_bitmap(board,al_get_display_width(display) / 2 - boarddim /2,al_get_display_height(display) / 2 - boarddim / 2,0)
for s in squares
    al_draw_bitmap(s[1],SquarePostions[s[2]][1],SquarePostions[s[2]][2],0)
next
al_flip_display()

Now its time to put the ball in front of the player to make him/her show his/her best :)

This could be done using while loop which include listening for the player interaction, applying his/her chosen move then checking for correct solution of the whole puzzle.

When the player completed the puzzle seccessfully we have to estimate and give opinion about his/her effort solving the puzzle depending on the number of moves he/she used.

while true
    al_wait_for_event(event_queue, ev)
    switch al_get_allegro_event_type(ev)
    on ALLEGRO_EVENT_DISPLAY_CLOSE
        exit
    on ALLEGRO_EVENT_MOUSE_BUTTON_UP
        mouse_x = al_get_allegro_event_mouse_x(ev)
        mouse_y = al_get_allegro_event_mouse_y(ev)
        for cursqr = 1 to 9
            dx = mouse_x - SquarePostions[cursqr][1]
            dy = mouse_y - SquarePostions[cursqr][2]
            if dx < squaredim and dx > 0
                if dy < squaredim and dy > 0
                    ns = CheckNearSpace(cursqr)
                    if ns != 0 exsquareposition(cursqr,ns)
                    ok
                ok
            ok
        next
    on ALLEGRO_EVENT_KEY_UP
        switch al_get_allegro_event_keyboard_keycode(ev)
        on ALLEGRO_KEY_UP
            ps = GiveSelectedSqrInd(1)
            if ps != 0 exsquareposition(ps,squares[9][2]) ok
        on ALLEGRO_KEY_DOWN
            ps = GiveSelectedSqrInd(3)
                     if ps != 0 exsquareposition(ps,squares[9][2]) ok
                    on ALLEGRO_KEY_LEFT
            ps = GiveSelectedSqrInd(4)
                     if ps != 0 exsquareposition(ps,squares[9][2]) ok
                    on ALLEGRO_KEY_RIGHT
            ps = GiveSelectedSqrInd(2)
                     if ps != 0 exsquareposition(ps,squares[9][2]) ok
        off
    off
    if Solved() = true
        ft = al_load_ttf_font("pirulen.ttf",20,0 )
        lastpanel = al_create_bitmap(350,70)
        al_set_target_bitmap(lastpanel)
        al_clear_to_color(al_map_rgb(255,255,255))
        al_set_target_bitmap(al_get_backbuffer(display))
        al_draw_bitmap(lastpanel,al_get_display_width(display) /2 - boarddim /2 + 24,al_get_display_height(display) /2 -30,0)
if moves < 50
        al_draw_text(ft, al_map_rgb(0,0,0), 40, al_get_display_height(display) /2 - 20,ALLEGRO_ALIGN_LEFT, "Congratulations ^_^")
        al_draw_text(font, al_map_rgb(0,0,0), 80, al_get_display_height(display) /2,ALLEGRO_ALIGN_LEFT, "You Are Really Genius")
but moves >= 50 and moves < 100
        al_draw_text(ft, al_map_rgb(0,0,0), 40, al_get_display_height(display) /2 - 20,ALLEGRO_ALIGN_LEFT, "Congratulations ^_^")
        al_draw_text(font, al_map_rgb(0,0,0), 100, al_get_display_height(display) /2,ALLEGRO_ALIGN_LEFT, "You Are Really Smart")
but moves >= 100 and moves < 200
        al_draw_text(ft, al_map_rgb(0,0,0), 40, al_get_display_height(display) /2 - 20,ALLEGRO_ALIGN_LEFT, "Congratulations ^_^")
        al_draw_text(font, al_map_rgb(0,0,0), 100, al_get_display_height(display) /2,ALLEGRO_ALIGN_LEFT, "You Are Smart")
but moves >= 200    
        al_draw_text(ft, al_map_rgb(0,0,0), 40, al_get_display_height(display) /2 - 20,ALLEGRO_ALIGN_LEFT, "Congratulations ^_^")
        al_draw_text(font, al_map_rgb(0,0,0), 90, al_get_display_height(display) /2,ALLEGRO_ALIGN_LEFT, "But Slowly Solved")
ok
        al_flip_display()
        al_rest(15)
        exit
    ok
end

Finalization and Functions:

After solving the puzzle we have to finalize and destroy previously used RingAllegro components like this;

# Finalization =================
al_destroy_event_queue(event_queue)
al_destroy_allegro_event(ev)
for s in squares
    al_destroy_bitmap(s[1])
next
al_destroy_bitmap(image)
al_destroy_bitmap(board)
al_destroy_display(display)    

al_exit()

Finally we have finished the major code that executes this simple game but the rest of lines of code that we didn't talk about are for the functions that have been defined and used locally in this game because this is the rule of code organization in Ring Language to declare classes and functions at the bottom of the code.

func LimitRandom S,E
while true
r = random(e)
if r >= s return r ok
end

func ExSquarePosition filled,spaced
    al_set_target_bitmap(al_get_backbuffer(display))
    al_draw_bitmap(squares[find(squares,filled,2)][1],SquarePostions[squares[9][2]][1],SquarePostions[squares[9][2]][2],0)
    al_draw_bitmap(squares[9][1],SquarePostions[filled][1],SquarePostions[filled][2],0)
    squares[9][2] = filled
    squares[find(squares,filled,2)][2] = spaced
    moves += 1
    al_draw_bitmap(movelabel,0,al_get_display_height(display) - 30,0)
    al_draw_text(font, al_map_rgb(0,0,0), 150, al_get_display_height(display) - 20,ALLEGRO_ALIGN_LEFT, "Moves : " + moves)
    al_flip_display()

func CheckNearSpace i
    S = squares[9][2]
    switch i
    on 1
        switch s on 2 return s on 4 return s off
    on 2
        switch s on 1 return s on 3 return s on 5 return s off
    on 3
        switch s on 2 return s on 6 return s off
    on 4
        switch s on 1 return s on 5 return s on 7 return s off
    on 5
        switch s on 2 return s on 4 return s on 6 return s on 8 return s off
    on 6
        switch s on 3 return s on 5 return s on 9 return s off
    on 7
        switch s on 4 return s on 8 return s off
    on 8
        switch s on 5 return s on 7 return s on 9 return s off
    on 9
        switch s on 6 return s on 8 return s off
    off
return 0

func GiveSelectedSqrInd Dir # Up 1, Right 2, Down 3, Left 4
    S = squares[9][2]
    switch s
    on 1
        switch dir on 1 return 4 on 4 return 2 off
    on 2
        switch dir on 1 return 5 on 2 return 1 on 4 return 3 off
    on 3
        switch dir on 1 return 6 on 2 return 2 off
    on 4
        switch dir on 1 return 7 on 4 return 5 on 3 return 1 off
    on 5
        switch dir on 1 return 8 on 2 return 4 on 3 return 2 on 4  return 6 off
    on 6
        switch dir on 1 return 9 on 2 return 5 on 3 return 3 off
    on 7
        switch dir on 3 return 4 on 4 return 8 off
    on 8
        switch dir on 2 return 7 on 3 return 5 on 4 return 9 off
    on 9
        switch dir on 2 return 8 on 3 return 6 off
    off
return 0

func Solved
    for i = 1 to 9
    if squares[i][2] != i return false ok
    next
return true

Points of Interest

The major point of interest that I have to declare here is the easiness and simplicity of coding journey using Ring Programming Language as I'm not supposed to worry about type of variables that should I use or type and size even dimension of arrays that can be used.

Other point is that this game could be played cross-platformly so that I could comfortably porting it to other OS with a large ease.

The last thing I wanna highlight is that, Allegro library has a very nice innovative way of programming simple games with already clear predefined functions so that I think I'm really lucky to find it already integrated with Ring Programming Language.

Resources

1- Ring Programming Language Website.

2- Allegro Library Website.

3- This game's Github repository.

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Majdi Sobain
Student
Yemen Yemen
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionPuzzle logic (not programming) Pin
Michael J Churchill3-May-16 21:44
memberMichael J Churchill3-May-16 21:44 
AnswerRe: Puzzle logic (not programming) Pin
Majdi Sobain25-May-16 4:15
memberMajdi Sobain25-May-16 4:15 
GeneralMy vote of 5 Pin
Mahmoud Samir Fayed1-May-16 23:45
memberMahmoud Samir Fayed1-May-16 23:45 
GeneralRe: My vote of 5 Pin
Majdi Sobain2-May-16 10:13
memberMajdi Sobain2-May-16 10:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170915.1 | Last Updated 2 May 2016
Article Copyright 2016 by Majdi Sobain
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid