RosettaCodeData/Task/2048/C-sharp/2048.cs

395 lines
10 KiB
C#

using System;
namespace g2048_csharp
{
internal class Tile
{
public Tile()
{
Value = 0;
IsBlocked = false;
}
public int Value { get; set; }
public bool IsBlocked { get; set; }
}
internal enum MoveDirection
{
Up,
Down,
Left,
Right
}
internal class G2048
{
public G2048()
{
_isDone = false;
_isWon = false;
_isMoved = true;
_score = 0;
InitializeBoard();
}
private void InitializeBoard()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
_board[x, y] = new Tile();
}
}
}
private bool _isDone;
private bool _isWon;
private bool _isMoved;
private int _score;
private readonly Tile[,] _board = new Tile[4, 4];
private readonly Random _rand = new Random();
public void Loop()
{
AddTile();
while (true)
{
if (_isMoved)
{
AddTile();
}
DrawBoard();
if (_isDone)
{
break;
}
WaitKey();
}
string endMessage = _isWon ? "You've made it!" : "Game Over!";
Console.WriteLine(endMessage);
}
private void DrawBoard()
{
Console.Clear();
Console.WriteLine("Score: " + _score + "\n");
for (int y = 0; y < 4; y++)
{
Console.WriteLine("+------+------+------+------+");
Console.Write("| ");
for (int x = 0; x < 4; x++)
{
if (_board[x, y].Value == 0)
{
const string empty = " ";
Console.Write(empty.PadRight(4));
}
else
{
Console.Write(_board[x, y].Value.ToString().PadRight(4));
}
Console.Write(" | ");
}
Console.WriteLine();
}
Console.WriteLine("+------+------+------+------+\n\n");
}
private void WaitKey()
{
_isMoved = false;
Console.WriteLine("(W) Up (S) Down (A) Left (D) Right");
char input;
char.TryParse(Console.ReadKey().Key.ToString(), out input);
switch (input)
{
case 'W':
Move(MoveDirection.Up);
break;
case 'A':
Move(MoveDirection.Left);
break;
case 'S':
Move(MoveDirection.Down);
break;
case 'D':
Move(MoveDirection.Right);
break;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
_board[x, y].IsBlocked = false;
}
}
}
private void AddTile()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (_board[x, y].Value != 0) continue;
int a, b;
do
{
a = _rand.Next(0, 4);
b = _rand.Next(0, 4);
} while (_board[a, b].Value != 0);
double r = _rand.NextDouble();
_board[a, b].Value = r > 0.89f ? 4 : 2;
if (CanMove())
{
return;
}
}
}
_isDone = true;
}
private bool CanMove()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (_board[x, y].Value == 0)
{
return true;
}
}
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (TestAdd(x + 1, y, _board[x, y].Value)
|| TestAdd(x - 1, y, _board[x, y].Value)
|| TestAdd(x, y + 1, _board[x, y].Value)
|| TestAdd(x, y - 1, _board[x, y].Value))
{
return true;
}
}
}
return false;
}
private bool TestAdd(int x, int y, int value)
{
if (x < 0 || x > 3 || y < 0 || y > 3)
{
return false;
}
return _board[x, y].Value == value;
}
private void MoveVertically(int x, int y, int d)
{
if (_board[x, y + d].Value != 0
&& _board[x, y + d].Value == _board[x, y].Value
&& !_board[x, y].IsBlocked
&& !_board[x, y + d].IsBlocked)
{
_board[x, y].Value = 0;
_board[x, y + d].Value *= 2;
_score += _board[x, y + d].Value;
_board[x, y + d].IsBlocked = true;
_isMoved = true;
}
else if (_board[x, y + d].Value == 0
&& _board[x, y].Value != 0)
{
_board[x, y + d].Value = _board[x, y].Value;
_board[x, y].Value = 0;
_isMoved = true;
}
if (d > 0)
{
if (y + d < 3)
{
MoveVertically(x, y + d, 1);
}
}
else
{
if (y + d > 0)
{
MoveVertically(x, y + d, -1);
}
}
}
private void MoveHorizontally(int x, int y, int d)
{
if (_board[x + d, y].Value != 0
&& _board[x + d, y].Value == _board[x, y].Value
&& !_board[x + d, y].IsBlocked
&& !_board[x, y].IsBlocked)
{
_board[x, y].Value = 0;
_board[x + d, y].Value *= 2;
_score += _board[x + d, y].Value;
_board[x + d, y].IsBlocked = true;
_isMoved = true;
}
else if (_board[x + d, y].Value == 0
&& _board[x, y].Value != 0)
{
_board[x + d, y].Value = _board[x, y].Value;
_board[x, y].Value = 0;
_isMoved = true;
}
if (d > 0)
{
if (x + d < 3)
{
MoveHorizontally(x + d, y, 1);
}
}
else
{
if (x + d > 0)
{
MoveHorizontally(x + d, y, -1);
}
}
}
private void Move(MoveDirection direction)
{
switch (direction)
{
case MoveDirection.Up:
for (int x = 0; x < 4; x++)
{
int y = 1;
while (y < 4)
{
if (_board[x, y].Value != 0)
{
MoveVertically(x, y, -1);
}
y++;
}
}
break;
case MoveDirection.Down:
for (int x = 0; x < 4; x++)
{
int y = 2;
while (y >= 0)
{
if (_board[x, y].Value != 0)
{
MoveVertically(x, y, 1);
}
y--;
}
}
break;
case MoveDirection.Left:
for (int y = 0; y < 4; y++)
{
int x = 1;
while (x < 4)
{
if (_board[x, y].Value != 0)
{
MoveHorizontally(x, y, -1);
}
x++;
}
}
break;
case MoveDirection.Right:
for (int y = 0; y < 4; y++)
{
int x = 2;
while (x >= 0)
{
if (_board[x, y].Value != 0)
{
MoveHorizontally(x, y, 1);
}
x--;
}
}
break;
}
}
}
internal static class Program
{
public static void Main(string[] args)
{
RunGame();
}
private static void RunGame()
{
G2048 game = new G2048();
game.Loop();
CheckRestart();
}
private static void CheckRestart()
{
Console.WriteLine("(N) New game (P) Exit");
while (true)
{
char input;
char.TryParse(Console.ReadKey().Key.ToString(), out input);
switch (input)
{
case 'N':
RunGame();
break;
case 'P':
return;
default:
ClearLastLine();
break;
}
}
}
private static void ClearLastLine()
{
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write(new string(' ', Console.BufferWidth));
Console.SetCursorPosition(0, Console.CursorTop - 1);
}
}
}