summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/sudoku.cxx591
-rw-r--r--test/sudoku.h70
-rw-r--r--test/sudoku_cell.cxx174
-rw-r--r--test/sudoku_cell.h49
-rw-r--r--test/sudoku_generator.cxx61
-rw-r--r--test/sudoku_generator.h60
-rw-r--r--test/sudoku_sound.cxx305
-rw-r--r--test/sudoku_sound.h97
9 files changed, 776 insertions, 633 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 730da2444..d1cda15cc 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -133,7 +133,7 @@ CREATE_EXAMPLE (resize-example5c "resize-example5c.cxx;resize-arrows.cxx" fltk)
CREATE_EXAMPLE (rotated_text rotated_text.cxx fltk)
CREATE_EXAMPLE (scroll scroll.cxx fltk)
CREATE_EXAMPLE (subwindow subwindow.cxx fltk)
-CREATE_EXAMPLE (sudoku "sudoku.cxx;sudoku_generator.cxx;sudoku.plist;sudoku.icns;sudoku.rc" "fltk_images;fltk;${AUDIOLIBS}")
+CREATE_EXAMPLE (sudoku "sudoku.cxx;sudoku_cell.cxx;sudoku_sound.cxx;sudoku_generator.cxx;sudoku.plist;sudoku.icns;sudoku.rc" "fltk_images;fltk;${AUDIOLIBS}")
CREATE_EXAMPLE (symbols symbols.cxx fltk)
CREATE_EXAMPLE (tabs tabs.fl fltk)
CREATE_EXAMPLE (table table.cxx fltk)
diff --git a/test/sudoku.cxx b/test/sudoku.cxx
index 43fe37124..822508b7f 100644
--- a/test/sudoku.cxx
+++ b/test/sudoku.cxx
@@ -15,6 +15,11 @@
// https://www.fltk.org/bugs.php
//
+#include "sudoku.h"
+#include "sudoku_cell.h"
+#include "sudoku_sound.h"
+#include "sudoku_generator.h"
+
#include <FL/Fl.H>
#include <FL/Enumerations.H>
#include <FL/Fl_Double_Window.H>
@@ -36,25 +41,6 @@
#include "pixmaps/sudoku.xbm"
-// Audio headers...
-#include <config.h>
-
-#ifndef _WIN32
-# include <unistd.h>
-#endif // !_WIN32
-
-#ifdef HAVE_ALSA_ASOUNDLIB_H
-# define ALSA_PCM_NEW_HW_PARAMS_API
-# include <alsa/asoundlib.h>
-#endif // HAVE_ALSA_ASOUNDLIB_H
-#ifdef __APPLE__
-# include <CoreAudio/AudioHardware.h>
-#endif // __APPLE__
-#ifdef _WIN32
-# include <mmsystem.h>
-#endif // _WIN32
-
-
//
// Default sizes...
//
@@ -68,570 +54,6 @@
# define MENU_OFFSET 25
#endif // __APPLE__
-// Sound class for Sudoku...
-//
-// There are MANY ways to implement sound in a FLTK application.
-// The approach we are using here is to conditionally compile OS-
-// specific code into the application - CoreAudio for MacOS X, the
-// standard Win32 API stuff for Windows, ALSA or X11 for Linux, and
-// X11 for all others. We have to support ALSA on Linux because the
-// current Xorg releases no longer support XBell() or the PC speaker.
-//
-// There are several good cross-platform audio libraries we could also
-// use, such as OpenAL, PortAudio, and SDL, however they were not chosen
-// for this application because of our limited use of sound.
-//
-// Many thanks to Ian MacArthur who provided sample code that led to
-// the CoreAudio implementation you see here!
-class SudokuSound {
- // Private, OS-specific data...
-#ifdef __APPLE__
- AudioDeviceID device;
-#ifndef MAC_OS_X_VERSION_10_5
-#define MAC_OS_X_VERSION_10_5 1050
-#endif
-# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- AudioDeviceIOProcID audio_proc_id;
-# endif
- AudioStreamBasicDescription format;
- short *data;
- int remaining;
-
- static OSStatus audio_cb(AudioDeviceID device,
- const AudioTimeStamp *current_time,
- const AudioBufferList *data_in,
- const AudioTimeStamp *time_in,
- AudioBufferList *data_out,
- const AudioTimeStamp *time_out,
- void *client_data);
-#elif defined(_WIN32)
- HWAVEOUT device;
- HGLOBAL header_handle;
- LPWAVEHDR header_ptr;
- HGLOBAL data_handle;
- LPSTR data_ptr;
-
-#else
-# ifdef HAVE_ALSA_ASOUNDLIB_H
- snd_pcm_t *handle;
-# endif // HAVE_ALSA_ASOUNDLIB_H
-#endif // __APPLE__
-
- // Common data...
- static int frequencies[9];
- static short *sample_data[9];
- static int sample_size;
-
- public:
-
- SudokuSound();
- ~SudokuSound();
-
- void play(char note);
-};
-
-
-// Sudoku cell class...
-class SudokuCell : public Fl_Widget {
- bool readonly_;
- int value_;
- int marks_;
-
- public:
-
- SudokuCell(int X, int Y, int W, int H);
- void draw() FL_OVERRIDE;
- int handle(int event) FL_OVERRIDE;
- void readonly(bool r) { readonly_ = r; redraw(); }
- bool readonly() const { return readonly_; }
- void mark(int n, bool set);
- void toggle_mark(int n);
- bool mark(int n);
- void clear_marks();
- void value(int v) {
- value_ = v;
- clear_marks();
- redraw();
- }
- int value() const { return value_; }
-};
-
-
-// Sudoku window class...
-class Sudoku : public Fl_Double_Window {
- Fl_Sys_Menu_Bar *menubar_;
- Fl_Group *grid_;
- time_t seed_;
- char grid_values_[9][9];
- SudokuCell *grid_cells_[9][9];
- Fl_Group *grid_groups_[3][3];
- int difficulty_;
- SudokuSound *sound_;
-
- 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 update_helpers_cb(Fl_Widget *, void *);
- static void help_cb(Fl_Widget *, void *);
- static void mute_cb(Fl_Widget *widget, void *);
- static void new_cb(Fl_Widget *widget, void *);
- static void reset_cb(Fl_Widget *widget, void *);
- static void restart_cb(Fl_Widget *widget, void *);
- void set_title();
- static void solve_cb(Fl_Widget *widget, void *);
-
- static Fl_Help_Dialog *help_dialog_;
- static Fl_Preferences prefs_;
- public:
-
- Sudoku();
- ~Sudoku();
-
- void check_game(bool highlight = true);
- void load_game();
- void new_game(time_t seed);
- int next_value(SudokuCell *c);
- void resize(int X, int Y, int W, int H) FL_OVERRIDE;
- void save_game();
- void solve_game();
- void update_helpers();
-};
-
-
-// Sound class globals...
-int SudokuSound::frequencies[9] = {
- 880, // A(5)
- 988, // B(5)
- 1046, // C(5)
- 1174, // D(5)
- 1318, // E(5)
- 1396, // F(5)
- 1568, // G(5)
- 1760, // H (A6)
- 1976 // I (B6)
-};
-short *SudokuSound::sample_data[9] = { 0 };
-int SudokuSound::sample_size = 0;
-
-
-// Initialize the SudokuSound class
-SudokuSound::SudokuSound() {
- sample_size = 0;
-
-#ifdef __APPLE__
- remaining = 0;
-
- UInt32 size = sizeof(device);
-
- if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
- &size, (void *)&device) != noErr) return;
-
- size = sizeof(format);
- if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat,
- &size, &format) != noErr) return;
-
- // Set up a format we like...
- format.mSampleRate = 44100.0; // 44.1kHz
- format.mChannelsPerFrame = 2; // stereo
-
- if (AudioDeviceSetProperty(device, NULL, 0, false,
- kAudioDevicePropertyStreamFormat,
- sizeof(format), &format) != noErr) return;
-
- // Check we got linear pcm - what to do if we did not ???
- if (format.mFormatID != kAudioFormatLinearPCM) return;
-
- // Attach the callback and start the device
-# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- if (AudioDeviceCreateIOProcID(device, audio_cb, (void *)this, &audio_proc_id) != noErr) return;
- AudioDeviceStart(device, audio_proc_id);
-# else
- if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return;
- AudioDeviceStart(device, audio_cb);
-# endif
-
- sample_size = (int)format.mSampleRate / 20;
-
-#elif defined(_WIN32)
- WAVEFORMATEX format;
-
- memset(&format, 0, sizeof(format));
- format.cbSize = sizeof(format);
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = 2;
- format.nSamplesPerSec = 44100;
- format.nAvgBytesPerSec = 44100 * 4;
- format.nBlockAlign = 4;
- format.wBitsPerSample = 16;
-
- data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, format.nSamplesPerSec / 5);
- if (!data_handle) return;
-
- data_ptr = (LPSTR)GlobalLock(data_handle);
-
- header_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
- if (!header_handle) return;
-
- header_ptr = (WAVEHDR *)GlobalLock(header_handle);
-
- header_ptr->lpData = data_ptr;
- header_ptr->dwBufferLength = format.nSamplesPerSec / 5;
- header_ptr->dwFlags = 0;
- header_ptr->dwLoops = 0;
-
- if (waveOutOpen(&device, WAVE_MAPPER, &format, 0, 0, WAVE_ALLOWSYNC)
- != MMSYSERR_NOERROR) return;
-
- waveOutPrepareHeader(device, header_ptr, sizeof(WAVEHDR));
-
- sample_size = 44100 / 20;
-
-#else
-# ifdef HAVE_ALSA_ASOUNDLIB_H
- handle = NULL;
-
- if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) {
- // Initialize PCM sound stuff...
- snd_pcm_hw_params_t *params;
-
- snd_pcm_hw_params_alloca(&params);
- snd_pcm_hw_params_any(handle, params);
- snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
- snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
- snd_pcm_hw_params_set_channels(handle, params, 2);
- unsigned rate = 44100;
- int dir;
- snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
- snd_pcm_uframes_t period = (int)rate / 4;
- snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir);
-
- sample_size = rate / 20;
-
- if (snd_pcm_hw_params(handle, params) < 0) {
- sample_size = 0;
- snd_pcm_close(handle);
- handle = NULL;
- }
- }
-# endif // HAVE_ALSA_ASOUNDLIB_H
-#endif // __APPLE__
-
- if (sample_size) {
- // Make each of the notes using a combination of sine and sawtooth waves
- int attack = sample_size / 10;
- int decay = 4 * sample_size / 5;
-
- for (int i = 0; i < 9; i ++) {
- sample_data[i] = new short[2 * sample_size];
-
- short *sample_ptr = sample_data[i];
-
- for (int j = 0; j < sample_size; j ++, sample_ptr += 2) {
- double theta = 0.05 * frequencies[i] * j / sample_size;
- double val = 0.5 * sin(2.0 * M_PI * theta) + theta - (int)theta - 0.5;
-
- if (j < attack) {
- *sample_ptr = (int)(32767 * val * j / attack);
- } else if (j > decay) {
- *sample_ptr = (int)(32767 * val * (sample_size - j + decay) /
- sample_size);
- } else *sample_ptr = (int)(32767 * val);
-
- sample_ptr[1] = *sample_ptr;
- }
- }
- }
-}
-
-
-// Cleanup the SudokuSound class
-SudokuSound::~SudokuSound() {
-#ifdef __APPLE__
- if (sample_size) {
-# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- AudioDeviceStop(device, audio_proc_id);
- AudioDeviceDestroyIOProcID(device, audio_proc_id);
-# else
- AudioDeviceStop(device, audio_cb);
- AudioDeviceRemoveIOProc(device, audio_cb);
-# endif
- }
-
-#elif defined(_WIN32)
- if (sample_size) {
- waveOutClose(device);
-
- GlobalUnlock(header_handle);
- GlobalFree(header_handle);
-
- GlobalUnlock(data_handle);
- GlobalFree(data_handle);
- }
-
-#else
-# ifdef HAVE_ALSA_ASOUNDLIB_H
- if (handle) {
- snd_pcm_drain(handle);
- snd_pcm_close(handle);
- }
-# endif // HAVE_ALSA_ASOUNDLIB_H
-#endif // __APPLE__
-
- if (sample_size) {
- for (int i = 0; i < 9; i ++) {
- delete[] sample_data[i];
- }
- }
-}
-
-
-#ifdef __APPLE__
-// Callback function for writing audio data...
-OSStatus
-SudokuSound::audio_cb(AudioDeviceID device,
- const AudioTimeStamp *current_time,
- const AudioBufferList *data_in,
- const AudioTimeStamp *time_in,
- AudioBufferList *data_out,
- const AudioTimeStamp *time_out,
- void *client_data) {
- SudokuSound *ss = (SudokuSound *)client_data;
- int count;
- float *buffer;
-
- if (!ss->remaining) return noErr;
-
- for (count = data_out->mBuffers[0].mDataByteSize / sizeof(float),
- buffer = (float*) data_out->mBuffers[0].mData;
- ss->remaining > 0 && count > 0;
- count --, ss->data ++, ss->remaining --) {
- *buffer++ = *(ss->data) / 32767.0;
- }
-
- while (count > 0) {
- *buffer++ = 0.0;
- count --;
- }
-
- return noErr;
-}
-#endif // __APPLE__
-
-#define NOTE_DURATION 50
-
-// Play a note for <NOTE_DURATION> ms...
-void SudokuSound::play(char note) {
- Fl::check();
-
-#ifdef __APPLE__
- // Point to the next note...
- data = sample_data[note - 'A'];
- remaining = sample_size * 2;
-
- // Wait for the sound to complete...
- usleep(NOTE_DURATION*1000);
-
-#elif defined(_WIN32)
- if (sample_size) {
- memcpy(data_ptr, sample_data[note - 'A'], sample_size * 4);
-
- waveOutWrite(device, header_ptr, sizeof(WAVEHDR));
-
- Sleep(NOTE_DURATION);
- } else Beep(frequencies[note - 'A'], NOTE_DURATION);
-
-#elif defined(FLTK_USE_X11)
-# ifdef HAVE_ALSA_ASOUNDLIB_H
- if (handle) {
- // Use ALSA to play the sound...
- if (snd_pcm_writei(handle, sample_data[note - 'A'], sample_size) < 0) {
- snd_pcm_prepare(handle);
- snd_pcm_writei(handle, sample_data[note - 'A'], sample_size);
- }
- usleep(NOTE_DURATION*1000);
- return;
- }
-# endif // HAVE_ALSA_ASOUNDLIB_H
-
- // Just use standard X11 stuff...
- XKeyboardState state;
- XKeyboardControl control;
-
- // Get original pitch and duration...
- XGetKeyboardControl(fl_display, &state);
-
- // Sound a tone for the given note...
- control.bell_percent = 100;
- control.bell_pitch = frequencies[note - 'A'];
- control.bell_duration = NOTE_DURATION;
-
- XChangeKeyboardControl(fl_display,
- KBBellPercent | KBBellPitch | KBBellDuration,
- &control);
- XBell(fl_display, 100);
- XFlush(fl_display);
-
- // Restore original pitch and duration...
- control.bell_percent = state.bell_percent;
- control.bell_pitch = state.bell_pitch;
- control.bell_duration = state.bell_duration;
-
- XChangeKeyboardControl(fl_display,
- KBBellPercent | KBBellPitch | KBBellDuration,
- &control);
-#endif // __APPLE__
-}
-
-
-// Create a cell widget
-SudokuCell::SudokuCell(int X, int Y, int W, int H)
-: Fl_Widget(X, Y, W, H, 0),
- marks_(0)
-{
- value(0);
-}
-
-
-// Draw cell
-void
-SudokuCell::draw() {
- static Fl_Align align[10] = {
- 0,
- FL_ALIGN_TOP_LEFT,
- FL_ALIGN_TOP,
- FL_ALIGN_TOP_RIGHT,
- FL_ALIGN_LEFT,
- 0,
- FL_ALIGN_RIGHT,
- FL_ALIGN_BOTTOM_LEFT,
- FL_ALIGN_BOTTOM,
- FL_ALIGN_BOTTOM_RIGHT,
- };
-
-
- // 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 c = fl_color_average(FL_SELECTION_COLOR, color(), 0.5f);
- fl_color(c);
- fl_rectf(x() + 4, y() + 4, w() - 8, h() - 8);
- fl_color(fl_contrast(labelcolor(), c));
- } else fl_color(labelcolor());
-
- // Draw the cell value...
- char s[2];
-
- s[1] = '\0';
-
- if (value_) {
- s[0] = value_ + '0';
-
- fl_font(FL_HELVETICA_BOLD, h() - 10);
- fl_draw(s, x(), y(), w(), h(), FL_ALIGN_CENTER);
- }
-
- fl_font(FL_HELVETICA_BOLD, h()*2/9);
-
- for (int i = 1; i <= 9; i ++) {
- if (mark(i)) {
- s[0] = i + '0';
- fl_draw(s, x() + 5, y() + 5, w() - 10, h() - 10, align[i]);
- }
- }
-}
-
-
-// Handle events in cell
-int
-SudokuCell::handle(int event) {
- switch (event) {
- case FL_FOCUS :
- Fl::focus(this);
- redraw();
- return 1;
-
- case FL_UNFOCUS :
- redraw();
- return 1;
-
- case FL_PUSH :
- if (!readonly() && Fl::event_inside(this)) {
- if (Fl::event_clicks()) {
- // 2+ clicks increments/sets value
- if (value()) {
- if (value() < 9) value(value() + 1);
- else value(1);
- } else value(((Sudoku *)window())->next_value(this));
- }
-
- Fl::focus(this);
- redraw();
- return 1;
- }
- break;
-
- case FL_KEYDOWN :
- if (Fl::event_state() & FL_CTRL) break;
- int key = Fl::event_key() - '0';
- if (key < 0 || key > 9) key = Fl::event_key() - FL_KP - '0';
- if (key > 0 && key <= 9) {
- if (readonly()) {
- fl_beep(FL_BEEP_ERROR);
- return 1;
- }
-
- if (Fl::event_state() & (FL_SHIFT | FL_CAPS_LOCK)) {
- toggle_mark(key);
- value_ = 0;
- redraw();
- } else {
- value(key);
- do_callback();
- }
- return 1;
- } else if (key == 0 || Fl::event_key() == FL_BackSpace ||
- Fl::event_key() == FL_Delete) {
- if (readonly()) {
- fl_beep(FL_BEEP_ERROR);
- return 1;
- }
-
- value(0);
- do_callback();
- return 1;
- }
- break;
- }
-
- return Fl_Widget::handle(event);
-}
-
-void SudokuCell::mark(int n, bool set) {
- if (n<1 || n>9) return;
- if (set) {
- marks_ |= (1<<n);
- } else {
- marks_ &= ~(1<<n);
- }
-}
-
-void SudokuCell::toggle_mark(int n) {
- if (n<1 || n>9) return;
- marks_ ^= (1<<n);
-}
-
-bool SudokuCell::mark(int n) {
- if (n<1 || n>9) return 0;
- return (marks_>>n) & 1;
-}
-
-void SudokuCell::clear_marks() {
- marks_ = 0;
-}
-
// Sudoku class globals...
Fl_Help_Dialog *Sudoku::help_dialog_ = (Fl_Help_Dialog *)0;
@@ -1081,9 +503,6 @@ Sudoku::new_cb(Fl_Widget *widget, void *) {
s->new_game(time(NULL));
}
-
-extern int generate_sudoku(int grid_data[81], int minHints, int maxHints);
-
// Create a new game...
void
Sudoku::new_game(time_t seed) {
diff --git a/test/sudoku.h b/test/sudoku.h
new file mode 100644
index 000000000..05b8f1f63
--- /dev/null
+++ b/test/sudoku.h
@@ -0,0 +1,70 @@
+//
+// Sudoku game using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005-2018 by Michael Sweet.
+// Copyright 2019-2021 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#ifndef _SUDOKU_H_
+#define _SUDOKU_H_
+
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Preferences.H>
+
+class SudokuCell;
+class SudokuSound;
+class Fl_Sys_Menu_Bar;
+class Fl_Help_Dialog;
+
+// Sudoku window class...
+class Sudoku : public Fl_Double_Window {
+ Fl_Sys_Menu_Bar *menubar_;
+ Fl_Group *grid_;
+ time_t seed_;
+ char grid_values_[9][9];
+ SudokuCell *grid_cells_[9][9];
+ Fl_Group *grid_groups_[3][3];
+ int difficulty_;
+ SudokuSound *sound_;
+
+ 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 update_helpers_cb(Fl_Widget *, void *);
+ static void help_cb(Fl_Widget *, void *);
+ static void mute_cb(Fl_Widget *widget, void *);
+ static void new_cb(Fl_Widget *widget, void *);
+ static void reset_cb(Fl_Widget *widget, void *);
+ static void restart_cb(Fl_Widget *widget, void *);
+ void set_title();
+ static void solve_cb(Fl_Widget *widget, void *);
+
+ static Fl_Help_Dialog *help_dialog_;
+ static Fl_Preferences prefs_;
+ public:
+
+ Sudoku();
+ ~Sudoku();
+
+ void check_game(bool highlight = true);
+ void load_game();
+ void new_game(time_t seed);
+ int next_value(SudokuCell *c);
+ void resize(int X, int Y, int W, int H) FL_OVERRIDE;
+ void save_game();
+ void solve_game();
+ void update_helpers();
+};
+
+
+#endif _SUDOKU_H_
diff --git a/test/sudoku_cell.cxx b/test/sudoku_cell.cxx
new file mode 100644
index 000000000..671bde4bd
--- /dev/null
+++ b/test/sudoku_cell.cxx
@@ -0,0 +1,174 @@
+//
+// Sudoku game using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005-2018 by Michael Sweet.
+// Copyright 2019-2021 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#include "sudoku_cell.h"
+#include "sudoku.h"
+
+#include <FL/fl_draw.H>
+#include <FL/fl_ask.H>
+
+// Create a cell widget
+SudokuCell::SudokuCell(int X, int Y, int W, int H)
+: Fl_Widget(X, Y, W, H, 0),
+ marks_(0)
+{
+ value(0);
+}
+
+
+// Draw cell
+void
+SudokuCell::draw() {
+ static Fl_Align align[10] = {
+ 0,
+ FL_ALIGN_TOP_LEFT,
+ FL_ALIGN_TOP,
+ FL_ALIGN_TOP_RIGHT,
+ FL_ALIGN_LEFT,
+ 0,
+ FL_ALIGN_RIGHT,
+ FL_ALIGN_BOTTOM_LEFT,
+ FL_ALIGN_BOTTOM,
+ FL_ALIGN_BOTTOM_RIGHT,
+ };
+
+
+ // 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 c = fl_color_average(FL_SELECTION_COLOR, color(), 0.5f);
+ fl_color(c);
+ fl_rectf(x() + 4, y() + 4, w() - 8, h() - 8);
+ fl_color(fl_contrast(labelcolor(), c));
+ } else fl_color(labelcolor());
+
+ // Draw the cell value...
+ char s[2];
+
+ s[1] = '\0';
+
+ if (value_) {
+ s[0] = value_ + '0';
+
+ fl_font(FL_HELVETICA_BOLD, h() - 10);
+ fl_draw(s, x(), y(), w(), h(), FL_ALIGN_CENTER);
+ }
+
+ fl_font(FL_HELVETICA_BOLD, h()*2/9);
+
+ for (int i = 1; i <= 9; i ++) {
+ if (mark(i)) {
+ s[0] = i + '0';
+ fl_draw(s, x() + 5, y() + 5, w() - 10, h() - 10, align[i]);
+ }
+ }
+}
+
+
+// Handle events in cell
+int
+SudokuCell::handle(int event) {
+ switch (event) {
+ case FL_FOCUS :
+ Fl::focus(this);
+ redraw();
+ return 1;
+
+ case FL_UNFOCUS :
+ redraw();
+ return 1;
+
+ case FL_PUSH :
+ if (!readonly() && Fl::event_inside(this)) {
+ if (Fl::event_clicks()) {
+ // 2+ clicks increments/sets value
+ if (value()) {
+ if (value() < 9) value(value() + 1);
+ else value(1);
+ } else value(((Sudoku *)window())->next_value(this));
+ }
+
+ Fl::focus(this);
+ redraw();
+ return 1;
+ }
+ break;
+
+ case FL_KEYDOWN :
+ if (Fl::event_state() & FL_CTRL) break;
+ int key = Fl::event_key() - '0';
+ if (key < 0 || key > 9) key = Fl::event_key() - FL_KP - '0';
+ if (key > 0 && key <= 9) {
+ if (readonly()) {
+ fl_beep(FL_BEEP_ERROR);
+ return 1;
+ }
+
+ if (Fl::event_state() & (FL_SHIFT | FL_CAPS_LOCK)) {
+ toggle_mark(key);
+ value_ = 0;
+ redraw();
+ } else {
+ value(key);
+ do_callback();
+ }
+ return 1;
+ } else if (key == 0 || Fl::event_key() == FL_BackSpace ||
+ Fl::event_key() == FL_Delete) {
+ if (readonly()) {
+ fl_beep(FL_BEEP_ERROR);
+ return 1;
+ }
+
+ value(0);
+ do_callback();
+ return 1;
+ }
+ break;
+ }
+
+ return Fl_Widget::handle(event);
+}
+
+void SudokuCell::mark(int n, bool set) {
+ if (n<1 || n>9) return;
+ if (set) {
+ marks_ |= (1<<n);
+ } else {
+ marks_ &= ~(1<<n);
+ }
+}
+
+void SudokuCell::toggle_mark(int n) {
+ if (n<1 || n>9) return;
+ marks_ ^= (1<<n);
+}
+
+bool SudokuCell::mark(int n) {
+ if (n<1 || n>9) return 0;
+ return (marks_>>n) & 1;
+}
+
+void SudokuCell::clear_marks() {
+ marks_ = 0;
+}
+
+
+
diff --git a/test/sudoku_cell.h b/test/sudoku_cell.h
new file mode 100644
index 000000000..2fc2b9cf7
--- /dev/null
+++ b/test/sudoku_cell.h
@@ -0,0 +1,49 @@
+//
+// Sudoku game cell using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005-2018 by Michael Sweet.
+// Copyright 2019-2021 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#ifndef _SUDOKU_CELL_H_
+#define _SUDOKU_CELL_H_
+
+#include <FL/Fl_Button.H>
+
+// Sudoku cell class...
+class SudokuCell : public Fl_Widget {
+ bool readonly_;
+ int value_;
+ int marks_;
+
+ public:
+
+ SudokuCell(int X, int Y, int W, int H);
+ void draw() FL_OVERRIDE;
+ int handle(int event) FL_OVERRIDE;
+ void readonly(bool r) { readonly_ = r; redraw(); }
+ bool readonly() const { return readonly_; }
+ void mark(int n, bool set);
+ void toggle_mark(int n);
+ bool mark(int n);
+ void clear_marks();
+ void value(int v) {
+ value_ = v;
+ clear_marks();
+ redraw();
+ }
+ int value() const { return value_; }
+};
+
+
+#endif // _SUDOKU_CELL_H_
diff --git a/test/sudoku_generator.cxx b/test/sudoku_generator.cxx
index 58f8d6890..36a74850f 100644
--- a/test/sudoku_generator.cxx
+++ b/test/sudoku_generator.cxx
@@ -25,6 +25,8 @@
// and adapted to the FLTK naming scheme.
//
+#include "sudoku_generator.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
@@ -32,33 +34,6 @@
#define UNASSIGNED 0
-typedef int GridData[9][9];
-
-class Sudoku_Generator {
-private:
-public:
- GridData grid;
- GridData solnGrid;
- int guessNum[9];
- int gridPos[81];
- int difficultyLevel;
- bool grid_status;
-
-public:
- Sudoku_Generator ();
- Sudoku_Generator(int[81], bool row_major=true);
- void fillEmptyDiagonalBox(int);
- void createSeed();
- void printGrid();
- bool solveGrid();
- void countSoln(int &number);
- void genPuzzle(int minHints);
- bool gridStatus();
- void calculateDifficulty();
- void restoreWorkGrid();
- int branchDifficultyScore();
-};
-
void Sudoku_Generator::restoreWorkGrid()
{
for(int i=0;i<9;i++)
@@ -72,7 +47,6 @@ int genRandNum(int maxLimit)
return rand()%maxLimit;
}
-
// We take an integer array of the length n and swap the content around randomly.
// The function was part of the c++11 standard, but was removed in C++17 because
// it was regarded as flawed.
@@ -88,11 +62,6 @@ void random_shuffle(int *data, int n)
data[j] = tmp;
}
}
-// printf("Rand: ");
-// for (int j=0; j<n; j++) {
-// printf("%d ", data[j]);
-// }
-// printf("\n");
}
// Helper functions for solving grid
@@ -562,19 +531,19 @@ int generate_sudoku(int grid_data[81], int minHints, int maxHints)
// Generating the puzzle
puzzle->genPuzzle(minHints);
- int minDiff = 100, maxDiff = 0;
- for (int zz=0; zz<100; zz++) {
- time_t start; time(&start);
- random_shuffle(puzzle->gridPos, 81);
- puzzle->restoreWorkGrid();
- puzzle->genPuzzle(minHints);
- time_t end; time(&end);
- puzzle->calculateDifficulty();
- printf("--- in %ld, difficulty is %d\n", end-start, puzzle->difficultyLevel);
- if (puzzle->difficultyLevel < minDiff) minDiff = puzzle->difficultyLevel;
- if (puzzle->difficultyLevel > maxDiff) maxDiff = puzzle->difficultyLevel;
- }
- printf("Difficulty range is %d to %d\n", minDiff, maxDiff);
+// int minDiff = 100, maxDiff = 0;
+// for (int zz=0; zz<100; zz++) {
+// time_t start; time(&start);
+// random_shuffle(puzzle->gridPos, 81);
+// puzzle->restoreWorkGrid();
+// puzzle->genPuzzle(minHints);
+// time_t end; time(&end);
+// puzzle->calculateDifficulty();
+// printf("--- in %ld, difficulty is %d\n", end-start, puzzle->difficultyLevel);
+// if (puzzle->difficultyLevel < minDiff) minDiff = puzzle->difficultyLevel;
+// if (puzzle->difficultyLevel > maxDiff) maxDiff = puzzle->difficultyLevel;
+// }
+// printf("Difficulty range is %d to %d\n", minDiff, maxDiff);
// 22: 55 to 1658
// 25: 56 to 1456
// 28: 53 to 953, 53 to 1153, 53 to 1253
diff --git a/test/sudoku_generator.h b/test/sudoku_generator.h
new file mode 100644
index 000000000..4510adc67
--- /dev/null
+++ b/test/sudoku_generator.h
@@ -0,0 +1,60 @@
+//
+// Sudoku game generator using the Fast Light Tool Kit (FLTK).
+//
+// Copyright (c) 2018 Vaibhav Thakkar.
+// Copyright 2023 by Vaibhav Thakkar and Matthias Melcher.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+//
+// This solver is based on the work of Vaibhav Thakkar
+// from https://github.com/vaithak/Sudoku-Generator
+// vaithak/Sudoku-Generator is licensed under the MIT License
+// Copyright (c) 2018 Vaibhav Thakkar
+//
+// The solver was modified to fit FLTKs requirements of using minimal C++
+// and adapted to the FLTK naming scheme.
+//
+
+#ifndef _SUDOKU_GENERATOR_H_
+#define _SUDOKU_GENERATOR_H_
+
+typedef int GridData[9][9];
+
+extern int generate_sudoku(int grid_data[81], int minHints, int maxHints);
+
+class Sudoku_Generator {
+private:
+public:
+ GridData grid;
+ GridData solnGrid;
+ int guessNum[9];
+ int gridPos[81];
+ int difficultyLevel;
+ bool grid_status;
+
+public:
+ Sudoku_Generator ();
+ Sudoku_Generator(int[81], bool row_major=true);
+ void fillEmptyDiagonalBox(int);
+ void createSeed();
+ void printGrid();
+ bool solveGrid();
+ void countSoln(int &number);
+ void genPuzzle(int minHints);
+ bool gridStatus();
+ void calculateDifficulty();
+ void restoreWorkGrid();
+ int branchDifficultyScore();
+};
+
+#endif // _SUDOKU_GENERATOR_H_
diff --git a/test/sudoku_sound.cxx b/test/sudoku_sound.cxx
new file mode 100644
index 000000000..60acbf9c1
--- /dev/null
+++ b/test/sudoku_sound.cxx
@@ -0,0 +1,305 @@
+//
+// Sudoku game using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005-2018 by Michael Sweet.
+// Copyright 2019-2021 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#include "sudoku_sound.h"
+
+#include <FL/Fl.H>
+
+// Sound class globals...
+int SudokuSound::frequencies[9] = {
+ 880, // A(5)
+ 988, // B(5)
+ 1046, // C(5)
+ 1174, // D(5)
+ 1318, // E(5)
+ 1396, // F(5)
+ 1568, // G(5)
+ 1760, // H (A6)
+ 1976 // I (B6)
+};
+short *SudokuSound::sample_data[9] = { 0 };
+int SudokuSound::sample_size = 0;
+
+
+// Initialize the SudokuSound class
+SudokuSound::SudokuSound() {
+ sample_size = 0;
+
+#ifdef __APPLE__
+ remaining = 0;
+
+ UInt32 size = sizeof(device);
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
+ &size, (void *)&device) != noErr) return;
+
+ size = sizeof(format);
+ if (AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyStreamFormat,
+ &size, &format) != noErr) return;
+
+ // Set up a format we like...
+ format.mSampleRate = 44100.0; // 44.1kHz
+ format.mChannelsPerFrame = 2; // stereo
+
+ if (AudioDeviceSetProperty(device, NULL, 0, false,
+ kAudioDevicePropertyStreamFormat,
+ sizeof(format), &format) != noErr) return;
+
+ // Check we got linear pcm - what to do if we did not ???
+ if (format.mFormatID != kAudioFormatLinearPCM) return;
+
+ // Attach the callback and start the device
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (AudioDeviceCreateIOProcID(device, audio_cb, (void *)this, &audio_proc_id) != noErr) return;
+ AudioDeviceStart(device, audio_proc_id);
+# else
+ if (AudioDeviceAddIOProc(device, audio_cb, (void *)this) != noErr) return;
+ AudioDeviceStart(device, audio_cb);
+# endif
+
+ sample_size = (int)format.mSampleRate / 20;
+
+#elif defined(_WIN32)
+ WAVEFORMATEX format;
+
+ memset(&format, 0, sizeof(format));
+ format.cbSize = sizeof(format);
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = 2;
+ format.nSamplesPerSec = 44100;
+ format.nAvgBytesPerSec = 44100 * 4;
+ format.nBlockAlign = 4;
+ format.wBitsPerSample = 16;
+
+ data_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, format.nSamplesPerSec / 5);
+ if (!data_handle) return;
+
+ data_ptr = (LPSTR)GlobalLock(data_handle);
+
+ header_handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
+ if (!header_handle) return;
+
+ header_ptr = (WAVEHDR *)GlobalLock(header_handle);
+
+ header_ptr->lpData = data_ptr;
+ header_ptr->dwBufferLength = format.nSamplesPerSec / 5;
+ header_ptr->dwFlags = 0;
+ header_ptr->dwLoops = 0;
+
+ if (waveOutOpen(&device, WAVE_MAPPER, &format, 0, 0, WAVE_ALLOWSYNC)
+ != MMSYSERR_NOERROR) return;
+
+ waveOutPrepareHeader(device, header_ptr, sizeof(WAVEHDR));
+
+ sample_size = 44100 / 20;
+
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ handle = NULL;
+
+ if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0) {
+ // Initialize PCM sound stuff...
+ snd_pcm_hw_params_t *params;
+
+ snd_pcm_hw_params_alloca(&params);
+ snd_pcm_hw_params_any(handle, params);
+ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
+ snd_pcm_hw_params_set_channels(handle, params, 2);
+ unsigned rate = 44100;
+ int dir;
+ snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
+ snd_pcm_uframes_t period = (int)rate / 4;
+ snd_pcm_hw_params_set_period_size_near(handle, params, &period, &dir);
+
+ sample_size = rate / 20;
+
+ if (snd_pcm_hw_params(handle, params) < 0) {
+ sample_size = 0;
+ snd_pcm_close(handle);
+ handle = NULL;
+ }
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ if (sample_size) {
+ // Make each of the notes using a combination of sine and sawtooth waves
+ int attack = sample_size / 10;
+ int decay = 4 * sample_size / 5;
+
+ for (int i = 0; i < 9; i ++) {
+ sample_data[i] = new short[2 * sample_size];
+
+ short *sample_ptr = sample_data[i];
+
+ for (int j = 0; j < sample_size; j ++, sample_ptr += 2) {
+ double theta = 0.05 * frequencies[i] * j / sample_size;
+ double val = 0.5 * sin(2.0 * M_PI * theta) + theta - (int)theta - 0.5;
+
+ if (j < attack) {
+ *sample_ptr = (int)(32767 * val * j / attack);
+ } else if (j > decay) {
+ *sample_ptr = (int)(32767 * val * (sample_size - j + decay) /
+ sample_size);
+ } else *sample_ptr = (int)(32767 * val);
+
+ sample_ptr[1] = *sample_ptr;
+ }
+ }
+ }
+}
+
+
+// Cleanup the SudokuSound class
+SudokuSound::~SudokuSound() {
+#ifdef __APPLE__
+ if (sample_size) {
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ AudioDeviceStop(device, audio_proc_id);
+ AudioDeviceDestroyIOProcID(device, audio_proc_id);
+# else
+ AudioDeviceStop(device, audio_cb);
+ AudioDeviceRemoveIOProc(device, audio_cb);
+# endif
+ }
+
+#elif defined(_WIN32)
+ if (sample_size) {
+ waveOutClose(device);
+
+ GlobalUnlock(header_handle);
+ GlobalFree(header_handle);
+
+ GlobalUnlock(data_handle);
+ GlobalFree(data_handle);
+ }
+
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ if (handle) {
+ snd_pcm_drain(handle);
+ snd_pcm_close(handle);
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ if (sample_size) {
+ for (int i = 0; i < 9; i ++) {
+ delete[] sample_data[i];
+ }
+ }
+}
+
+
+#ifdef __APPLE__
+// Callback function for writing audio data...
+OSStatus
+SudokuSound::audio_cb(AudioDeviceID device,
+ const AudioTimeStamp *current_time,
+ const AudioBufferList *data_in,
+ const AudioTimeStamp *time_in,
+ AudioBufferList *data_out,
+ const AudioTimeStamp *time_out,
+ void *client_data) {
+ SudokuSound *ss = (SudokuSound *)client_data;
+ int count;
+ float *buffer;
+
+ if (!ss->remaining) return noErr;
+
+ for (count = data_out->mBuffers[0].mDataByteSize / sizeof(float),
+ buffer = (float*) data_out->mBuffers[0].mData;
+ ss->remaining > 0 && count > 0;
+ count --, ss->data ++, ss->remaining --) {
+ *buffer++ = *(ss->data) / 32767.0;
+ }
+
+ while (count > 0) {
+ *buffer++ = 0.0;
+ count --;
+ }
+
+ return noErr;
+}
+#endif // __APPLE__
+
+#define NOTE_DURATION 50
+
+// Play a note for <NOTE_DURATION> ms...
+void SudokuSound::play(char note) {
+ Fl::check();
+
+#ifdef __APPLE__
+ // Point to the next note...
+ data = sample_data[note - 'A'];
+ remaining = sample_size * 2;
+
+ // Wait for the sound to complete...
+ usleep(NOTE_DURATION*1000);
+
+#elif defined(_WIN32)
+ if (sample_size) {
+ memcpy(data_ptr, sample_data[note - 'A'], sample_size * 4);
+
+ waveOutWrite(device, header_ptr, sizeof(WAVEHDR));
+
+ Sleep(NOTE_DURATION);
+ } else Beep(frequencies[note - 'A'], NOTE_DURATION);
+
+#elif defined(FLTK_USE_X11)
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ if (handle) {
+ // Use ALSA to play the sound...
+ if (snd_pcm_writei(handle, sample_data[note - 'A'], sample_size) < 0) {
+ snd_pcm_prepare(handle);
+ snd_pcm_writei(handle, sample_data[note - 'A'], sample_size);
+ }
+ usleep(NOTE_DURATION*1000);
+ return;
+ }
+# endif // HAVE_ALSA_ASOUNDLIB_H
+
+ // Just use standard X11 stuff...
+ XKeyboardState state;
+ XKeyboardControl control;
+
+ // Get original pitch and duration...
+ XGetKeyboardControl(fl_display, &state);
+
+ // Sound a tone for the given note...
+ control.bell_percent = 100;
+ control.bell_pitch = frequencies[note - 'A'];
+ control.bell_duration = NOTE_DURATION;
+
+ XChangeKeyboardControl(fl_display,
+ KBBellPercent | KBBellPitch | KBBellDuration,
+ &control);
+ XBell(fl_display, 100);
+ XFlush(fl_display);
+
+ // Restore original pitch and duration...
+ control.bell_percent = state.bell_percent;
+ control.bell_pitch = state.bell_pitch;
+ control.bell_duration = state.bell_duration;
+
+ XChangeKeyboardControl(fl_display,
+ KBBellPercent | KBBellPitch | KBBellDuration,
+ &control);
+#endif // __APPLE__
+}
+
diff --git a/test/sudoku_sound.h b/test/sudoku_sound.h
new file mode 100644
index 000000000..dd7f6fe3c
--- /dev/null
+++ b/test/sudoku_sound.h
@@ -0,0 +1,97 @@
+//
+// Sudoku game sound using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005-2018 by Michael Sweet.
+// Copyright 2019-2023 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// https://www.fltk.org/COPYING.php
+//
+// Please see the following page on how to report bugs and issues:
+//
+// https://www.fltk.org/bugs.php
+//
+
+#ifndef _SUDOKU_SOUND_H_
+#define _SUDOKU_SOUND_H_
+
+// Audio headers...
+#include <config.h>
+
+#ifdef HAVE_ALSA_ASOUNDLIB_H
+# define ALSA_PCM_NEW_HW_PARAMS_API
+# include <alsa/asoundlib.h>
+#endif // HAVE_ALSA_ASOUNDLIB_H
+#ifdef __APPLE__
+# include <CoreAudio/AudioHardware.h>
+#endif // __APPLE__
+#ifdef _WIN32
+# include <mmsystem.h>
+#endif // _WIN32
+
+// Sound class for Sudoku...
+//
+// There are MANY ways to implement sound in a FLTK application.
+// The approach we are using here is to conditionally compile OS-
+// specific code into the application - CoreAudio for MacOS X, the
+// standard Win32 API stuff for Windows, ALSA or X11 for Linux, and
+// X11 for all others. We have to support ALSA on Linux because the
+// current Xorg releases no longer support XBell() or the PC speaker.
+//
+// There are several good cross-platform audio libraries we could also
+// use, such as OpenAL, PortAudio, and SDL, however they were not chosen
+// for this application because of our limited use of sound.
+//
+// Many thanks to Ian MacArthur who provided sample code that led to
+// the CoreAudio implementation you see here!
+class SudokuSound {
+ // Private, OS-specific data...
+#ifdef __APPLE__
+ AudioDeviceID device;
+#ifndef MAC_OS_X_VERSION_10_5
+#define MAC_OS_X_VERSION_10_5 1050
+#endif
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ AudioDeviceIOProcID audio_proc_id;
+# endif
+ AudioStreamBasicDescription format;
+ short *data;
+ int remaining;
+
+ static OSStatus audio_cb(AudioDeviceID device,
+ const AudioTimeStamp *current_time,
+ const AudioBufferList *data_in,
+ const AudioTimeStamp *time_in,
+ AudioBufferList *data_out,
+ const AudioTimeStamp *time_out,
+ void *client_data);
+#elif defined(_WIN32)
+ HWAVEOUT device;
+ HGLOBAL header_handle;
+ LPWAVEHDR header_ptr;
+ HGLOBAL data_handle;
+ LPSTR data_ptr;
+
+#else
+# ifdef HAVE_ALSA_ASOUNDLIB_H
+ snd_pcm_t *handle;
+# endif // HAVE_ALSA_ASOUNDLIB_H
+#endif // __APPLE__
+
+ // Common data...
+ static int frequencies[9];
+ static short *sample_data[9];
+ static int sample_size;
+
+ public:
+
+ SudokuSound();
+ ~SudokuSound();
+
+ void play(char note);
+};
+
+#endif // _SUDOKU_SOUND_H_