/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2009 Clément Pit--Claudel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #include "lib/configfile.h" #include "lib/playback_control.h" #include "lib/pluginlib_actions.h" PLUGIN_HEADER /* Limits */ #define MAX_PIECES_COUNT 5 #define MAX_COLORS_COUNT 8 #define MAX_GUESSES_COUNT 10 const struct button_mapping *plugin_contexts[] = {generic_directions, generic_actions}; /* * Screen structure: * * (guesses_count) lines of guesses, * * 1 center line of solution (hidden), * * 1 line showing available colors. * * Status vars: * * quit: exit the plugin * * leave: restart the plugin (leave the current game) * * game_ended: the game has ended * * found: the combination has been found * * Colors used are taken from the Tango project. * * Due to integer truncations, 2 vars are used for some objects' dimensions * (eg. true_guess_w, true_score_w). The actual dimension of these objects is * stored in the corresponding var. without the "true" prefix. */ struct mm_score { int correct; int misplaced; }; struct mm_line { struct mm_score score; int pieces[MAX_PIECES_COUNT]; }; const int colors[MAX_COLORS_COUNT] = { LCD_RGBPACK(252, 233, 79), LCD_RGBPACK(206, 92, 0), LCD_RGBPACK(143, 89, 2), LCD_RGBPACK( 78, 154, 6), /* LCD_RGBPACK( 32, 74, 135), */ LCD_RGBPACK( 52, 101, 164), /* LCD_RGBPACK(114, 159, 207), */ LCD_RGBPACK(117, 80, 123), /* LCD_RGBPACK(173, 127, 168), */ LCD_RGBPACK(164, 0, 0), LCD_RGBPACK(238, 238, 236), }; /* Flags */ static bool quit, leave, usb; static bool found, game_ended; /* Settings */ struct settings { int pieces; int colors; int guesses; bool labeling; bool framing; }; static struct settings settings = { 5, 7, 10, false, false, }; static struct settings old_settings; static int pieces_count; static int colors_count; static int guesses_count; /* Display */ #define ALUMINIUM LCD_RGBPACK(136, 138, 133) #define MARGIN 5 #define X_MARGIN (LCD_WIDTH / 20) #define Y_MARGIN (LCD_HEIGHT / 20) #define GAME_H (LCD_HEIGHT - (2 * Y_MARGIN)) #define LINE_W (LCD_WIDTH - (2 * X_MARGIN)) #define CONFIG_FILE_NAME "codebuster.cfg" static struct configdata config[] = { {TYPE_INT, 0, MAX_PIECES_COUNT, { .int_p = &settings.pieces }, "pieces", NULL}, {TYPE_INT, 0, MAX_COLORS_COUNT, { .int_p = &settings.colors }, "colors", NULL}, {TYPE_INT, 0, MAX_GUESSES_COUNT, { .int_p = &settings.guesses }, "guesses", NULL}, {TYPE_BOOL, 0, 1, { .bool_p = &settings.labeling }, "labeling", NULL}, {TYPE_BOOL, 0, 1, { .bool_p = &settings.framing }, "framing", NULL}, }; static int line_h; static int piece_w, tick_w; static int true_guess_w, true_score_w, guess_w, score_w; /* Guesses and solution */ struct mm_line solution, hidden; struct mm_line guesses[MAX_GUESSES_COUNT]; /* Alias for pluginlib_getaction */ static inline int get_button(void) { return pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 2); } /* Computes the margin to center an element */ static inline int get_margin(int width, int full_w) { return ((full_w - width) / 2); } static inline bool stop_game(void) { return (quit || leave || found); } static void fill_color_rect(int x, int y, int w, int h, int color) { rb->lcd_set_foreground(color); rb->lcd_fillrect(x, y, w, h); rb->lcd_set_foreground(LCD_WHITE); } static void overfill_rect(int x, int y, int w, int h) { rb->lcd_fillrect(x - 2, y - 2, w + 4, h + 4); } static void draw_piece(int x, int y, int w, int h, int color_id, bool emph) { int color = LCD_BLACK; if (color_id >= 0) color = colors[color_id]; else if (color_id == -2) /* Hidden piece */ color = ALUMINIUM; if (emph) overfill_rect(x, y, w, h); if (color_id == -1) /* Uninitialised color */ rb->lcd_drawrect(x, y, w, h); else fill_color_rect(x, y, w, h, color); if (!emph && settings.framing) rb->lcd_drawrect(x, y, w, h); if (settings.labeling && color_id >= 0) { char text[2]; rb->snprintf(text, 2, "%d", color_id); int fw, fh; rb->font_getstringsize(text, &fw, &fh, FONT_SYSFIXED); rb->lcd_putsxy(x + get_margin(fw, w), y + get_margin(fh, h), text); } } /* Compute the score for a given guess (expressed in ticks) */ static void validate_guess(struct mm_line* guess) { bool solution_match[MAX_PIECES_COUNT]; bool guess_match[MAX_PIECES_COUNT]; guess->score.misplaced = 0; guess->score.correct = 0; int guess_pos; /* Initialisation with 0s */ for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) solution_match[guess_pos] = guess_match[guess_pos] = false; /* 1st step : detect correctly positioned pieces */ for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) { if (solution.pieces[guess_pos] == guess->pieces[guess_pos]) { guess->score.correct += 1; guess_match[guess_pos] = solution_match[guess_pos] = true; } } /* Second step : detect mispositioned pieces */ for (guess_pos = 0; guess_pos < pieces_count; guess_pos++) { if (guess_match[guess_pos]) continue; int sol_pos; for (sol_pos = 0; sol_pos < pieces_count; sol_pos++) { if (guess_match[guess_pos]) break; if (solution_match[sol_pos]) continue; if (guess->pieces[guess_pos] == solution.pieces[sol_pos]) { guess->score.misplaced += 1; solution_match[sol_pos] = true; break; } } } } static void draw_guess(int line, struct mm_line* guess, int cur_guess, int cur_piece, bool show_score) { int cur_y = (Y_MARGIN + MARGIN) + 2 * line_h * line; int l_margin = X_MARGIN + (show_score ? 0 : get_margin(guess_w, LINE_W)); int piece; for (piece = 0; piece < pieces_count; piece++) { int cur_x = l_margin + 2 * piece_w * piece; draw_piece(cur_x, cur_y, piece_w, line_h, guess->pieces[piece], line == cur_guess && piece == cur_piece); } } static void draw_score(int line, struct mm_line* guess) { int cur_y = (Y_MARGIN + M/* Bitwise operations library */ /* (c) Reuben Thomas 2000-2008 */ /* bitlib is copyright Reuben Thomas 2000-2008, and is released under the MIT license, like Lua (see http://www.lua.org/copyright.html; it's basically the same as the BSD license). There is no warranty. */ #include "config.h" #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include <limits.h> /* FIXME: Assume lua_Integer is ptrdiff_t */ #define LUA_INTEGER_MAX INTPTR_MAX #define LUA_INTEGER_MIN INTPTR_MIN /* FIXME: Assume size_t is an unsigned lua_Integer */ typedef size_t lua_UInteger; #define LUA_UINTEGER_MAX UINT_MAX /* Bit type size and limits */ #define BIT_BITS (CHAR_BIT * sizeof(lua_Integer)) /* This code may give warnings if BITLIB_FLOAT_* are too big to fit in long, but that doesn't matter since in that case they won't be used. */ #define BIT_MAX (LUA_INTEGER_MAX) #define BIT_MIN (LUA_INTEGER_MIN) #define BIT_UMAX (LUA_UINTEGER_MAX) /* Define TOBIT to get a bit value */ #ifdef BUILTIN_CAST #define #define TOBIT(L, n, res) \ ((void)(res), luaL_checkinteger((L), (n))) #else #define TOBIT(L, n, res) \ ((lua_Integer)(((res) = luaL_checknumber(L, (n)) % BIT_UMAX), \ (res) > BIT_MAX ? ((res) -= BIT_UMAX, (res) -= 1) : \ ((res) < BIT_MIN ? ((res) += BIT_UMAX, (res) += 1) : (res)))) #endif #define BIT_TRUNCATE(i) \ ((i) & BIT_UMAX) /* Operations The macros MONADIC and VARIADIC only deal with bitwise operations. LOGICAL_SHIFT truncates its left-hand operand before shifting so that any extra bits at the most-significant end are not shifted into the result. ARITHMETIC_SHIFT does not truncate its left-hand operand, so that the sign bits are not removed and right shift work properly. */ #define MONADIC(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE(op TOBIT(L, 1, f))); \ return 1; \ } #define VARIADIC(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ int n = lua_gettop(L), i; \ lua_Integer w = TOBIT(L, 1, f); \ for (i = 2; i <= n; i++) \ w op TOBIT(L, i, f); \ lua_pushinteger(L, BIT_TRUNCATE(w)); \ return 1; \ } #define LOGICAL_SHIFT(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE(BIT_TRUNCATE((lua_UInteger)TOBIT(L, 1, f)) op \ (unsigned)luaL_checknumber(L, 2))); \ return 1; \ } #define ARITHMETIC_SHIFT(name, op) \ static int bit_ ## name(lua_State *L) { \ lua_Number f; \ lua_pushinteger(L, BIT_TRUNCATE((lua_Integer)TOBIT(L, 1, f) op \ (unsigned)luaL_checknumber(L, 2))); \ return 1; \ } MONADIC(bnot, ~) VARIADIC(band, &=) VARIADIC(bor, |=) VARIADIC(bxor, ^=) ARITHMETIC_SHIFT(lshift, <<) LOGICAL_SHIFT(rshift, >>) ARITHMETIC_SHIFT(arshift, >>) static const struct luaL_reg bitlib[] = { {"bnot", bit_bnot}, {"band", bit_band}, {"bor", bit_bor}, {"bxor", bit_bxor}, {"lshift", bit_lshift}, {"rshift", bit_rshift}, {"arshift", bit_arshift}, {NULL, NULL} }; LUALIB_API int luaopen_bit (lua_State *L) { luaL_register(L, "bit", bitlib); lua_pushnumber(L, BIT_BITS); lua_setfield(L, -2, "bits"); return 1; }