Fix mousewheel handler bug (using wrong variable in initial check)

Add sudoku game app (fun for the holidays! :)

Use "-Os -g" as the default optimization settings.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4652 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Michael R Sweet 2005-11-25 20:40:16 +00:00
parent fe286dfe7b
commit 9e8a88e66c
8 changed files with 610 additions and 3 deletions

View File

@ -760,7 +760,7 @@ if test -n "$GCC"; then
# They all seem to make either no difference or enlarge
# the code by a few hundred bytes.
#
# "-O2" seems to be the best compromise between speed and
# "-Os" seems to be the best compromise between speed and
# code size. "-O3" and higher seem to make no effective
# difference in the speed of the code, but does bloat the
# library 10+%.
@ -769,7 +769,7 @@ if test -n "$GCC"; then
if test "x$with_optim" != x; then
OPTIM="$with_optim $OPTIM"
else
OPTIM="-O2 $OPTIM"
OPTIM="-Os -g $OPTIM"
fi
fi

View File

@ -799,7 +799,7 @@ static pascal OSStatus carbonMousewheelHandler( EventHandlerCallRef nextHandler,
// to me why Apple changed the API on this even though the current API
// supports two wheels just fine. Matthias,
EventRef event;
if (GetEventKind(event)==11) {
if (GetEventKind(ev)==11) {
// if this is a "MightyMouse" event, we need to convert it into a regular
// MouseWheel event
GetEventParameter( ev, kEventParamEventRef, typeEventRef, NULL, sizeof( EventRef ), NULL, &event );

View File

@ -85,6 +85,7 @@ CPPFILES =\
scroll.cxx \
shape.cxx \
subwindow.cxx \
sudoku.cxx \
symbols.cxx \
tabs.cxx \
threads.cxx \
@ -142,6 +143,7 @@ ALL = \
resizebox$(EXEEXT) \
scroll$(EXEEXT) \
subwindow$(EXEEXT) \
sudoku$(EXEEXT) \
symbols$(EXEEXT) \
tabs$(EXEEXT) \
$(THREADS) \
@ -331,6 +333,11 @@ scroll$(EXEEXT): scroll.o
subwindow$(EXEEXT): subwindow.o
sudoku$(EXEEXT): sudoku.o
echo Linking $@...
$(CXX) -I.. $(CXXFLAGS) sudoku.o -o $@ $(LINKFLTK) $(LDLIBS)
$(CP) sudoku$(EXEEXT) sudoku.app/Contents/MacOS
symbols$(EXEEXT): symbols.o
tabs$(EXEEXT): tabs.o

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="0.9">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleExecutable</key>
<string>sudoku</string>
<key>CFBundleIdentifier</key>
<string>org.fltk.sudoku</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 2005 by Michael Sweet</string>
<key>CFAppleHelpAnchor</key>
<string>help</string>
<key>CFBundleName</key>
<string>sudoku</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>FLSU</string>
<key>CFBundleIconFile</key>
<string>sudoku.icns</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleGetInfoString</key>
<string>1.0, Copyright 2005 by Michael Sweet</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
FLSUFlsu

Binary file not shown.

555
test/sudoku.cxx Normal file
View File

@ -0,0 +1,555 @@
//
// "$Id$"
//
// Sudoku game using the Fast Light Tool Kit (FLTK).
//
// Copyright 2005 by Michael Sweet.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#include <FL/Fl.H>
#include <FL/Enumerations.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Group.H>
#include <FL/fl_ask.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Preferences.H>
#include <FL/Fl_Sys_Menu_Bar.H>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
//
// Default sizes...
//
#define GROUP_SIZE 160
#define CELL_SIZE 50
#define CELL_OFFSET 5
#ifdef __APPLE__
# define MENU_OFFSET 0
#else
# define MENU_OFFSET 25
#endif // __APPLE__
// Sudoku cell class...
class SudokuCell : public Fl_Widget {
bool readonly_;
int value_;
public:
SudokuCell(int X, int Y, int W, int H);
void draw();
int handle(int event);
void readonly(bool r) { readonly_ = r; redraw(); }
bool readonly() const { return readonly_; }
void value(int v) { value_ = v; redraw(); }
int value() const { return value_; }
};
// Create a cell widget
SudokuCell::SudokuCell(int X, int Y, int W, int H)
: Fl_Widget(X, Y, W, H, 0) {
}
// Draw cell
void
SudokuCell::draw() {
// Draw the cell box...
if (readonly()) fl_draw_box(FL_UP_BOX, x(), y(), w(), h(), color());
else fl_draw_box(FL_DOWN_BOX, x(), y(), w(), h(), color());
// Draw the cell background...
if (Fl::focus() == this) {
fl_color(FL_SELECTION_COLOR);
fl_rectf(x() + 4, y() + 4, w() - 8, h() - 8);
fl_color(fl_contrast(labelcolor(), FL_SELECTION_COLOR));
} else fl_color(labelcolor());
// Draw the cell value...
if (value_) {
char s[2];
s[0] = value_ + '0';
s[1] = '\0';
fl_font(FL_HELVETICA_BOLD, h() - 10);
fl_draw(s, x(), y(), w(), h(), FL_ALIGN_CENTER);
}
}
// Handle events in cell
int
SudokuCell::handle(int event) {
switch (event) {
case FL_FOCUS :
if (!readonly()) {
Fl::focus(this);
redraw();
return 1;
}
break;
case FL_UNFOCUS :
redraw();
return 1;
break;
case FL_PUSH :
if (!readonly() && Fl::event_inside(this)) {
Fl::focus(this);
redraw();
return 1;
}
break;
case FL_KEYDOWN :
int key = Fl::event_key() - '0';
if (key >= 1 && key <= 9) {
value(key);
do_callback();
return 1;
}
break;
}
return Fl_Widget::handle(event);
}
// Sudoku window class...
class Sudoku : public Fl_Window {
Fl_Sys_Menu_Bar *menubar_;
Fl_Group *grid_;
char grid_values_[9][9];
SudokuCell *grid_cells_[9][9];
Fl_Group *grid_groups_[3][3];
int difficulty_;
static void check_cb(Fl_Widget *widget, void *);
static void close_cb(Fl_Widget *widget, void *);
static void diff_cb(Fl_Widget *widget, void *d);
static void new_cb(Fl_Widget *widget, void *);
static void reset_cb(Fl_Widget *widget, void *);
static void solve_cb(Fl_Widget *widget, void *);
static Fl_Preferences prefs_;
public:
Sudoku();
void check_game();
void load_game();
void new_game();
void resize(int X, int Y, int W, int H);
void save_game();
void solve_game();
};
// Preferences/saved state for game...
Fl_Preferences Sudoku::prefs_(Fl_Preferences::USER, "fltk.org", "sudoku");
// Create a Sudoku game window...
Sudoku::Sudoku()
: Fl_Window(GROUP_SIZE * 3, GROUP_SIZE * 3 + MENU_OFFSET, "Sudoku")
{
int i, j, k, m;
Fl_Group *g;
SudokuCell *cell;
static Fl_Menu_Item items[] = {
{ "&Game", 0, 0, 0, FL_SUBMENU },
{ "&New Game", FL_COMMAND | 'n', new_cb, 0, FL_MENU_DIVIDER },
{ "&Check Game", FL_COMMAND | 'c', check_cb, 0, 0 },
{ "&Solve Game", FL_COMMAND | 's', solve_cb, 0, FL_MENU_DIVIDER },
{ "&Quit", FL_COMMAND | 'q', close_cb, 0, 0 },
{ 0 },
{ "&Difficulty", 0, 0, 0, FL_SUBMENU },
{ "&Easy", FL_COMMAND | '1', diff_cb, (void *)"40", FL_MENU_RADIO },
{ "&Medium", FL_COMMAND | '2', diff_cb, (void *)"28", FL_MENU_RADIO },
{ "&Hard", FL_COMMAND | '3', diff_cb, (void *)"16", FL_MENU_RADIO },
{ 0 },
{ 0 }
};
// Menubar...
prefs_.get("difficulty", difficulty_, 40);
if (difficulty_ == 16) items[9].flags |= FL_MENU_VALUE;
else if (difficulty_ == 28) items[8].flags |= FL_MENU_VALUE;
else items[7].flags |= FL_MENU_VALUE;
menubar_ = new Fl_Sys_Menu_Bar(0, 0, 3 * GROUP_SIZE, 25);
menubar_->menu(items);
// Create the grids...
grid_ = new Fl_Group(0, MENU_OFFSET, 3 * GROUP_SIZE, 3 * GROUP_SIZE);
for (i = 0; i < 3; i ++)
for (j = 0; j < 3; j ++) {
g = new Fl_Group(i * GROUP_SIZE, j * GROUP_SIZE + MENU_OFFSET,
GROUP_SIZE, GROUP_SIZE);
g->box(FL_BORDER_BOX);
g->color(FL_DARK3);
grid_groups_[i][j] = g;
for (k = 0; k < 3; k ++)
for (m = 0; m < 3; m ++) {
cell = new SudokuCell(i * GROUP_SIZE + CELL_OFFSET + k * CELL_SIZE,
j * GROUP_SIZE + CELL_OFFSET + m * CELL_SIZE +
MENU_OFFSET,
CELL_SIZE, CELL_SIZE);
cell->callback(reset_cb);
grid_cells_[i * 3 + k][j * 3 + m] = cell;
}
g->end();
}
callback(close_cb);
resizable(grid_);
// Restore the previous window dimensions...
int X, Y, W, H;
if (prefs_.get("x", X, -1)) {
prefs_.get("y", Y, -1);
prefs_.get("width", W, 3 * GROUP_SIZE);
prefs_.get("height", H, 3 * GROUP_SIZE + MENU_OFFSET);
resize(X, X, W, H);
}
// Load the previous game...
load_game();
}
// Check for a solution to the game...
void
Sudoku::check_cb(Fl_Widget *widget, void *) {
((Sudoku *)(widget->window()))->check_game();
}
// Check if the user has correctly solved the game...
void
Sudoku::check_game() {
bool empty = false;
bool correct = true;
// Check the game for right/wrong answers...
for (int i = 0; i < 9; i ++)
for (int j = 0; j < 9; j ++) {
SudokuCell *cell = grid_cells_[i][j];
int val = cell->value();
if (!val) empty = true;
if (val && grid_values_[i][j] != val) {
cell->color(FL_YELLOW);
cell->redraw();
correct = false;
}
}
if (!empty && correct) {
// Success!
solve_game();
fl_message("Congratulations, you solved the game!");
}
}
// Close the window, saving the game first...
void
Sudoku::close_cb(Fl_Widget *widget, void *) {
Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget);
s->save_game();
s->hide();
}
// Set the level of difficulty...
void
Sudoku::diff_cb(Fl_Widget *widget, void *d) {
Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget);
s->difficulty_ = atoi((char *)d);
s->new_game();
}
// Load the game from saved preferences...
void
Sudoku::load_game() {
// Load the current values and state of each grid...
memset(grid_values_, 0, sizeof(grid_values_));
for (int i = 0; i < 9; i ++)
for (int j = 0; j < 9; j ++) {
char name[255];
int val;
SudokuCell *cell = grid_cells_[i][j];
sprintf(name, "value%d.%d", i, j);
if (!prefs_.get(name, val, 0)) {
i = 9;
grid_values_[0][0] = 0;
break;
}
grid_values_[i][j] = val;
sprintf(name, "state%d.%d", i, j);
prefs_.get(name, val, 0);
cell->value(val);
sprintf(name, "readonly%d.%d", i, j);
prefs_.get(name, val, 0);
cell->readonly(val);
if (val) cell->color(FL_GRAY);
else cell->color(FL_LIGHT3);
}
// If we didn't load any values, then create a new game...
if (!grid_values_[0][0]) new_game();
}
// Create a new game...
void
Sudoku::new_cb(Fl_Widget *widget, void *) {
((Sudoku *)(widget->window()))->new_game();
}
// Create a new game...
void
Sudoku::new_game() {
int i, j, k, m, t, count;
// Generate a new (valid) Sudoku grid...
srand(time(NULL));
memset(grid_values_, 0, sizeof(grid_values_));
for (i = 0; i < 9; i += 3) {
for (j = 0; j < 9; j += 3) {
for (t = 1; t <= 9; t ++) {
for (count = 0; count < 20; count ++) {
k = i + (rand() % 3);
m = j + (rand() % 3);
if (!grid_values_[k][m]) {
int kk;
for (kk = 0; kk < k; kk ++)
if (grid_values_[kk][m] == t) break;
if (kk < k) continue;
int mm;
for (mm = 0; mm < m; mm ++)
if (grid_values_[k][mm] == t) break;
if (mm < m) continue;
grid_values_[k][m] = t;
break;
}
}
if (count == 20) {
// Unable to find a valid puzzle so far, so start over...
j = 9;
i = -3;
memset(grid_values_, 0, sizeof(grid_values_));
}
}
}
}
// Start by making all cells editable
SudokuCell *cell;
for (i = 0; i < 9; i ++)
for (j = 0; j < 9; j ++) {
cell = grid_cells_[i][j];
cell->value(0);
cell->readonly(0);
cell->color(FL_LIGHT3);
}
// Show N cells, starting with potential confusing ones...
count = difficulty_;
for (i = 0; i < 8; i ++)
for (j = 0; j < 8; j ++) {
cell = grid_cells_[i][j];
for (k = i + 1; k < 9; k ++) {
if (grid_values_[i][j] == grid_values_[k][j + 1] &&
grid_values_[i][j + 1] == grid_values_[k][j]) {
cell->value(grid_values_[i][j]);
cell->readonly(1);
cell->color(FL_GRAY);
count --;
}
}
for (m = j + 1; m < 9; m ++) {
if (!cell->readonly() &&
grid_values_[i][j] == grid_values_[i + 1][m] &&
grid_values_[i + 1][m] == grid_values_[i][m]) {
cell->value(grid_values_[i][j]);
cell->readonly(1);
cell->color(FL_GRAY);
count --;
}
}
}
// Now show random fields...
while (count > 0) {
i = rand() % 9;
j = rand() % 9;
cell = grid_cells_[i][j];
if (!cell->readonly()) {
cell->value(grid_values_[i][j]);
cell->readonly(1);
cell->color(FL_GRAY);
count --;
}
}
}
// Reset widget color to gray...
void
Sudoku::reset_cb(Fl_Widget *widget, void *) {
widget->color(FL_LIGHT3);
widget->redraw();
}
// Resize the window...
void
Sudoku::resize(int X, int Y, int W, int H) {
// Force resizes to keep the proper aspect ratio...
int M = H - MENU_OFFSET;
if (M > W) M = W;
if (W != M || H != (M + MENU_OFFSET)) {
W = M;
H = M + MENU_OFFSET;
}
// Resize the window...
Fl_Window::resize(X, Y, W, H);
// Save the new window geometry...
prefs_.set("x", X);
prefs_.set("y", Y);
prefs_.set("width", W);
prefs_.set("height", H);
}
// Save the current game state...
void
Sudoku::save_game() {
// Save the current values and state of each grid...
for (int i = 0; i < 9; i ++)
for (int j = 0; j < 9; j ++) {
char name[255];
SudokuCell *cell = grid_cells_[i][j];
sprintf(name, "value%d.%d", i, j);
prefs_.set(name, grid_values_[i][j]);
sprintf(name, "state%d.%d", i, j);
prefs_.set(name, cell->value());
sprintf(name, "readonly%d.%d", i, j);
prefs_.set(name, cell->readonly());
}
}
// Solve the puzzle...
void
Sudoku::solve_cb(Fl_Widget *widget, void *) {
((Sudoku *)(widget->window()))->solve_game();
}
// Solve the puzzle...
void
Sudoku::solve_game() {
int i, j;
for (i = 0; i < 9; i ++)
for (j = 0; j < 9; j ++) {
SudokuCell *cell = grid_cells_[i][j];
cell->value(grid_values_[i][j]);
cell->readonly();
cell->color(FL_GRAY);
}
}
// Main entry for game...
int
main(int argc, char *argv[]) {
Sudoku s;
s.show(argc, argv);
return (Fl::run());
}
//
// End of "$Id$".
//

BIN
test/sudoku.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB