summaryrefslogtreecommitdiff
path: root/test/sudoku.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'test/sudoku.cxx')
-rw-r--r--test/sudoku.cxx591
1 files changed, 5 insertions, 586 deletions
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) {