init commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Snake
|
||||
Snake
|
||||
CLI snake game. CSIS 2410 project A05.
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Snake", "Snake\Snake.csproj", "{4A6995A3-4AC4-4954-A7CA-904A77D5AC85}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4A6995A3-4AC4-4954-A7CA-904A77D5AC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A6995A3-4AC4-4954-A7CA-904A77D5AC85}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A6995A3-4AC4-4954-A7CA-904A77D5AC85}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A6995A3-4AC4-4954-A7CA-904A77D5AC85}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,64 @@
|
||||
namespace Snake
|
||||
{
|
||||
///
|
||||
/// <summary>Represents a Console position in Left and Top coordinates, AKA (x, y).</summary>
|
||||
///
|
||||
/// <author>Josh Ashton</author>
|
||||
///
|
||||
public class Position
|
||||
{
|
||||
public int X1;
|
||||
public int X2;
|
||||
public int Y { get; }
|
||||
|
||||
private const ConsoleColor D_GREEN = ConsoleColor.DarkGreen;
|
||||
private const ConsoleColor BLACK = ConsoleColor.Black;
|
||||
private const ConsoleColor GREEN = ConsoleColor.Green;
|
||||
private const ConsoleColor WHITE = ConsoleColor.White;
|
||||
private const ConsoleColor YELLOW = ConsoleColor.Yellow;
|
||||
|
||||
|
||||
public bool SnakeKiller { get; }
|
||||
public bool Snake { get; set; }
|
||||
public Position Next { get; set; }
|
||||
public Position Prev { get; set; }
|
||||
|
||||
public Position(int x1, int x2, int y)
|
||||
{
|
||||
X1 = x1;
|
||||
X2 = x2;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public Position(int x1, int x2, int y, bool snakeKiller)
|
||||
{
|
||||
X1 = x1;
|
||||
X2 = x2;
|
||||
Y = y;
|
||||
SnakeKiller = snakeKiller;
|
||||
}
|
||||
|
||||
public void Draw(bool isHead) {
|
||||
if(SnakeKiller)
|
||||
{
|
||||
Console.BackgroundColor = D_GREEN;
|
||||
Console.Write(" ");
|
||||
Console.BackgroundColor = BLACK;
|
||||
} else if (Snake)
|
||||
{
|
||||
Console.BackgroundColor = WHITE;
|
||||
Console.Write(" ");
|
||||
Console.BackgroundColor = BLACK;
|
||||
} else if (isHead)
|
||||
{
|
||||
Console.BackgroundColor = GREEN;
|
||||
Console.Write(" ");
|
||||
Console.BackgroundColor = BLACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
using System.ComponentModel;
|
||||
using System.Timers;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace Snake;
|
||||
|
||||
public class Program
|
||||
{
|
||||
int leftMargin = 9;
|
||||
int topMargin = 0;
|
||||
private int height = 19;
|
||||
private int width = 31;
|
||||
private double difficulty;
|
||||
private int time;
|
||||
private Position[][] grid;
|
||||
private Position bottom { get; set; }
|
||||
private Position top { get; set; }
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Program p = new Program();
|
||||
p.bottom = new Position(p.leftMargin, p.leftMargin + 1, p.topMargin + p.height);
|
||||
p.top = new Position(p.leftMargin, p.leftMargin + 1, p.topMargin);
|
||||
p.time = 0;
|
||||
p.PrintIntro();
|
||||
p.MenuInput();
|
||||
}
|
||||
|
||||
void DrawSnake()
|
||||
{
|
||||
Snake s = new Snake(grid, 100);
|
||||
Timer t = new Timer(100);
|
||||
t.Elapsed += TimerAction;
|
||||
t.Enabled = true;
|
||||
if (!s.Move())
|
||||
{
|
||||
DisplayGameOver();
|
||||
Thread.Sleep(3000);
|
||||
PrintIntro();
|
||||
MenuInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayNextLevel();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerAction(object? sender, ElapsedEventArgs elapsedEventArgs)
|
||||
{
|
||||
time++;
|
||||
}
|
||||
|
||||
void PrintIntro()
|
||||
{
|
||||
string[] s =
|
||||
{
|
||||
"╔════════════════════════════════════════════════════════════╗",
|
||||
" /^\\/^\\ ",
|
||||
" _|__| O| ",
|
||||
" \\/ /~ \\_/ \\ ",
|
||||
" \\____|__________/ \\ ",
|
||||
" \\_______ \\ ",
|
||||
" '\\ \\ \\ ",
|
||||
" | | \\ ",
|
||||
" / / \\ ",
|
||||
" / / \\\\ ",
|
||||
" / / \\\\ ",
|
||||
" / / \\ \\\\ ",
|
||||
" / / _----_ \\ \\\\ ",
|
||||
" / / _-~ ~-_ | | ",
|
||||
" ( ( _-~ _--_ ~-_ _/ | ",
|
||||
" \\ ~-____-~ _-~ ~-_ ~-_-~ / ",
|
||||
" ~-_ _-~ ~-_ _-~ ",
|
||||
" ~--______-~ ~-___-~ ",
|
||||
"╚════════════════════════════════════════════════════════════╝"
|
||||
};
|
||||
PrintConsole(s);
|
||||
}
|
||||
|
||||
// TODO: Can no longer press q or r after starting the game.
|
||||
void MenuInput()
|
||||
{
|
||||
Console.SetCursorPosition(bottom.X1, bottom.Y);
|
||||
Console.Write("Enter p to play, q to quit, r for rules: ");
|
||||
char input = Console.ReadKey().KeyChar;
|
||||
Console.SetCursorPosition(bottom.X1, bottom.Y);
|
||||
while (input != 'q')
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case 'p':
|
||||
Console.SetCursorPosition(bottom.X1, bottom.Y);
|
||||
Console.Write("Enter e for easy, m for medium, and h for hard: ");
|
||||
char level = Console.ReadKey().KeyChar;
|
||||
grid = new Position[height][];
|
||||
switch (level)
|
||||
{
|
||||
case 'e':
|
||||
grid = GenerateGameBoard(grid, 0.03);
|
||||
break;
|
||||
case 'm':
|
||||
grid = GenerateGameBoard(grid, 0.06);
|
||||
break;
|
||||
case 'h':
|
||||
grid = GenerateGameBoard(grid, 0.1);
|
||||
break;
|
||||
}
|
||||
DrawGameBoard(grid);
|
||||
DrawSnake();
|
||||
break;
|
||||
case 'q':
|
||||
Environment.Exit(0);
|
||||
break;
|
||||
case 'r':
|
||||
DisplayRules();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawGameBoard(Position[][] grid)
|
||||
{
|
||||
for (int i = 0; i < grid.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < grid[i].Length; j++)
|
||||
{
|
||||
Console.SetCursorPosition(grid[i][j].X1, grid[i][j].Y);
|
||||
grid[i][j].Draw(false);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
time = 0;
|
||||
}
|
||||
|
||||
void DisplayRules()
|
||||
{
|
||||
Position[][] grid = new Position[height][];
|
||||
grid = GenerateGameBoard(grid, 0.03);
|
||||
DrawGameBoard(grid);
|
||||
|
||||
string rules = (
|
||||
"RULES:\n" +
|
||||
" - Do not let the snake head touch walls or obstacles.\n" +
|
||||
" - Use the arrow keys to control the snake."
|
||||
//" - Collect all points in a level to move to the next level.",
|
||||
//" - Levels increase difficulty."
|
||||
);
|
||||
PrintConsole(rules);
|
||||
}
|
||||
|
||||
// TODO: ASCII art for game over screen
|
||||
void DisplayGameOver()
|
||||
{
|
||||
string[] s =
|
||||
{
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣤⠀⠀⠀⢀⣴⣿⡶⠀⣾⣿⣿⡿⠟⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣄⣀⠀⠀⠀⠀⣶⣶⣦⠀⠀⠀⠀⣼⣿⣿⡇⠀⣠⣿⣿⣿⠇⣸⣿⣿⣧⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⡿⠿⠿⠿⠇⠀⠀⣸⣿⣿⣿⡆⠀⠀⢰⣿⣿⣿⣷⣼⣿⣿⣿⡿⢀⣿⣿⡿⠟⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⢠⣿⣿⣹⣿⣿⣿⣿⣿⣿⡏⢻⣿⣿⢿⣿⣿⠃⣼⣿⣯⣤⣴⣶⣿⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⠏⠀⣀⣠⣤⣶⣾⣷⠄⣰⣿⣿⡿⠿⠻⣿⣯⣸⣿⡿⠀⠀⠀⠁⣾⣿⡏⢠⣿⣿⠿⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠲⢿⣿⣿⣿⣿⡿⠋⢰⣿⣿⠋⠀⠀⠀⢻⣿⣿⣿⠇⠀⠀⠀⠀⠙⠛⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⢿⣷⣶⣿⣿⠿⠋⠀⠀⠈⠙⠃⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣴⣶⣦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡀⠀⠀⠀⠀⠀⠀⠀⣠⡇⢰⣶⣶⣾⡿⠷⣿⣿⣿⡟⠛⣉⣿⣿⣿⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣿⣿⡎⣿⣿⣦⠀⠀⠀⢀⣤⣾⠟⢀⣿⣿⡟⣁⠀⠀⣸⣿⣿⣤⣾⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⡿⠛⠉⢿⣦⠘⣿⣿⡆⠀⢠⣾⣿⠋⠀⣼⣿⣿⣿⠿⠷⢠⣿⣿⣿⠿⢻⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⠋⠀⠀⠀⢸⣿⣇⢹⣿⣷⣰⣿⣿⠃⠀⢠⣿⣿⢃⣀⣤⣤⣾⣿⡟⠀⠀⠀⢻⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀⠀⢀⣴⣿⣿⡟⠀⣿⣿⣿⣿⠃⠀⠀⣾⣿⣿⡿⠿⠛⢛⣿⡟⠀⠀⠀⠀⠀⠻⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣶⣾⣿⣿⣿⠟⠁⠀⠸⢿⣿⠇⠀⠀⠀⠛⠛⠁⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀",
|
||||
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"
|
||||
};
|
||||
// Prints score and time below ASCII art of same dimension as the snake drawing above
|
||||
PrintConsole($"Score: {time * 100} | Time: {time / 10} seconds ");
|
||||
PrintConsole(s);
|
||||
time = 0;
|
||||
}
|
||||
|
||||
void DisplayNextLevel()
|
||||
{
|
||||
grid = GenerateGameBoard(grid, difficulty * (1 + difficulty));
|
||||
DrawGameBoard(grid);
|
||||
DrawSnake();
|
||||
}
|
||||
|
||||
void PrintConsole(string message)
|
||||
{
|
||||
Console.SetCursorPosition(bottom.X1, bottom.Y + 1);
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
void PrintConsole(string[] s)
|
||||
{
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
Console.SetCursorPosition(top.X1, top.Y + i);
|
||||
Console.WriteLine(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private Position[][] GenerateGameBoard(Position[][] grid, double chance)
|
||||
{
|
||||
int xCounter = 0;
|
||||
for (int y = 0; y < grid.Length; y++)
|
||||
{
|
||||
grid[y] = new Position[width];
|
||||
for (int x = 0; x < grid[y].Length; x++)
|
||||
{
|
||||
if (x == 0 || x == grid[y].Length - 1 || y == 0 || y == grid.Length - 1 ||
|
||||
new Random().NextDouble() <= chance)
|
||||
{
|
||||
grid[y][x] = new Position(xCounter++ + leftMargin, xCounter++ + leftMargin, y + topMargin, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid[y][x] = new Position(xCounter++ + leftMargin, xCounter++ + leftMargin, y + topMargin, false);
|
||||
}
|
||||
}
|
||||
xCounter = 0;
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
namespace Snake
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the in-game snake, which traverses the 2D array of Positions.
|
||||
/// </summary>
|
||||
public class Snake
|
||||
{
|
||||
private Queue<Position> body;
|
||||
private int n;
|
||||
private int capacity;
|
||||
private Position[][] grid;
|
||||
private bool Collided;
|
||||
|
||||
public Snake(Position[][] grid, int capacity)
|
||||
{
|
||||
this.grid = grid;
|
||||
this.capacity = capacity;
|
||||
n = 0;
|
||||
Collided = false;
|
||||
body = new Queue<Position>();
|
||||
}
|
||||
|
||||
public bool Move()
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Black;
|
||||
int x = 1;
|
||||
int y = grid.Length / 2;
|
||||
int direction = 0;
|
||||
|
||||
while (!Collided && x < grid[0].Length - 1 && y < grid.Length - 1 && x > 0 && y > 0)
|
||||
{
|
||||
if (Console.KeyAvailable)
|
||||
{
|
||||
char d = Console.ReadKey().KeyChar;
|
||||
switch (d)
|
||||
{
|
||||
case 'w':
|
||||
direction = 1;
|
||||
break;
|
||||
case 'a':
|
||||
direction = 2;
|
||||
break;
|
||||
case 's':
|
||||
direction = 3;
|
||||
break;
|
||||
case 'd':
|
||||
direction = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Console.SetCursorPosition(grid[y][x].X1, grid[y][x].Y);
|
||||
grid[y][x].Draw(false);
|
||||
switch (direction)
|
||||
{
|
||||
case 0: // move right
|
||||
x++;
|
||||
break;
|
||||
case 1: // move up
|
||||
y--;
|
||||
break;
|
||||
case 2: // move left
|
||||
x--;
|
||||
break;
|
||||
case 3: // move down
|
||||
y++;
|
||||
break;
|
||||
}
|
||||
if (grid[y][x].SnakeKiller)
|
||||
{
|
||||
Console.SetCursorPosition(grid[0][0].X1, grid[grid.Length - 1][0].Y + 1);
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
return false;
|
||||
}
|
||||
body.Enqueue(grid[y][x]);
|
||||
body.Dequeue();
|
||||
grid[y][x].Snake = true;
|
||||
Thread.Sleep(150);
|
||||
}
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user