<tb@panthema.net>
<http://www.gnu.org/licenses/>
#include "WSortView.h"
#include "SortAlgo.h"
#include "WMain.h"
#include <wx/dcbuffer.h>
size_t g_compare_count = 0;
size_t g_access_count = 0;
void ArrayItem::OnAccess(const ArrayItem& a)
{
SoundAccess(a.get_direct());
}
void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b)
{
++g_compare_count;
SoundAccess(a.get_direct());
SoundAccess(b.get_direct());
}
double g_delay = 0;
bool g_algo_running = false;
wxString g_algo_name;
WSortView::WSortView(wxWindow *parent, int id, class WMain_wxg* wmain)
: wxPanel(parent, id),
wmain(reinterpret_cast<WMain*>(wmain))
{
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
m_stepwise = false;
}
WSortView::~WSortView()
{
}
void WSortView::ResetArray(size_t size)
{
m_array.resize(size, ArrayItem(0));
m_mark.resize(size);
}
void WSortView::FinishFill()
{
ASSERT(m_array.size() > 0);
m_array_max = m_array[0].get_direct();
for (size_t i = 1; i < size(); ++i)
{
if (m_array_max < m_array[i].get_direct())
m_array_max = m_array[i].get_direct();
}
unmark_all();
unwatch_all();
m_is_sorted = false;
g_access_count = 0;
g_compare_count = 0;
}
void WSortView::FillInputlist(wxControlWithItems* list)
{
list->Append(_("Random Shuffle"));
list->Append(_("Ascending"));
list->Append(_("Descending"));
list->Append(_("Shuffled Cubic"));
list->Append(_("Shuffled Quintic"));
list->Append(_("Shuffled n-2 Equal"));
}
void WSortView::FillData(unsigned int schema, size_t arraysize)
{
if (arraysize == 0) arraysize = 1;
ResetArray(arraysize);
if (schema == 0)
{
for (size_t i = 0; i < m_array.size(); ++i)
m_array[i] = ArrayItem(i+1);
std::random_shuffle(m_array.begin(), m_array.end());
}
else if (schema == 1)
{
for (size_t i = 0; i < m_array.size(); ++i)
m_array[i] = ArrayItem(i+1);
}
else if (schema == 2)
{
for (size_t i = 0; i < m_array.size(); ++i)
m_array[i] = ArrayItem(m_array.size() - i);
}
else if (schema == 3)
{
for (size_t i = 0; i < m_array.size(); ++i)
{
double x = (2.0 * (double)i / m_array.size()) - 1.0;
double v = x * x * x;
double w = (v + 1.0) / 2.0 * arraysize + 1;
w /= 3.0;
m_array[i] = ArrayItem(w + 1);
}
std::random_shuffle(m_array.begin(), m_array.end());
}
else if (schema == 4)
{
for (size_t i = 0; i < m_array.size(); ++i)
{
double x = (2.0 * (double)i / m_array.size()) - 1.0;
double v = x * x * x * x * x;
double w = (v + 1.0) / 2.0 * arraysize + 1;
w /= 3.0;
m_array[i] = ArrayItem(w + 1);
}
std::random_shuffle(m_array.begin(), m_array.end());
}
else if (schema == 5)
{
m_array[0] = ArrayItem(1);
for (size_t i = 1; i < m_array.size()-1; ++i)
{
m_array[i] = ArrayItem( arraysize / 2 + 1 );
}
m_array[m_array.size()-1] = ArrayItem(arraysize);
std::random_shuffle(m_array.begin(), m_array.end());
}
else
{
return FillData(0, arraysize);
}
FinishFill();
}
void WSortView::DoDelay(double delay)
{
ASSERT(wmain->m_thread);
ASSERT(wxThread::GetCurrentId() == wmain->m_thread->GetId());
if (wmain->m_thread_terminate)
wmain->m_thread->Exit();
while (m_stepwise)
{
wxSemaError se = m_step_semaphore.WaitTimeout(200);
if (se == wxSEMA_NO_ERROR)
break;
wmain->m_thread->TestDestroy();
wmain->m_thread->Yield();
}
wmain->m_thread->TestDestroy();
#if __WXGTK__
wxMicroSleep(delay * 1000.0);
#else
wxMilliSleep(delay);
#endif
}
void WSortView::DoStepwise()
{
wxSemaError se = m_step_semaphore.Post();
if (se != wxSEMA_NO_ERROR)
wxLogError(_T("Error posting to semaphore: %d"), se);
}
void WSortView::OnAccess()
{
++g_access_count;
DoDelay(g_delay);
}
void WSortView::CheckSorted()
{
unmark_all();
ArrayItem prev = get_nocount(0);
mark(0);
for (size_t i = 1; i < size(); ++i)
{
ArrayItem key = get_nocount(i);
g_compare_count--;
if (!(prev <= key)) {
wxLogError(_T("Result of sorting algorithm is incorrect!"));
break;
}
mark(i);
prev = key;
}
unmark_all();
m_is_sorted = true;
}
void WSortView::RepaintNow()
{
if (!IsShownOnScreen()) return;
wxClientDC dc(this);
wxBufferedDC bdc(&dc, GetSize(), wxBUFFER_CLIENT_AREA);
paint(bdc, GetSize());
}
void WSortView::OnPaint(wxPaintEvent&)
{
wxAutoBufferedPaintDC dc(this);
paint(dc, GetSize());
}
void WSortView::OnSize(wxSizeEvent&)
{
Refresh(false);
}
template <typename Vector>
static inline bool InList(const Vector& vec, const typename Vector::value_type& v)
{
for (typename Vector::const_iterator it = vec.begin();
it != vec.end(); ++it)
{
if (*it == v) return true;
}
return false;
}
unsigned char WSortView::InWatchList(ssize_t idx) const
{
for (size_t i = 0; i < m_watch.size(); ++i)
{
if (m_watch[i].first == NULL) continue;
if (*m_watch[i].first != idx) continue;
return m_watch[i].second;
}
return 0;
}
void WSortView::paint(wxDC& dc, const wxSize& dcsize)
{
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
if (size() == 0) return;
size_t fwidth = dcsize.GetWidth();
size_t fheight = dcsize.GetHeight();
size_t width = fwidth - 20;
size_t height = fheight - 20;
dc.SetDeviceOrigin(10,10);
double wbar = (width - (size()-1)) / (double)size();
if (width <= (size()-1)) wbar = 0.0;
double bstep = wbar + 1.0;
if ( fabs(wbar - 1.0) < 0.1 && fabs(bstep - 2.0) < 0.1 ) wbar = 2, bstep = 2;
static const wxPen pens[] = {
*wxWHITE_PEN,
*wxGREEN_PEN,
*wxCYAN_PEN,
wxPen(wxColour(255,255,0)),
wxPen(wxColour(255,0,255)),
wxPen(wxColour(255,192,128)),
wxPen(wxColour(255,128,192)),
wxPen(wxColour(128,192,255)),
wxPen(wxColour(192,255,128)),
wxPen(wxColour(192,128,255)),
wxPen(wxColour(128,255,192)),
wxPen(wxColour(128,128,255)),
wxPen(wxColour(192,128,192)),
wxPen(wxColour(128,192,192)),
wxPen(wxColour(192,192,128)),
};
static const wxBrush brushes[] = {
*wxWHITE_BRUSH,
*wxGREEN_BRUSH,
*wxCYAN_BRUSH,
wxBrush(wxColour(255,255,0)),
wxBrush(wxColour(255,0,255)),
wxBrush(wxColour(255,192,128)),
wxBrush(wxColour(255,128,192)),
wxBrush(wxColour(128,192,255)),
wxBrush(wxColour(192,255,128)),
wxBrush(wxColour(192,128,255)),
wxBrush(wxColour(128,255,192)),
wxBrush(wxColour(128,128,255)),
wxBrush(wxColour(192,128,192)),
wxBrush(wxColour(128,192,192)),
wxBrush(wxColour(192,192,128)),
};
wxMutexLocker lock(m_mutex);
ASSERT(lock.IsOk());
unsigned char clr;
for (size_t i = 0; i < size(); ++i)
{
if (i == m_access1 || i == m_access2)
{
dc.SetPen( *wxRED_PEN );
dc.SetBrush( *wxRED_BRUSH );
}
else if ( (clr = InWatchList(i)) != 0 )
{
ASSERT(clr < sizeof(brushes) / sizeof(brushes[0]));
dc.SetPen( pens[clr] );
dc.SetBrush( brushes[clr] );
}
else if (m_mark[i] != 0)
{
ASSERT(m_mark[i] < sizeof(brushes) / sizeof(brushes[0]));
dc.SetPen( pens[m_mark[i]] );
dc.SetBrush( brushes[m_mark[i]] );
}
else if (InList(m_access_list, i))
{
dc.SetPen( *wxRED_PEN );
dc.SetBrush( *wxRED_BRUSH );
}
else
{
dc.SetPen( *wxWHITE_PEN );
dc.SetBrush( *wxWHITE_BRUSH );
}
dc.DrawRectangle(i*bstep, height,
wxMax(1,
(wxCoord((i+1)*bstep) - wxCoord(i*bstep))
- (bstep - wbar)
),
-(double)height * m_array[i].get_direct() / m_array_max);
}
m_access_list.clear();
}
BEGIN_EVENT_TABLE(WSortView, wxWindow)
EVT_PAINT (WSortView::OnPaint)
EVT_SIZE (WSortView::OnSize)
END_EVENT_TABLE()
SortAlgoThread::SortAlgoThread(WMain* wmain, class WSortView& array, size_t algo)
: wxThread(wxTHREAD_JOINABLE),
m_wmain(wmain),
m_array(array),
m_algo(algo)
{
}
void* SortAlgoThread::Entry()
{
ASSERT(m_algo < g_algolist_size);
const AlgoEntry& ae = g_algolist[m_algo];
ae.func(m_array);
m_array.CheckSorted();
wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, WMain::ID_RUN_FINISHED);
m_wmain->GetEventHandler()->AddPendingEvent(evt);
return NULL;
}
void SortAlgoThread::Exit()
{
wxThread::Exit();
}