123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730 |
- /*
- * File : tetris_modal.c
- * This file is part of RTGUI in RT-Thread RTOS
- * COPYRIGHT (C) 2010, RT-Thread Development Team
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rt-thread.org/license/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2010-08-14 Yi.Qiu first version
- */
-
- #include <rtthread.h>
- #include <stdlib.h>
- #include "tetris.h"
- struct rt_tetris
- {
- rt_uint32_t width; /* the width of the tetris */
- rt_uint32_t height; /* the height of the tetris */
- rt_uint16_t* panel; /* the panel of the tetris */
- rt_uint32_t* brick; /* the current brick of the tetris */
- rt_uint32_t* next_brick; /* the next brick of the tetris */
- rt_tetris_view_t* view; /* the view on which the tetris show */
- rt_uint32_t level; /* game level */
- rt_uint32_t lines; /* released lines count */
- rt_uint32_t score; /* total scores statistic */
- rt_bool_t status; /* game status, pause or runing */
- };
- static const rt_uint32_t g_brick[][4] =
- {
- {23,7,8,22},
- {23,7,8,24},
- {24,7,8,25},
- {8,7,9,23},
- {8,7,9,24},
- {8,7,9,25},
- {7,6,8,9},
- };
- static rt_err_t rt_tetris_append_brick(rt_tetris_t* thiz, rt_uint32_t brick[]);
- static rt_err_t rt_tetris_delete_brick(rt_tetris_t* thiz, rt_uint32_t brick[]);
- static rt_err_t rt_tetris_release_lines(rt_tetris_t* thiz, rt_uint32_t brick[]);
- static rt_err_t rt_tetris_is_reach_top(rt_tetris_t* thiz, rt_uint32_t brick[]);
- static rt_err_t rt_tetris_update_brick(rt_tetris_t* thiz);
- /**
- * this function create a tetris instance
- *
- * @param width the width of tetris.
- * @param height the height of tetris.
- *
- * @return the tetris instance
- */
- rt_tetris_t* rt_tetris_create(rt_uint32_t width, rt_uint32_t height)
- {
- int index;
- rt_tetris_t* thiz = (rt_tetris_t*)rt_malloc(sizeof(rt_tetris_t));
- RT_ASSERT(thiz != RT_NULL);
- thiz->height = height;
- thiz->width = width;
- thiz->panel = rt_malloc(thiz->height * sizeof(rt_uint32_t));
- rt_memset(thiz->panel, 0, thiz->height * sizeof(rt_uint32_t));
- thiz->brick = (rt_uint32_t*)rt_malloc(4 * sizeof(rt_uint32_t));
- index = (int)(7.0 * rand()/(RAND_MAX + 1.0));
- rt_memcpy(thiz->brick, g_brick[index], 4 * sizeof(rt_uint32_t));
- thiz->next_brick= (rt_uint32_t*)rt_malloc(4 * sizeof(rt_uint32_t));
- index = (int)(7.0 * rand()/(RAND_MAX + 1.0));
- rt_memcpy(thiz->next_brick, g_brick[index], 4 * sizeof(rt_uint32_t));
- thiz->view = RT_NULL;
- thiz->level = 0;
- thiz->lines = 0;
- thiz->score = 0;
- thiz->status = RT_FALSE;
- return thiz;
- }
- /**
- * this function destory a tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK
- */
- rt_err_t rt_tetris_destory(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz->panel && thiz->brick && thiz->next_brick);
- rt_free(thiz->panel);
- rt_free(thiz->brick);
- rt_free(thiz->next_brick);
- rt_free(thiz);
- return RT_EOK;
- }
- /**
- * this function start tetris game
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK
- */
- rt_err_t rt_tetris_start(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- /* update next brick on view */
- thiz->view->update_next_brick(thiz->view, thiz);
- /* update level */
- thiz->view->update_level(thiz->view, thiz);
- /* update lines and score */
- thiz->view->update_score_and_lines(thiz->view, thiz);
- thiz->status = RT_TRUE;
- return RT_EOK;
- }
- /**
- * this function pause tetris game
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK
- */
- rt_err_t rt_tetris_pause(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- thiz->status = RT_FALSE;
- return RT_EOK;
- }
- /**
- * this function get width of a tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the width of the tetris instance
- */
- rt_uint32_t rt_tetris_width(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->width;
- }
- /**
- * this function get next brick of a tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the next brick of the tetris instance
- */
- rt_uint32_t* rt_tetris_next_brick(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->next_brick;
- }
- /**
- * this function get level of the tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the level of the tetris instance
- */
- rt_uint32_t rt_tetris_level(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->level;
- }
- /**
- * this function get released lines of the tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the released lines of the tetris instance
- */
- rt_uint32_t rt_tetris_lines(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->lines;
- }
- /**
- * this function get score of the tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the score of the tetris instance
- */
- rt_uint32_t rt_tetris_score(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->score;
- }
- /**
- * this function get height of a tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the height of the tetris instance
- */
- rt_uint32_t rt_tetris_height(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->height;
- }
- /**
- * this function get status of a tetris instance
- *
- * @param thiz the tetris instance.
- *
- * @return the status of the tetris instance
- */
- rt_bool_t rt_tetris_status(rt_tetris_t* thiz)
- {
- RT_ASSERT(thiz != RT_NULL);
- return thiz->status;
- }
- /**
- * this function makes current brick move down
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_down(rt_tetris_t* thiz)
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- if(thiz->status == RT_FALSE) return -RT_ERROR;
- /* delete the brick from tetris panel */
- rt_tetris_delete_brick(thiz, thiz->brick);
- for(i=0; i<4; i++)
- {
- /* check collision and bottom*/
- if((thiz->brick[i] >= thiz->width * (thiz->height - 1))
- || rt_tetris_check_collision(thiz, thiz->brick[i] + thiz->width) == RT_EOK)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- if(rt_tetris_is_reach_top(thiz, thiz->brick) == RT_EOK)
- {
- rt_memset(thiz->panel, 0xff, thiz->height * sizeof(rt_uint32_t));
- /* update view */
- thiz->view->update(thiz->view, thiz);
- /* game over */
- return -RT_ETIMEOUT;
- }
- if(rt_tetris_release_lines(thiz, thiz->brick) == RT_EOK)
- {
- /* update view */
- thiz->view->update(thiz->view, thiz);
- }
- rt_tetris_update_brick(thiz);
- return -RT_ERROR;
- }
- }
- for(i=0; i<4; i++)
- {
- /* increase one line */
- thiz->brick[i] += thiz->width;
- }
- /* append the brick to tetris panel */
- rt_tetris_append_brick(thiz, thiz->brick);
- /* update view */
- thiz->view->update(thiz->view, thiz);
- return RT_EOK;
- }
- /**
- * this function makes current brick move left
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_left(rt_tetris_t* thiz)
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- if(thiz->status == RT_FALSE) return -RT_ERROR;
- /* delete the brick from tetris panel */
- rt_tetris_delete_brick(thiz, thiz->brick);
- for(i=0; i<4; i++)
- {
- /* check left board */
- if((thiz->brick[i] % thiz->width) == 0)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- if(rt_tetris_check_collision(thiz, thiz->brick[i] - 1) == RT_EOK)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- }
-
- for(i=0; i<4; i++)
- {
- /* move one step to left */
- thiz->brick[i] --;;
- }
- /* append the brick to tetris panel */
- rt_tetris_append_brick(thiz, thiz->brick);
- /* update view */
- thiz->view->update(thiz->view, thiz);
- return RT_EOK;
- }
- /**
- * this function makes current brick move right
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_right(rt_tetris_t* thiz)
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- if(thiz->status == RT_FALSE) return -RT_ERROR;
- /* delete the brick from tetris panel */
- rt_tetris_delete_brick(thiz, thiz->brick);
- for(i=0; i<4; i++)
- {
- /* check left board */
- if(((thiz->brick[i] + 1) % thiz->width) == 0)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- /* check collision */
- if(rt_tetris_check_collision(thiz, thiz->brick[i] + 1) == RT_EOK)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- }
-
- for(i=0; i<4; i++)
- {
- /* move one step to right */
- thiz->brick[i] ++;;
- }
- /* append the brick to tetris panel */
- rt_tetris_append_brick(thiz, thiz->brick);
- /* update view */
- thiz->view->update(thiz->view, thiz);
- return RT_EOK;
- }
- /**
- * this function makes current brick drop quickly
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_drop(rt_tetris_t* thiz)
- {
- rt_err_t ret;
- RT_ASSERT(thiz != RT_NULL);
- if(thiz->status == RT_FALSE) return -RT_ETIMEOUT;
- /* move down until blocked */
- while((ret = rt_tetris_down(thiz)) == RT_EOK);
- return ret;
- }
- /**
- * this function makes current brick do rotation
- *
- * @param thiz the tetris instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_rotate(rt_tetris_t* thiz, rt_bool_t direction)
- {
- int i;
- rt_uint32_t tmp[4];
- RT_ASSERT(thiz != RT_NULL);
- if(thiz->status == RT_FALSE) return -RT_ERROR;
- rt_tetris_delete_brick(thiz, thiz->brick);
- tmp[0] = thiz->brick[0];
- for(i=1; i<4; i++)
- {
- int diff = thiz->brick[0] - thiz->brick[i];
- if(diff == 1)
- {
- tmp[i] = thiz->brick[0] - thiz->width;
- }
- else if(diff == -1)
- {
- tmp[i] = thiz->brick[0] + thiz->width;
- }
- else if(diff == 2)
- {
- tmp[i] = thiz->brick[0] - 2 * thiz->width;
- }
- else if(diff == -2)
- {
- tmp[i] = thiz->brick[0] + 2 * thiz->width;
- }
- else if(diff == thiz->width - 1)
- {
- tmp[i] = thiz->brick[0] + thiz->width + 1;
- }
- else if(diff == 1 - thiz->width)
- {
- tmp[i] = thiz->brick[0] - thiz->width - 1;
- }
- else if(diff == thiz->width)
- {
- if((thiz->brick[0] + 1) % thiz->width == 0)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- else tmp[i] = thiz->brick[0] + 1;
- }
- else if(diff == -1 * (thiz->width))
- {
- if(thiz->brick[0] % thiz->width == 0)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- else tmp[i] = thiz->brick[0] - 1;
- }
- else if(diff == thiz->width + 1)
- {
- tmp[i] = thiz->brick[0] - thiz->width + 1;
- }
- else if(diff == -1 - thiz->width)
- {
- tmp[i] = thiz->brick[0] + thiz->width - 1;
- }
- else if(diff == 2 * thiz->width)
- {
- if((thiz->brick[0] % thiz->width) >= (thiz->width - 2))
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- else tmp[i] = thiz->brick[0] + 2;
- }
- else if(diff == -2 * thiz->width)
- {
- if((thiz->brick[0] % thiz->width) < 2)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- else tmp[i] = thiz->brick[0] - 2;
- }
-
- if(tmp[i] > (thiz->height) * thiz->width)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- if(rt_tetris_check_collision(thiz, tmp[i]) == RT_EOK)
- {
- /* restore the deleted brick */
- rt_tetris_append_brick(thiz, thiz->brick);
- return -RT_ERROR;
- }
- }
- /* do roration */
- for(i=0; i<4; i++)
- {
- thiz->brick[i] = tmp[i];
- }
- /* append the brick to tetris panel */
- rt_tetris_append_brick(thiz, thiz->brick);
- /* update view */
- thiz->view->update(thiz->view, thiz);
- return RT_EOK;
- }
- /**
- * this function add a view to the tetris
- *
- * @param thiz the tetris instance.
- * @param view the view instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_add_view(rt_tetris_t* thiz, rt_tetris_view_t* view)
- {
- RT_ASSERT(thiz != RT_NULL);
- /* Only suppurt single view now */
- thiz->view = view;
- return RT_EOK;
- }
- /**
- * this function delete a view from the tetris
- *
- * @param thiz the tetris instance.
- * @param view the view instance.
- *
- * @return RT_EOK on success, -RT_ERROR on fail
- */
- rt_err_t rt_tetris_delete_view(rt_tetris_t* thiz, rt_tetris_view_t* view)
- {
- RT_ASSERT(thiz != RT_NULL);
- thiz->view = RT_NULL;
- return RT_EOK;
- }
- /**
- * this function used to check collision
- *
- * @param thiz the tetris instance.
- * @param block the block to be checked.
- *
- * @return RT_EOK on collision, -RT_ERROR on not collision
- */
- rt_err_t rt_tetris_check_collision(rt_tetris_t* thiz, rt_uint32_t block)
- {
- RT_ASSERT(thiz != RT_NULL);
- RT_ASSERT(block < thiz->height * thiz->width);
- if((thiz->panel[block/thiz->width] & (1 << (block % thiz->width)))
- == (1 << (block % thiz->width)))
- {
- return RT_EOK;
- }
- else
- {
- return -RT_ERROR;
- }
- }
- static rt_err_t rt_tetris_update_brick(rt_tetris_t* thiz)
- {
- int index;
- RT_ASSERT(thiz != RT_NULL);
- index = (int)(7.0 * rand()/(RAND_MAX + 1.0));
- rt_memcpy(thiz->brick, thiz->next_brick, 4 * sizeof(rt_uint32_t));
- rt_memcpy(thiz->next_brick, g_brick[index], 4 * sizeof(rt_uint32_t));
- /* update next brick on view */
- thiz->view->update_next_brick(thiz->view, thiz);
-
- return RT_EOK;
- }
- static rt_err_t rt_tetris_append_brick(rt_tetris_t* thiz, rt_uint32_t brick[])
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- RT_ASSERT(brick != RT_NULL);
- for(i=0; i<4; i++)
- {
- int y = brick[i]/thiz->width;
- int x = brick[i]%thiz->width;
- thiz->panel[y] |= (1<<x);
- }
- return RT_EOK;
- }
- static rt_err_t rt_tetris_delete_brick(rt_tetris_t* thiz, rt_uint32_t brick[])
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- RT_ASSERT(brick != RT_NULL);
- for(i=0; i<4; i++)
- {
- int y = brick[i]/thiz->width;
- int x = brick[i]%thiz->width;
- thiz->panel[y] &= ~(1<<x);
- }
- return RT_EOK;
- }
- static rt_err_t rt_tetris_is_reach_top(rt_tetris_t* thiz, rt_uint32_t brick[])
- {
- int i;
- RT_ASSERT(thiz != RT_NULL);
- RT_ASSERT(brick != RT_NULL);
- for(i=0; i<4; i++)
- {
- if(brick[i] / thiz->width == 0)
- return RT_EOK;
- }
- return -RT_ERROR;
- }
- static rt_err_t rt_tetris_release_lines(rt_tetris_t* thiz, rt_uint32_t brick[])
- {
- int i, j, check_line = 0;
- rt_bool_t line_released = -RT_ERROR;
- RT_ASSERT(thiz != RT_NULL);
- RT_ASSERT(brick != RT_NULL);
- for(i=0; i<4; i++)
- {
- /* choose a line */
- check_line = brick[i]/thiz->width;
- if((thiz->panel[check_line]) == ((1 << thiz->width) - 1))
- {
- for(j=check_line; j>0; j--)
- {
- thiz->panel[j] = thiz->panel[j-1];
- }
-
- /* clear the first line */
- thiz->panel[0] = 0;
-
- for(j=i+1; j<4; j++)
- {
- if(brick[j] < brick[i])
- {
- brick[j] += thiz->width;
- }
- }
-
- thiz->lines++;
- thiz->score += 100;
- line_released = RT_EOK;
- }
- }
- if(line_released == RT_EOK)
- {
- /* update view */
- thiz->view->update_score_and_lines(thiz->view, thiz);
- return RT_EOK;
- }
- else
- {
- return -RT_ERROR;
- }
- }
|