Click here to Skip to main content
12,402,211 members (33,280 online)
Click here to Skip to main content

Stats

26.4K views
1.7K downloads
20 bookmarked
Posted

Checkers for Pocket PC using a Recursive Min-Max Tree

, 19 Jun 2008 CPOL
Checkers/Draughts game for Pocket PC, using the recursive Min-Max tree to calculate moves, coded with C# over the .NET Compact Framework
GamesPackage
GamesPackage.csdproj
GamesPackage.csdproj.user
GamesPackage.csproj.user
GamesPackage.resharperoptions
GamesPackage.suo
SoundPPCLibrary
SoundPPCLibrary.csdproj
SoundPPCLibrary.csdproj.user
SoundPPCLibrary.csproj.user
SoundPPCLibrary.resharperoptions
SoundPPCLibrary.suo
BoardEngine
BoardEngine.csdproj
BoardEngine.csdproj.user
BoardEngine.csproj.user
Checkers
001_select_checker_0.wav
002_select_destination_0.wav
003_player_move_0.wav
004_eat_a_player_0.wav
005_end_of_the_board_0.wav
006_game_over_0.wav
007_win_game_0.wav
CHECKER.ico
Checkers.csdproj
Checkers.csdproj.user
Checkers.csproj.user
Checkers.resharper.user
Checkers.resharperoptions
Checkers.suo
checkersico.ico
Thumbs.db
Checkers.csdproj
Checkers.csdproj.user
Checkers.csproj.user
checkersico.ico
001_select_checker_0.wav
002_select_destination_0.wav
003_player_move_0.wav
004_eat_a_player_0.wav
005_end_of_the_board_0.wav
006_game_over_0.wav
007_win_game_0.wav
CHECKER.ico
using System;
using System.IO;
using System.Threading;
using System.Collections;
using Microsoft.WindowsCE.Forms;


namespace SoundPPCLibray
{
	public class SoundPlayer: ISound
	{
		#region Members 
		MyWaveOutMsgWindow	myWceMessageWindow;
		IntPtr				myWaveOutHandle;
		int					mySampleSize;
		const int			myReadBufferSize = 2048;
		int					myWaveBufferSize;
		ArrayList			myPlayingSounds;
		
		Thread				myMixerThread;
		byte []				myMixerBuffer;
		AutoResetEvent		myMixerEvent;
		
		bool				myMixerQuit;
		Queue				myWaveHdrFreeQueue;
		#region added by khazim

		public bool Mute
		{
			get { return _Mute; }
			set { _Mute = value; }
		}

		private bool _Mute;

		#endregion

		const int			myNbWaveHdr = 5;

		#endregion

		#region Constructor
		public SoundPlayer()
		{
			mySampleSize = 0;
			myWaveOutHandle = IntPtr.Zero;
			myMixerQuit = false;
			myPlayingSounds = new ArrayList();
			myWaveHdrFreeQueue = new Queue();
			myMixerEvent = new AutoResetEvent(false); // start non-signaled (blocking)
			myWceMessageWindow = new MyWaveOutMsgWindow();
			myWceMessageWindow.SetBufferDoneCallback(new MyWaveOutMsgWindow.Callback(this.WaveOutBufferDone));

			OpenDevice();

			if (myWaveOutHandle != IntPtr.Zero)
			{
				StartMixerThread();
			}
			else
			{
				Dispose();
			}
		}
		#endregion
	
		#region Public Methods and Properties

		#region public bool HasSoundHandle
		public bool HasSoundHandle
		{
			get { return myWaveOutHandle != IntPtr.Zero;}
		}
		#endregion
		
		#region public void Dispose()
		public void Dispose()
		{
			StopPlayback();
			StopMixerThread();

			if (myWceMessageWindow != null)
			{
				myWceMessageWindow.Dispose();
				myWceMessageWindow = null;
			}

			if (myMixerEvent != null)
			{
				myMixerEvent.Close();
				myMixerEvent = null;
			}

			CloseDevice();
		}
		#endregion
		
		#region public object CreateSoundBuffer(Stream stream)
		public object CreateSoundBuffer(Stream stream)
		{
			return new MyWavStreamReader(stream);
		}
		#endregion
		
		#region public void DisposeSoundBuffer(object sound)
		public void DisposeSoundBuffer(object sound)
		{
			if (sound != null && sound is IDisposable)
				((IDisposable)sound).Dispose();
		}
		#endregion

		#region public bool Play(MySound sound)
		public bool Play(MySound sound)
		{
			return Play(sound, true);
		}
		#endregion

		#region public bool Play(MySound sound, bool restart)
		public bool Play(MySound sound, bool restart)
		{
			//System.Diagnostics.Debug.Assert(sound != null);
			if (sound == null || _Mute)
				return false;

			System.Diagnostics.Debug.Assert(sound.SoundData != null);
			if (sound.SoundData == null)
				return false;

			MySoundReader reader = sound.SoundData as MySoundReader;

			if (IsPlaying(reader))
			{
				if (restart)
					StopSound(reader);

				
				return true;
			}

			AddSound(reader);
			return true;
		}
		#endregion
		
		#region public bool Stop(MySound sound)
		public bool Stop(MySound sound)
		{
			System.Diagnostics.Debug.Assert(sound != null);
			if (sound == null)
				return false;

			System.Diagnostics.Debug.Assert(sound.SoundData != null);
			if (sound.SoundData == null)
				return false;

			MySoundReader reader = sound.SoundData as MySoundReader;

			StopSound(reader);

			return true;
		}
		#endregion

		#region public bool Wait(MySound sound)
		public bool Wait(MySound sound)
		{
			System.Diagnostics.Debug.Assert(sound != null);
			if (sound == null)
				return false;

			System.Diagnostics.Debug.Assert(sound.SoundData != null);
			if (sound.SoundData == null)
				return false;

			MySoundReader reader = sound.SoundData as MySoundReader;

			WaitSound(reader);

			return true;
		}
		#endregion

		#endregion

		#region Private Methods

		#region private void OpenDevice()
		private void OpenDevice()
		{
			CloseDevice();

			
			for(int s = 1; s <= 2; s++)
			{
				
				for(int b = 1; b <= 1; b++)
				{
					
					for(int r = 1; r <= 4; r *= 2)
					{
						mySampleSize = s * b * r;
						myWaveBufferSize = myReadBufferSize * mySampleSize;
						myWaveOutHandle = OpenWaveOutDevice((s == 2), r*11025, b*8);

						if (myWaveOutHandle != IntPtr.Zero)
							return;
					}
				}
			}
		}
		#endregion
		
		#region private void StopPlayback()
		private void StopPlayback()
		{
			if (myWaveOutHandle != IntPtr.Zero)
			{
				MyWaveOut.waveOutReset(myWaveOutHandle);
			}
		}
		#endregion

		#region private void CloseDevice()
		private void CloseDevice()
		{
			if (myWaveOutHandle != IntPtr.Zero)
			{
				MyWaveOut.waveOutClose(myWaveOutHandle);
				myWaveOutHandle = IntPtr.Zero;
			}
		}
		#endregion

		#region private IntPtr OpenWaveOutDevice(bool stereo, int samplesPerSec, int bitPerSample)
		private IntPtr OpenWaveOutDevice(bool stereo, int samplesPerSec, int bitPerSample)
		{
			IntPtr hWaveOut = IntPtr.Zero;

			try
			{
				

				ushort nChannels = (ushort)(stereo ? 2 : 1);
				ushort nBlockAlign = (ushort)(nChannels*bitPerSample/8);
				uint nAvgBytesPerSec = (uint)(samplesPerSec*nBlockAlign);

				MyWaveOut.MyWAVEFORMATEX wFormatEx = new MyWaveOut.MyWAVEFORMATEX();
				wFormatEx.wFormatTag = (ushort)MyWaveOut.WAVE_FORMAT_PCM;
				wFormatEx.nChannels = nChannels;
				wFormatEx.nSamplesPerSec = (uint)samplesPerSec;
				wFormatEx.nAvgBytesPerSec = nAvgBytesPerSec;
				wFormatEx.nBlockAlign = nBlockAlign;
				wFormatEx.wBitsPerSample = (ushort)bitPerSample;

				MyWaveOut.myMMSYSERR err = MyWaveOut.waveOutOpen(
					ref hWaveOut,
					MyWaveOut.WAVE_MAPPER,
					wFormatEx,
					myWceMessageWindow.Hwnd,
					0,
					MyWaveOut.CALLBACK_WINDOW);
				

				if (err != MyWaveOut.myMMSYSERR.NOERROR)
					return IntPtr.Zero;
			}
			catch(Exception ex)
			{
				System.Diagnostics.Debug.WriteLine(ex.Message);
			}

			return hWaveOut;
		}
		#endregion

		#region private bool IsPlaying(RISoundReader reader)
		private bool IsPlaying(MySoundReader reader)
		{
			lock(myPlayingSounds.SyncRoot)
			{
				foreach(MySoundData sd in myPlayingSounds)
				{
					if (sd.myReader == reader)
						return true;
				}
			}

			return false;
		}
		#endregion

		#region private void AddSound(MySoundReader reader)
		private void AddSound(MySoundReader reader)
		{
			lock(myPlayingSounds.SyncRoot)
			{
				
				foreach(MySoundData sd1 in myPlayingSounds)
				{
					if (sd1.myReader == reader)
						return;
				}

				MySoundData sd2 = new MySoundData(reader);
				myPlayingSounds.Add(sd2);
				
				if (myMixerEvent != null)
					myMixerEvent.Set();
			}
		}
		#endregion

		#region private void StopSound(MySoundReader reader)
		private void StopSound(MySoundReader reader)
		{
			lock(myPlayingSounds.SyncRoot)
			{
				for(int i = myPlayingSounds.Count-1; i >= 0; i--)
				{
					MySoundData sd = myPlayingSounds[i] as MySoundData;
					if (sd.myReader == reader)
					{
						sd.Stop();
						return;
					}
				}
			}
		}
		#endregion

		#region private void WaitSound(MySoundReader reader)
		private void WaitSound(MySoundReader reader)
		{
			while(IsPlaying(reader))
			{
				System.Windows.Forms.Application.DoEvents();
				System.Threading.Thread.Sleep(250);	// 1/4 second
			}
		}
		#endregion

		#region private void StartMixerThread()
		private void StartMixerThread()
		{
			
			while(myWaveHdrFreeQueue.Count < myNbWaveHdr)
			{
				IntPtr hdr = AllocWaveHdr();
				System.Diagnostics.Debug.Assert(hdr != IntPtr.Zero);
				if (hdr != IntPtr.Zero)
					myWaveHdrFreeQueue.Enqueue(hdr);
				else
					break;
			}

			
			if (myMixerThread == null)
			{
				myMixerQuit = false;
				myMixerEvent.Reset();

				myMixerThread = new Thread(new ThreadStart(this.MixerLoop));
				myMixerThread.Start();
			}
		}
		#endregion 

		#region private void StopMixerThread()
		private void StopMixerThread()
		{
			if (myMixerThread != null)
			{
		
				myMixerQuit = true;
				myMixerEvent.Set();

				for(int i=0; i<8; i++)
				{
					Thread.Sleep(250); // 250 ms
					if (myMixerThread == null)
						break;
				}

				myMixerThread = null;
			}

			if (myWaveHdrFreeQueue != null)
				while(myWaveHdrFreeQueue.Count > 0)
					FreeWaveHdr((IntPtr) myWaveHdrFreeQueue.Dequeue());
		}
		#endregion

		#region private IntPtr AllocWaveHdr()
		private IntPtr AllocWaveHdr()
		{
			IntPtr hdr = MyMemAlloc.LocalAlloc(MyMemAlloc.LMEM_FIXED, 8*4 + myWaveBufferSize);

			unsafe
			{
				uint *ptr = (uint *) hdr.ToPointer();

				*(ptr++) = (uint)hdr.ToInt32() + MyWaveOut.SizeofWAVEHDR;	
				*(ptr++) = (uint)myWaveBufferSize;		
				*(ptr++) = 0;							
				*(ptr++) = 0;							
				*(ptr++) = 0;							
				*(ptr++) = 0;							
				*(ptr++) = 0;							
				*(ptr++) = 0;							
			}
			
			MyWaveOut.myMMSYSERR mmerr;
			mmerr = MyWaveOut.waveOutPrepareHeader(myWaveOutHandle, hdr, MyWaveOut.SizeofWAVEHDR);
			System.Diagnostics.Debug.Assert(mmerr == MyWaveOut.myMMSYSERR.NOERROR, mmerr.ToString());

			return hdr;
		}
		#endregion

		#region private void FreeWaveHdr(IntPtr hdr)
		private void FreeWaveHdr(IntPtr hdr)
		{
			if (hdr != IntPtr.Zero)
			{
				MyWaveOut.myMMSYSERR mmerr;
				mmerr = MyWaveOut.waveOutUnprepareHeader(myWaveOutHandle, hdr, MyWaveOut.SizeofWAVEHDR);
				System.Diagnostics.Debug.Assert(mmerr == MyWaveOut.myMMSYSERR.NOERROR, mmerr.ToString());
				
				MyMemAlloc.LocalFree(hdr);
			}
		}
		#endregion

		#region private void MixerLoop()
		private void MixerLoop()
		{
			myMixerBuffer = new byte[myReadBufferSize];
			
			while (myMixerEvent != null && myMixerEvent.WaitOne())
			{
				if (myMixerQuit)
					break;
				
				bool need_to_play = false;
				lock(myPlayingSounds.SyncRoot)
				{
					for(int i = myPlayingSounds.Count-1; i >= 0; i--)
					{
						MySoundData sd = myPlayingSounds[i] as MySoundData;
					
						if (sd.myStop)
						{
							myPlayingSounds.RemoveAt(i);
						}
						else if (sd.IsPlaying)
						{
							need_to_play = true;
							break;
						}
					}
				}


				if (!need_to_play)
					continue;

				
				IntPtr waveHdr = IntPtr.Zero;
				
				lock(myWaveHdrFreeQueue.SyncRoot)
				{
					if (myWaveHdrFreeQueue.Count > 0)
						waveHdr = (IntPtr) myWaveHdrFreeQueue.Dequeue();
				}
				
				if (waveHdr == IntPtr.Zero)
					continue;

				
				if (MixBuffer(waveHdr))
				{
				
					MyWaveOut.myMMSYSERR mmerr;
					mmerr = MyWaveOut.waveOutWrite(this.myWaveOutHandle, waveHdr, MyWaveOut.SizeofWAVEHDR);
					System.Diagnostics.Debug.Assert(mmerr == MyWaveOut.myMMSYSERR.NOERROR, mmerr.ToString());
				}
				else
				{
					lock(myWaveHdrFreeQueue.SyncRoot)
					{
						myWaveHdrFreeQueue.Enqueue(waveHdr);
					}
				}
				
				myMixerEvent.Set();
			}

			myMixerThread = null;
			myMixerBuffer = null;
		}
		#endregion

		#region private void WaveOutBufferDone(IntPtr waveHdr)
		private void WaveOutBufferDone(IntPtr waveHdr)
		{
		
			lock(myWaveHdrFreeQueue.SyncRoot)
			{
				myWaveHdrFreeQueue.Enqueue(waveHdr);
			}

			if (myMixerEvent != null)
				myMixerEvent.Set();
		}
		#endregion

		#region private bool MixBuffer(IntPtr waveHdr)
		private bool MixBuffer(IntPtr waveHdr)
		{
			
			int max_data = 0;

			unsafe
			{
				int *header = (int *) waveHdr.ToPointer();
				
				uint *dest32 = (uint *)(header[0]);
				int size = myWaveBufferSize / 4;
				
				while(size-- > 0)
					*(dest32++) = 0x80808080;
			}

			lock(myPlayingSounds.SyncRoot)
			{
				bool is_first = true;

				for(int i = myPlayingSounds.Count-1; i >= 0; i--)
				{
					MySoundData sd = myPlayingSounds[i] as MySoundData;

					if (sd.IsPlaying)
					{
						int read_size = sd.mySize - sd.myOffset;
						if (read_size > myReadBufferSize)
							read_size = myReadBufferSize;

						if (sd.myReader.Read(myMixerBuffer, sd.myOffset, read_size))
						{
							unsafe
							{
								unchecked
								{
									fixed(byte *source = myMixerBuffer)
									{
										int *header = (int *) waveHdr.ToPointer();
										byte *dest = (byte *) (header[0]);

										if (mySampleSize == 1 && is_first)
										{
											if (read_size > max_data)
												max_data = read_size;

											int c = read_size/4;

											uint* dest4 = (uint *)dest;
											uint* src4 = (uint *)source;

											for(; c > 0; c--)
												*(dest4++) = *(src4)++;

											dest = (byte *)dest4;
											byte *src1 = (byte *)src4;
											for(c = read_size%4; c > 0; c--)
												*(dest++) = *(src1)++;
										}
										else
										{
											int rsn = read_size * mySampleSize;
											if (rsn > max_data)
												max_data = rsn;

											byte *src = (byte *)source;
											if (is_first)
											{
												for (int c = read_size; c > 0; c--)
												{
													byte a = *(src++);
													for(int j = mySampleSize; j > 0; j--)
														*(dest++) = a;
												}
											}
											else
											{
												for (int c = read_size; c > 0; c--)
												{
													
													int a = (int)(*dest) + (int)(*(src)++) - 0x80;
													if (a < 0)
														a = 0;
													else if (a > 0xFF)
														a = 0xFF;

													byte b = (byte)a;

													for(int j = mySampleSize; j > 0; j--)
														*(dest++) = b;
												}
											}
										}

									} 
								} 
							} 

							sd.myOffset += read_size;
							is_first = false;

						} 
					} 
					
					if (sd.myOffset >= sd.mySize)
					{
						if (sd.mRepeat)
						{
							sd.myOffset = 0;
						}
						else
						{
							myPlayingSounds.RemoveAt(i);
						}
					}
				} 
			} 

			if (max_data != 0)
			{
				unsafe
				{
					int *header = (int *) waveHdr.ToPointer();
	
					
					header[2] = max_data;			
					header[4] = header[4] & (~MyWaveOut.WHDR_DONE);
				}
			}

			return max_data > 0;
		}
		#endregion

		#endregion

		#region Classes

		#region protected class MySoundData
		protected class MySoundData
		{
			#region Members
			
			public	MySoundReader myReader;
			public	int myOffset;
			public	int	mySize;
			public	bool mRepeat;
			public	bool myStop;
			
			#endregion

			#region Constructor
			public MySoundData(MySoundReader reader)
			{
				myReader = reader;
				mySize = reader.Size();
				myStop = false;
				myOffset = 0;
			}
			#endregion

			#region public bool IsPlaying
			public bool IsPlaying
			{ 
				get { return myReader != null && !myStop && mySize > 0; }
			}
			#endregion

			#region public void Rewind()
			public void Rewind()
			{
				myOffset = 0;
			}
			#endregion

			#region public void Stop()
			public void Stop()
			{
				myOffset = mySize;
				myStop = true;
			}
			#endregion
			
		}
		#endregion
		
		#region private class MyWaveOutMsgWindow: MessageWindow
		private class MyWaveOutMsgWindow: MessageWindow
		{
			#region Members
			public delegate void Callback(IntPtr waveHdrPtr);
			private Callback mBufferDoneCallback = null;
			#endregion

			#region public void SetBufferDoneCallback(Callback cb)
			public void SetBufferDoneCallback(Callback cb)
			{
				mBufferDoneCallback = cb;
			}
			#endregion

			#region protected override void WndProc(ref Message m)
			protected override void WndProc(ref Message m)
			{
				if (m.Msg == MyWaveOut.MM_WOM_DONE && mBufferDoneCallback != null)
					mBufferDoneCallback(m.LParam);
				base.WndProc(ref m);
			}
			#endregion
			
		}
		#endregion

		#endregion
	} 
} 

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Leonardo Paneque
Architect
United States United States
Leonardo loves to code with C# on any platform and OS.
He has a Master degree in Computer Sciences and likes to share code and ideas.

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 20 Jun 2008
Article Copyright 2008 by Leonardo Paneque
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid