diff --git a/CustomDevice/CustomDevice.csproj b/CustomDevice/CustomDevice.csproj
new file mode 100644
index 0000000..5633e6a
--- /dev/null
+++ b/CustomDevice/CustomDevice.csproj
@@ -0,0 +1,105 @@
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {43619745-0A80-499E-907C-E733FF3DA2BE}
+ Library
+ Properties
+ CustomDevice
+ CustomDevice
+
+
+
+
+ 2.0
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ 512
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ 512
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+
+
+ False
+ .NET Framework Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+ copy $(TargetPath) $(SolutionDir)\Builds\$(ConfigurationName)\
+
+
\ No newline at end of file
diff --git a/CustomDevice/DeviceGraphics.cs b/CustomDevice/DeviceGraphics.cs
new file mode 100644
index 0000000..829b93c
--- /dev/null
+++ b/CustomDevice/DeviceGraphics.cs
@@ -0,0 +1,88 @@
+// Copyright (c) 2009 DotNetAnywhere
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+
+namespace CustomDevice {
+
+ public static class DeviceGraphics {
+
+ private const int ScreenX = 320;
+ private const int ScreenY = 240;
+
+ private static int whichScreen = 0;
+
+ public static int ScreenXSize {
+ get {
+ return ScreenX;
+ }
+ }
+
+ public static int ScreenYSize {
+ get {
+ return ScreenY;
+ }
+ }
+
+ public static Graphics GetScreen() {
+ if (whichScreen == 0) {
+ if (Utils.IsInterNet2) {
+ whichScreen = 1;
+ } else {
+ whichScreen = 2;
+ }
+ }
+ if (whichScreen == 1) {
+ return GetScreen_InterNet2();
+ } else {
+ return GetScreen_Windows();
+ }
+ }
+
+ private static Graphics GetScreen_InterNet2() {
+ // In the InterNet2 System.Drawing dll Graphics.FromHdc() will always
+ // return the Graphics object for the screen.
+ return Graphics.FromHdc(IntPtr.Zero);
+ }
+
+ private static Graphics GetScreen_Windows() {
+
+ if (WindowsScreen.winScreen == null) {
+ Thread t = new Thread(WindowsScreen.WindowsMessagePump);
+ t.IsBackground = true;
+ t.Start();
+ while (WindowsScreen.winScreen == null) {
+ Thread.Sleep(2);
+ }
+ }
+
+ lock (WindowsScreen.winScreen) {
+ Graphics g = Graphics.FromImage(WindowsScreen.winScreen.FormSurface);
+ return g;
+ }
+ }
+
+ }
+
+}
diff --git a/CustomDevice/KeyPad.cs b/CustomDevice/KeyPad.cs
new file mode 100644
index 0000000..13c22a3
--- /dev/null
+++ b/CustomDevice/KeyPad.cs
@@ -0,0 +1,102 @@
+// Copyright (c) 2009 DotNetAnywhere
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Threading;
+
+namespace CustomDevice {
+ public static class KeyPad {
+
+ [DllImport("libIGraph")]
+ extern private static bool IsKeyDown_Internal(KeyPadKey key);
+
+ [DllImport("libIGraph")]
+ extern private static int LatestKeyUp_Internal();
+
+ [DllImport("libIGraph")]
+ extern private static int LatestKeyDown_Internal();
+
+ public static bool IsKeyDown(KeyPadKey key) {
+ if (Utils.IsInterNet2) {
+ return IsKeyDown_Internal(key);
+ } else {
+ return WindowsScreen.WinScreen.IsKeyDown(key);
+ }
+ }
+
+ private static bool WindowsLatestKeyUp(out KeyPadKey key) {
+ return WindowsScreen.WinScreen.LatestKeyUp(out key);
+ }
+
+ private static bool WindowsLatestKeyDown(out KeyPadKey key) {
+ return WindowsScreen.WinScreen.LatestKeyDown(out key);
+ }
+
+ public static bool LatestKeyUp(out KeyPadKey key) {
+ if (Utils.IsInterNet2) {
+ int iKey = LatestKeyUp_Internal();
+ if (iKey >= 0) {
+ key = (KeyPadKey)iKey;
+ return true;
+ } else {
+ key = KeyPadKey.B0;
+ return false;
+ }
+ } else {
+ return WindowsLatestKeyUp(out key);
+ }
+ }
+
+ public static bool LatestKeyDown(out KeyPadKey key) {
+ if (Utils.IsInterNet2) {
+ int iKey = LatestKeyDown_Internal();
+ if (iKey >= 0) {
+ key = (KeyPadKey)iKey;
+ return true;
+ } else {
+ key = KeyPadKey.B0;
+ return false;
+ }
+ } else {
+ return WindowsLatestKeyDown(out key);
+ }
+ }
+
+ public static KeyPadKey? ReadKey(int timeoutMs) {
+ DateTime end = DateTime.UtcNow.AddMilliseconds(timeoutMs);
+ do {
+ KeyPadKey key;
+ if (LatestKeyDown(out key)) {
+ return key;
+ }
+ Thread.Sleep(1);
+ } while (DateTime.UtcNow < end && timeoutMs >= 0);
+ return null;
+ }
+
+ public static KeyPadKey? ReadKey() {
+ return ReadKey(-1);
+ }
+ }
+}
diff --git a/CustomDevice/KeyPadKey.cs b/CustomDevice/KeyPadKey.cs
new file mode 100644
index 0000000..aa5b5a7
--- /dev/null
+++ b/CustomDevice/KeyPadKey.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 DotNetAnywhere
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CustomDevice {
+ public enum KeyPadKey {
+
+ B0 = 0,
+ B1 = 1,
+ B2 = 2,
+ B3 = 3,
+ B4 = 4,
+ B5 = 5,
+ B6 = 6,
+ B7 = 7,
+ B8 = 8,
+ B9 = 9,
+ C = 10,
+ OK = 11
+
+ }
+}
diff --git a/CustomDevice/Properties/AssemblyInfo.cs b/CustomDevice/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..cef3e29
--- /dev/null
+++ b/CustomDevice/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DeviceGraphics")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Docobo")]
+[assembly: AssemblyProduct("DeviceGraphics")]
+[assembly: AssemblyCopyright("Copyright © Docobo 2007")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a7a488bb-a22b-4377-ab45-d2139150ff7d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/CustomDevice/Utils.cs b/CustomDevice/Utils.cs
new file mode 100644
index 0000000..2f91131
--- /dev/null
+++ b/CustomDevice/Utils.cs
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 DotNetAnywhere
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CustomDevice {
+ static class Utils {
+
+ private static bool isInterNet2, isInterNet2Set = false;
+ public static bool IsInterNet2 {
+ get {
+ if (!isInterNet2Set) {
+ isInterNet2 = Environment.OSVersion.VersionString.EndsWith("(InterNet2)");
+ isInterNet2Set = true;
+ }
+ return isInterNet2;
+ }
+ }
+
+ }
+}
diff --git a/CustomDevice/WindowsScreen.cs b/CustomDevice/WindowsScreen.cs
new file mode 100644
index 0000000..c3f01ff
--- /dev/null
+++ b/CustomDevice/WindowsScreen.cs
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 DotNetAnywhere
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Threading;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace CustomDevice {
+ class WindowsScreen : Form {
+
+ internal static WindowsScreen winScreen = null;
+
+ public static WindowsScreen WinScreen {
+ get {
+ if (winScreen == null) {
+ using (Graphics g = DeviceGraphics.GetScreen()) {
+ }
+ }
+ return winScreen;
+ }
+ }
+
+ public WindowsScreen(int width, int height) {
+ this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+ this.SetStyle(ControlStyles.FixedWidth, true);
+ this.SetStyle(ControlStyles.FixedHeight, true);
+ this.SetStyle(ControlStyles.Opaque, true);
+ this.SetStyle(ControlStyles.UserPaint, true);
+
+ this.formSurface = new Bitmap(width, height);
+
+ this.ClientSize = new Size(width, height);
+
+ this.Show();
+ this.Activate();
+
+ }
+
+ private Bitmap formSurface;
+
+ public Bitmap FormSurface {
+ get {
+ return this.formSurface;
+ }
+ }
+
+ protected override void OnPaint(PaintEventArgs e) {
+ lock (this) {
+ e.Graphics.DrawImageUnscaled(this.formSurface, new Point());
+ }
+ }
+
+ internal static void WindowsMessagePump(object state) {
+ WindowsScreen.winScreen = new WindowsScreen(DeviceGraphics.ScreenXSize, DeviceGraphics.ScreenYSize);
+ for (; ; ) {
+ Application.DoEvents();
+ Thread.Sleep(40);
+ WindowsScreen.winScreen.Refresh();
+ }
+ }
+
+ private bool[] keyState = new bool[12];
+
+ private KeyPadKey MapKey(Keys pcKey, out bool isValid) {
+ isValid = true;
+ switch (pcKey) {
+ case Keys.D0:
+ case Keys.NumPad0:
+ return KeyPadKey.B0;
+ case Keys.D1:
+ case Keys.NumPad1:
+ return KeyPadKey.B1;
+ case Keys.D2:
+ case Keys.NumPad2:
+ return KeyPadKey.B2;
+ case Keys.D3:
+ case Keys.NumPad3:
+ return KeyPadKey.B3;
+ case Keys.D4:
+ case Keys.NumPad4:
+ return KeyPadKey.B4;
+ case Keys.D5:
+ case Keys.NumPad5:
+ return KeyPadKey.B5;
+ case Keys.D6:
+ case Keys.NumPad6:
+ return KeyPadKey.B6;
+ case Keys.D7:
+ case Keys.NumPad7:
+ return KeyPadKey.B7;
+ case Keys.D8:
+ case Keys.NumPad8:
+ return KeyPadKey.B8;
+ case Keys.D9:
+ case Keys.NumPad9:
+ return KeyPadKey.B9;
+ case Keys.Enter:
+ return KeyPadKey.OK;
+ case Keys.Escape:
+ return KeyPadKey.C;
+ default:
+ isValid = false;
+ return KeyPadKey.B0;
+ }
+ }
+
+ protected override void OnKeyDown(KeyEventArgs e) {
+ bool isValid;
+ KeyPadKey key = this.MapKey(e.KeyCode, out isValid);
+ if (isValid) {
+ e.Handled = true;
+ this.keyState[(int)key] = true;
+ this.latestKeyDown = key;
+ return;
+ }
+ base.OnKeyDown(e);
+ }
+
+ protected override void OnKeyUp(KeyEventArgs e) {
+ bool isValid;
+ KeyPadKey key = this.MapKey(e.KeyCode, out isValid);
+ if (isValid) {
+ e.Handled = true;
+ this.keyState[(int)key] = false;
+ this.latestKeyUp = key;
+ return;
+ }
+ base.OnKeyUp(e);
+ }
+
+ public bool IsKeyDown(KeyPadKey key) {
+ return this.keyState[(int)key];
+ }
+
+ private KeyPadKey? latestKeyUp = null;
+ public bool LatestKeyUp(out KeyPadKey key) {
+ if (this.latestKeyUp.HasValue) {
+ key = this.latestKeyUp.Value;
+ this.latestKeyUp = null;
+ return true;
+ } else {
+ key = KeyPadKey.B0;
+ return false;
+ }
+ }
+
+ private KeyPadKey? latestKeyDown = null;
+ public bool LatestKeyDown(out KeyPadKey key) {
+ if (this.latestKeyDown.HasValue) {
+ key = this.latestKeyDown.Value;
+ this.latestKeyDown = null;
+ return true;
+ } else {
+ key = KeyPadKey.B0;
+ return false;
+ }
+ }
+ }
+}
diff --git a/Snake/ASnake.cs b/Snake/ASnake.cs
new file mode 100644
index 0000000..a0d32fa
--- /dev/null
+++ b/Snake/ASnake.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+
+namespace Snake {
+ class ASnake {
+
+ private SnakePit snakePit;
+ private Queue bodyParts = new Queue();
+ private Point head;
+ private int xSpeed, ySpeed;
+ private Color col;
+ private int increaseBy;
+
+ public ASnake(SnakePit snakePit, int startLength, Point startPosition, Color col) {
+ this.snakePit = snakePit;
+ for (int i = 0; i < startLength; i++) {
+ Point cell = new Point(startPosition.X - startLength + i + 1, startPosition.Y);
+ snakePit.SetCell(cell, col);
+ this.bodyParts.Enqueue(cell);
+ this.head = cell;
+ }
+ this.col = col;
+ this.xSpeed = 1;
+ this.ySpeed = 0;
+ this.increaseBy = 0;
+ snakePit.AddSnake(this);
+ }
+
+ public CrashType Move() {
+ if (this.increaseBy == 0) {
+ Point tail = this.bodyParts.Dequeue();
+ snakePit.ClearCell(tail);
+ } else {
+ this.increaseBy--;
+ }
+ this.head.X += this.xSpeed;
+ this.head.Y += this.ySpeed;
+ if (this.DoesIntersect(this.head)) {
+ Console.WriteLine("!!!SELF CRASH!!!");
+ return CrashType.Self;
+ }
+ this.bodyParts.Enqueue(this.head);
+ snakePit.SetCell(this.head, this.col);
+ CrashType crash = this.snakePit.IsCrash(head);
+ return crash;
+ }
+
+ public void DrawHead() {
+ snakePit.SetCell(this.head, this.col);
+ }
+
+ public void SetDirection(int x, int y) {
+ // Do nothing if trying to set current or opposite direction
+ if (x != 0 && this.xSpeed != 0) {
+ return;
+ }
+ if (y != 0 && this.ySpeed != 0) {
+ return;
+ }
+ // Set new speeds
+ this.xSpeed = x;
+ this.ySpeed = y;
+ }
+
+ public bool DoesIntersect(IEnumerable cells) {
+ foreach (Point cell in cells) {
+ if (this.DoesIntersect(cell)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool DoesIntersect(Point cell) {
+ foreach (Point p in this.bodyParts) {
+ if (p == cell) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void IncreaseLength(int amount) {
+ this.increaseBy += amount;
+ }
+
+ public Point Head {
+ get {
+ return this.head;
+ }
+ }
+
+ }
+}
diff --git a/Snake/CrashType.cs b/Snake/CrashType.cs
new file mode 100644
index 0000000..881f514
--- /dev/null
+++ b/Snake/CrashType.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Snake {
+ public enum CrashType {
+ None,
+ Self,
+ Wall,
+ Food,
+ }
+}
diff --git a/Snake/Program.cs b/Snake/Program.cs
new file mode 100644
index 0000000..73fdce1
--- /dev/null
+++ b/Snake/Program.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using CustomDevice;
+
+namespace Snake {
+ class Program {
+ static void Main(string[] args) {
+ for (; ; ) {
+ bool res = Play();
+ if (!res) {
+ break;
+ }
+ }
+ }
+
+ static bool Play() {
+
+ Font f = new Font("tahoma", 25);
+ SnakePit snakePit = new SnakePit();
+ Random rnd = new Random();
+ int delay = 300;
+
+ ASnake snake = new ASnake(snakePit, 5, snakePit.Centre, Color.Black);
+
+ CrashType crashType;
+ for (; ; ) {
+ Thread.Sleep(delay);
+ KeyPadKey key;
+ if (KeyPad.LatestKeyDown(out key)) {
+ switch (key) {
+ case KeyPadKey.B6: // Left
+ snake.SetDirection(-1, 0);
+ break;
+ case KeyPadKey.B7: // Down
+ snake.SetDirection(0, 1);
+ break;
+ case KeyPadKey.B8: // Up
+ snake.SetDirection(0, -1);
+ break;
+ case KeyPadKey.B9: // Right
+ snake.SetDirection(1, 0);
+ break;
+ case KeyPadKey.C:
+ return false;
+ }
+ }
+ crashType = snake.Move();
+ bool finish = false;
+ switch (crashType) {
+ case CrashType.None:
+ break;
+ case CrashType.Self:
+ case CrashType.Wall:
+ default:
+ finish = true;
+ break;
+ case CrashType.Food:
+ bool levelUp = snakePit.EatFood();
+ if (levelUp) {
+ delay = (delay * 3) / 4;
+ }
+ snake.IncreaseLength(4);
+ break;
+
+ }
+ snake.DrawHead();
+ if (finish) {
+ break;
+ }
+
+ int r = rnd.Next(1000);
+ if (r < 50) {
+ snakePit.CreateFood(r < 5);
+ }
+ r = rnd.Next(1000);
+ if (r < 20) {
+ snakePit.AddObsticle();
+ }
+ }
+ snakePit.Msg(crashType.ToString());
+ Thread.Sleep(5000);
+
+ return true;
+ }
+ }
+}
diff --git a/Snake/Properties/AssemblyInfo.cs b/Snake/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5e7832f
--- /dev/null
+++ b/Snake/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Snake")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Docobo")]
+[assembly: AssemblyProduct("Snake")]
+[assembly: AssemblyCopyright("Copyright © Docobo 2007")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a65d79de-9fdb-4e50-aa31-5aff8c5f8744")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Snake/Snake.csproj b/Snake/Snake.csproj
new file mode 100644
index 0000000..473c4d1
--- /dev/null
+++ b/Snake/Snake.csproj
@@ -0,0 +1,108 @@
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {C26A3309-7A61-40B6-9998-69B78CF226C1}
+ Exe
+ Properties
+ Snake
+ Snake
+
+
+
+
+ 2.0
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ 512
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {43619745-0A80-499E-907C-E733FF3DA2BE}
+ CustomDevice
+
+
+
+
+ False
+ .NET Framework Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+ copy $(TargetPath) $(SolutionDir)\Builds\$(ConfigurationName)\
+
+
\ No newline at end of file
diff --git a/Snake/SnakePit.cs b/Snake/SnakePit.cs
new file mode 100644
index 0000000..b643c3c
--- /dev/null
+++ b/Snake/SnakePit.cs
@@ -0,0 +1,266 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using CustomDevice;
+using System.Drawing.Drawing2D;
+
+namespace Snake {
+ class SnakePit {
+
+ private const int cellSize = 8;
+ private const int scoreBoardHeight = 48;
+
+ private Graphics screen;
+ private int cellOfsX, cellOfsY;
+ private int numCellsX, numCellsY;
+ private Random rnd;
+ private Point[] food;
+ private List snakes = new List();
+ private int score, level;
+ private List obstacles = new List();
+
+ public SnakePit() {
+ this.screen = DeviceGraphics.GetScreen();
+ this.screen.Clear(Color.White);
+ this.numCellsX = (DeviceGraphics.ScreenXSize / cellSize) - 2;
+ this.numCellsY = ((DeviceGraphics.ScreenYSize - scoreBoardHeight) / cellSize) - 2;
+ this.cellOfsX = cellSize;
+ this.cellOfsY = cellSize;
+ this.rnd = new Random();
+ this.food = null;
+ this.score = 0;
+ this.level = 1;
+
+ using (Brush brush = new HatchBrush(HatchStyle.DiagonalCross, Color.Black, Color.White)) {
+ this.screen.FillRectangle(brush, 0, 0, DeviceGraphics.ScreenXSize, cellSize);
+ this.screen.FillRectangle(brush, 0, cellSize, cellSize, this.numCellsY * cellSize);
+ this.screen.FillRectangle(brush, (1 + this.numCellsX) * cellSize, cellSize, cellSize, this.numCellsY * cellSize);
+ this.screen.FillRectangle(brush, 0, (1 + this.numCellsY) * cellSize, DeviceGraphics.ScreenXSize, cellSize);
+ }
+ this.screen.DrawRectangle(Pens.Black, cellSize - 1, cellSize - 1,
+ this.numCellsX * cellSize + 1, this.numCellsY * cellSize + 1);
+
+ using (Font f = new Font("tahoma", 15)) {
+ using (StringFormat sf = new StringFormat()) {
+ sf.Alignment = StringAlignment.Center;
+ sf.LineAlignment = StringAlignment.Center;
+ this.screen.DrawString("<", f, Brushes.Black, new RectangleF(0, 220, 64, 20), sf);
+ this.screen.DrawString("v", f, Brushes.Black, new RectangleF(64, 220, 64, 20), sf);
+ this.screen.DrawString("^", f, Brushes.Black, new RectangleF(128, 220, 64, 20), sf);
+ this.screen.DrawString(">", f, Brushes.Black, new RectangleF(192, 220, 64, 20), sf);
+ }
+ }
+
+ this.ShowScore();
+ }
+
+ private void FillCell(Point cell, Color col) {
+ using (Brush brush = new SolidBrush(col)) {
+ screen.FillRectangle(brush,
+ this.cellOfsX + cell.X * cellSize, this.cellOfsY + cell.Y * cellSize, cellSize, cellSize);
+ }
+ }
+
+ public void FillAndOutlineCells(IEnumerable points, Color fillCol, Color outlineCol) {
+ using (Brush brush = new SolidBrush(fillCol)) {
+ this.FillAndOutlineCells(points, brush, outlineCol);
+ }
+ }
+
+ public void FillAndOutlineCells(IEnumerable points, Brush fillBrush, Color outlineCol) {
+ int minX = int.MaxValue, maxX = int.MinValue;
+ int minY = int.MaxValue, maxY = int.MinValue;
+ foreach (Point p in points) {
+ minX = Math.Min(minX, p.X);
+ maxX = Math.Max(maxX, p.X);
+ minY = Math.Min(minY, p.Y);
+ maxY = Math.Max(maxY, p.Y);
+ }
+ int x = this.cellOfsX + minX * cellSize;
+ int y = this.cellOfsY + minY * cellSize;
+ int width = (maxX - minX + 1) * cellSize;
+ int height = (maxY - minY + 1) * cellSize;
+ this.screen.FillRectangle(fillBrush, x, y, width, height);
+ using (Pen pen = new Pen(outlineCol)) {
+ this.screen.DrawRectangle(pen, x, y, width - 1, height - 1);
+ }
+ }
+
+ public void AddSnake(ASnake snake) {
+ this.snakes.Add(snake);
+ }
+
+ public Point Centre {
+ get {
+ return new Point(numCellsX >> 1, numCellsY >> 1);
+ }
+ }
+
+ public Size Size {
+ get {
+ return new Size(numCellsX, numCellsY);
+ }
+ }
+
+ public void SetCell(Point cell, Color col) {
+ this.FillCell(cell, col);
+ }
+
+ public void ClearCell(Point cell) {
+ this.FillCell(cell, Color.White);
+ }
+
+ public bool IsCrashObstacle(Point cell) {
+ foreach (Point[] obs in this.obstacles) {
+ foreach (Point pt in obs) {
+ if (pt == cell) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public CrashType IsCrash(Point cell) {
+ if (cell.X < 0 || cell.X >= this.numCellsX || cell.Y < 0 || cell.Y >= this.numCellsY) {
+ return CrashType.Wall;
+ }
+ if (this.IsCrashObstacle(cell)) {
+ return CrashType.Wall;
+ }
+ if (this.food != null) {
+ for (int i = 0; i < this.food.Length; i++) {
+ if (this.food[i] == cell) {
+ return CrashType.Food;
+ }
+ }
+ }
+ return CrashType.None;
+ }
+
+ public void CreateFood(bool canMoveFood) {
+ if (this.food != null && !canMoveFood) {
+ // Don't move the food
+ return;
+ }
+ this.RemoveFood();
+ Point[] newFood;
+ for (; ; ) {
+ int x = this.rnd.Next(this.numCellsX - 1);
+ int y = this.rnd.Next(this.numCellsY - 1);
+ newFood = new Point[4];
+ newFood[0] = new Point(x, y);
+ newFood[1] = new Point(x + 1, y);
+ newFood[2] = new Point(x, y + 1);
+ newFood[3] = new Point(x + 1, y + 1);
+ bool ok = true;
+ foreach (ASnake snake in this.snakes) {
+ if (snake.DoesIntersect(newFood)) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ foreach (Point pt in newFood) {
+ if (IsCrashObstacle(pt)) {
+ ok = false;
+ break;
+ }
+ }
+ }
+ if (ok) {
+ break;
+ }
+ }
+ this.food = newFood;
+ this.FillAndOutlineCells(this.food, Color.Gray, Color.Black);
+ }
+
+ public void RemoveFood() {
+ if (this.food == null) {
+ return;
+ }
+ for (int i = 0; i < this.food.Length; i++) {
+ this.ClearCell(this.food[i]);
+ }
+ this.food = null;
+ }
+
+ public bool EatFood() {
+ this.RemoveFood();
+ this.score++;
+ bool ret = false;
+ if (this.score >= this.level * 4) {
+ this.level++;
+ ret = true;
+ }
+ this.ShowScore();
+ return ret;
+ }
+
+ public void Msg(string msg) {
+ using (Font f = new Font("tahoma", 40)) {
+ this.screen.DrawString(msg, f, Brushes.Black, 30, 80);
+ }
+ }
+
+ public void ShowScore() {
+ this.screen.FillRectangle(Brushes.White, 0,
+ DeviceGraphics.ScreenYSize - scoreBoardHeight, DeviceGraphics.ScreenXSize, scoreBoardHeight - 20);
+ using (Font f = new Font("tahoma", 15)) {
+ string s = string.Format("Level: {0}", this.level);
+ this.screen.DrawString(s, f, Brushes.Black, 0, DeviceGraphics.ScreenYSize - scoreBoardHeight);
+ s = string.Format("Score: {0}", this.score);
+ this.screen.DrawString(s, f, Brushes.Black, DeviceGraphics.ScreenXSize >> 1, DeviceGraphics.ScreenYSize - scoreBoardHeight);
+ }
+ }
+
+ public int Level {
+ get {
+ return this.level;
+ }
+ }
+
+ private int Dist(Point a, Point b) {
+ int dx = a.X - b.Y;
+ int dy = a.Y - b.Y;
+ return Math.Max(Math.Abs(dx), Math.Abs(dy));
+ }
+
+ public void AddObsticle() {
+ Point[] obs;
+ for (; ; ) {
+ int x = this.rnd.Next(this.numCellsX - 1);
+ int y = this.rnd.Next(this.numCellsY - 1);
+ obs = new Point[4];
+ obs[0] = new Point(x, y);
+ obs[1] = new Point(x + 1, y);
+ obs[2] = new Point(x, y + 1);
+ obs[3] = new Point(x + 1, y + 1);
+ bool ok = true;
+ foreach (ASnake snake in this.snakes) {
+ if (snake.DoesIntersect(obs) || this.Dist(snake.Head, obs[0]) < 10) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ break;
+ }
+ }
+ using (HatchBrush brush = new HatchBrush(HatchStyle.DiagonalCross,Color.Black, Color.White)) {
+ this.FillAndOutlineCells(obs, brush, Color.Black);
+ }
+ this.obstacles.Add(obs);
+ if (this.obstacles.Count > this.Level * 2) {
+ // Remove an obstacle
+ obs = this.obstacles[0];
+ foreach (Point pt in obs) {
+ this.ClearCell(pt);
+ }
+ this.obstacles.RemoveAt(0);
+ }
+ }
+ }
+}