diff --git a/README.md b/README.md index ea052e9..1a50fd0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Week 2 Blazor - [x] https://dotnet.microsoft.com/learn/aspnet/blazor-tutorial/intro -- [ ] https://exceptionnotfound.net/tetris-in-blazor-webassembly/ +- [x] https://exceptionnotfound.net/tetris-in-blazor-webassembly/ - [ ] https://www.claudiobernasconi.ch/2021/04/23/building-a-dashboard-blazor/ - [ ] https://code-maze.com/download-files-from-azure-with-net-core-web-api-and-blazor-webassembly/ - [ ] https://code-maze.com/authentication-in-blazor-webassembly-hosted-applications/ diff --git a/Test b/Test new file mode 100644 index 0000000..e69de29 diff --git a/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.GeneratedMSBuildEditorConfig.editorconfig b/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.GeneratedMSBuildEditorConfig.editorconfig index de656bc..20996eb 100644 --- a/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = NumbersInCsharp -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M2-numbers-in-csharp-local/numbers-quickstart/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M2-numbers-in-csharp-local\numbers-quickstart\ diff --git a/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.assets.cache b/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.assets.cache index 913b0c5..12b4c7d 100644 Binary files a/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.assets.cache and b/W1-M2-numbers-in-csharp-local/numbers-quickstart/obj/Debug/net6.0/NumbersInCsharp.assets.cache differ diff --git a/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.GeneratedMSBuildEditorConfig.editorconfig b/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.GeneratedMSBuildEditorConfig.editorconfig index aa13a44..b920323 100644 --- a/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = BranchesAndLoops -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M3-branches-and-loops-local/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M3-branches-and-loops-local\ diff --git a/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.assets.cache b/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.assets.cache index 5417aaf..7c26aaf 100644 Binary files a/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.assets.cache and b/W1-M3-branches-and-loops-local/obj/Debug/net6.0/BranchesAndLoops.assets.cache differ diff --git a/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.GeneratedMSBuildEditorConfig.editorconfig b/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.GeneratedMSBuildEditorConfig.editorconfig index b2fe0c5..79dd8b2 100644 --- a/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = W1_M4_list_collections -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M4-list-collections/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M4-list-collections\ diff --git a/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.assets.cache b/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.assets.cache index 724e1e5..749db54 100644 Binary files a/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.assets.cache and b/W1-M4-list-collections/obj/Debug/net6.0/W1-M4-list-collections.assets.cache differ diff --git a/W1-M5-classes-and-objects/obj/Debug/net6.0/W1-M5-classes-and-objects.GeneratedMSBuildEditorConfig.editorconfig b/W1-M5-classes-and-objects/obj/Debug/net6.0/W1-M5-classes-and-objects.GeneratedMSBuildEditorConfig.editorconfig index b6a926f..1988bf8 100644 --- a/W1-M5-classes-and-objects/obj/Debug/net6.0/W1-M5-classes-and-objects.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M5-classes-and-objects/obj/Debug/net6.0/W1-M5-classes-and-objects.GeneratedMSBuildEditorConfig.editorconfig @@ -7,8 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = W1_M5_classes_and_objects -<<<<<<< HEAD -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M5-classes-and-objects/ -======= -build_property.ProjectDir = C:\s\najodev\JuniorLearning\W1-M5-classes-and-objects\ ->>>>>>> main +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M5-classes-and-objects\ diff --git a/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.GeneratedMSBuildEditorConfig.editorconfig b/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.GeneratedMSBuildEditorConfig.editorconfig index f2cae64..609e6c5 100644 --- a/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = W1_M5_classes_and_objects -build_property.ProjectDir = /home/najo/files/JuniorLearning/W1-M6-object-oriented/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M6-object-oriented\ diff --git a/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.csproj.AssemblyReference.cache b/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.csproj.AssemblyReference.cache index c2cb925..66b90b7 100644 Binary files a/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.csproj.AssemblyReference.cache and b/W1-M6-object-oriented/obj/Debug/net6.0/W1-M6-object-orientated.csproj.AssemblyReference.cache differ diff --git a/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.GeneratedMSBuildEditorConfig.editorconfig b/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.GeneratedMSBuildEditorConfig.editorconfig index af08f83..78daf93 100644 --- a/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = W1_M7_inheritance -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M7-inheritance/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M7-inheritance\ diff --git a/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.assets.cache b/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.assets.cache index 561bf58..0d7fa42 100644 Binary files a/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.assets.cache and b/W1-M7-inheritance/obj/Debug/net6.0/W1-M7-inheritance.assets.cache differ diff --git a/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.GeneratedMSBuildEditorConfig.editorconfig b/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.GeneratedMSBuildEditorConfig.editorconfig index 509a769..65bd027 100644 --- a/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.GeneratedMSBuildEditorConfig.editorconfig +++ b/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.GeneratedMSBuildEditorConfig.editorconfig @@ -7,4 +7,4 @@ build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = W1_M9_console_app -build_property.ProjectDir = /home/najo/files/JuniorLearning_backup/W1-M9-console-app/ +build_property.ProjectDir = C:\Users\NashBarden\Source\Repos\JuniorLearning\W1-M9-console-app\ diff --git a/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.assets.cache b/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.assets.cache index 40cfa37..e670250 100644 Binary files a/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.assets.cache and b/W1-M9-console-app/obj/Debug/net6.0/W1-M9-console-app.assets.cache differ diff --git a/W2-M2-Tetris b/W2-M2-Tetris new file mode 160000 index 0000000..42f48b3 --- /dev/null +++ b/W2-M2-Tetris @@ -0,0 +1 @@ +Subproject commit 42f48b31a1091d0582f9669b45d2dc26601bd1ac diff --git a/W2-M2-Tetris-new/App.razor b/W2-M2-Tetris-new/App.razor new file mode 100644 index 0000000..af20633 --- /dev/null +++ b/W2-M2-Tetris-new/App.razor @@ -0,0 +1,11 @@ + + + + + + +

Page not found

+

Sorry, there's nothing at this address.

+
+
+
\ No newline at end of file diff --git a/W2-M2-Tetris-new/Models/Tetris/Cell.cs b/W2-M2-Tetris-new/Models/Tetris/Cell.cs new file mode 100644 index 0000000..34bc1e1 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Cell.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris +{ + public class Cell + { + public int Row { get; set; } + public int Column { get; set; } + public string CssClass { get; set; } + + public Cell(int row, int column) + { + Row = row; + Column = column; + } + + public Cell(int row, int column, string css) + { + Row = row; + Column = column; + CssClass = css; + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/CellCollection.cs b/W2-M2-Tetris-new/Models/Tetris/CellCollection.cs new file mode 100644 index 0000000..fc8a0fc --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/CellCollection.cs @@ -0,0 +1,186 @@ +using System.Collections.Generic; +using System.Linq; + +namespace W1_M2_Tetris.Models.Tetris +{ + public class CellCollection + { + private readonly List _cells = new List(); + + /// + /// Returns all currently-occupied coordinates. + /// + /// + public List GetAll() + { + return _cells; + } + + /// + /// Returns all occupied cell in a given row. + /// + /// + /// + public List GetAllInRow(int row) + { + return _cells.Where(x => x.Row == row).ToList(); + } + + /// + /// Adds a new cell + /// + /// + /// + public void Add(int row, int column) + { + _cells.Add(new Cell(row, column)); + } + + /// + /// Adds several new Cells and gives them each the specified CSS class. + /// + /// + /// + public void AddMany(List cells, string cssClass) + { + foreach (var cell in cells) + { + _cells.Add(new Cell(cell.Row, cell.Column, cssClass)); + } + } + + /// + /// Returns true if the cell is occupied. + /// + /// + /// + /// + public bool Contains(int row, int column) + { + return _cells.Any(c => c.Row == row && c.Column == column); + } + + /// + /// Returns true if there are any occupied cells in the given column. + /// + /// + /// + public bool HasColumn(int column) + { + return _cells.Any(c => c.Column == column); + } + + /// + /// Gets the lowest (lowest Row value) cell in the collection. + /// + /// + public List GetLowest() + { + List cells = new List(); + foreach (var cell in _cells) + { + if (!Contains(cell.Row - 1, cell.Column)) + { + cells.Add(cell); + } + } + + return cells; + } + + /// + /// Gets the rightmost (highest Column value) cell in the collection. + /// + /// + public List GetRightmost() + { + List cells = new List(); + foreach (var cell in _cells) + { + if (!Contains(cell.Row, cell.Column + 1)) + { + cells.Add(cell); + } + } + + return cells; + } + + /// + /// Gets the leftmost (lowest Column value) cell in the collection. + /// + /// + public List GetLeftmost() + { + List cells = new List(); + foreach (var cell in _cells) + { + if (!Contains(cell.Row, cell.Column - 1)) + { + cells.Add(cell); + } + } + + return cells; + } + + /// + /// Returns true if any cell in the collection is in the specified row. + /// + /// + /// + public bool HasRow(int row) + { + return _cells.Any(c => c.Row == row); + } + + /// + /// Gets the CSS class of an individual cell. + /// + /// + /// + /// + public string GetCssClass(int row, int column) + { + var matching = _cells.FirstOrDefault(x => x.Row == row && x.Column == column); + + if (matching != null) + return matching.CssClass; + + return ""; + } + + /// + /// Sets the CSS class to each cell in an entire row. + /// + /// + /// + public void SetCssClass(int row, string cssClass) + { + _cells.Where(x => x.Row == row).ToList().ForEach(x => x.CssClass = cssClass); + } + + /// + /// Moves all "higher" cells down to fill in the specified completed rows. + /// + /// + public void CollapseRows(List rows) + { + var selectedCells = _cells.Where(x => rows.Contains(x.Row)); + + List toRemove = new List(); + foreach (var cell in selectedCells) + { + toRemove.Add(cell); + } + + _cells.RemoveAll(x => toRemove.Contains(x)); + + foreach (var cell in _cells) + { + int numberOfLessRows = rows.Where(x => x <= cell.Row).Count(); + cell.Row -= numberOfLessRows; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Enums/GameState.cs b/W2-M2-Tetris-new/Models/Tetris/Enums/GameState.cs new file mode 100644 index 0000000..bcab6d1 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Enums/GameState.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Enums +{ + /// + /// Represents the current state of the Tetris game + /// + public enum GameState + { + NotStarted, + Playing, //Game playing normally + GameOver + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoOrientation.cs b/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoOrientation.cs new file mode 100644 index 0000000..e5f8d54 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoOrientation.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Enums +{ + public enum TetrominoOrientation + { + UpDown, + LeftRight, + DownUp, + RightLeft + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoStyle.cs b/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoStyle.cs new file mode 100644 index 0000000..33386de --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Enums/TetrominoStyle.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Enums +{ + public enum TetrominoStyle + { + Straight = 1, + Block = 2, + TShaped = 3, + LeftZigZag = 4, + RightZigZag = 5, + LShaped = 6, + ReverseLShaped = 7 + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Grid.cs b/W2-M2-Tetris-new/Models/Tetris/Grid.cs new file mode 100644 index 0000000..ceabfbc --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Grid.cs @@ -0,0 +1,26 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris +{ + public class Grid + { + public int Width { get; } = 10; + public int Height { get; } = 20; + public CellCollection Cells { get; set; } = new CellCollection(); + + public GameState State { get; set; } = GameState.NotStarted; + + public bool IsStarted + { + get + { + return State == GameState.Playing + || State == GameState.GameOver; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/TetrominoGenerator.cs b/W2-M2-Tetris-new/Models/Tetris/TetrominoGenerator.cs new file mode 100644 index 0000000..bc62a38 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/TetrominoGenerator.cs @@ -0,0 +1,41 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using W1_M2_Tetris.Models.Tetris.Tetrominos; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris +{ + public class TetrominoGenerator + { + public TetrominoStyle Next(params TetrominoStyle[] unusableStyles) + { + Random rand = new Random(DateTime.Now.Millisecond); + + //Randomly generate one of the eight possible tetrominos + var style = (TetrominoStyle)rand.Next(1, 8); + + //Re-generate the new tetromino until it is of a style that is not one of the upcoming styles. + while (unusableStyles.Contains(style)) + style = (TetrominoStyle)rand.Next(1, 8); + + return style; + } + + public Tetromino CreateFromStyle(TetrominoStyle style, Grid grid) + { + return style switch + { + TetrominoStyle.Block => new Block(grid), + TetrominoStyle.Straight => new Straight(grid), + TetrominoStyle.TShaped => new TShaped(grid), + TetrominoStyle.LeftZigZag => new LeftZigZag(grid), + TetrominoStyle.RightZigZag => new RightZigZag(grid), + TetrominoStyle.LShaped => new LShaped(grid), + TetrominoStyle.ReverseLShaped => new ReverseLShaped(grid), + _ => new Block(grid), + }; + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Block.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Block.cs new file mode 100644 index 0000000..0aba3a6 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Block.cs @@ -0,0 +1,35 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A square or "block" tetromino. Block tetrominos do not rotate. + /// X X + /// X X + /// + public class Block : Tetromino + { + public Block(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.Block; + + public override string CssClass => "tetris-yellow-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn + 1); + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LShaped.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LShaped.cs new file mode 100644 index 0000000..ecaf518 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LShaped.cs @@ -0,0 +1,60 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// An "L-shaped" tetromino + /// X X X X X X X + /// X X X X X X + /// X X X + /// + public class LShaped : Tetromino + { + public LShaped(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.LShaped; + + public override string CssClass => "tetris-orange-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + switch(Orientation) + { + case TetrominoOrientation.LeftRight: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn - 2); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + break; + + case TetrominoOrientation.DownUp: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 2, CenterPieceColumn); + break; + + case TetrominoOrientation.RightLeft: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 2); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + break; + + case TetrominoOrientation.UpDown: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 2, CenterPieceColumn); + break; + } + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LeftZigZag.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LeftZigZag.cs new file mode 100644 index 0000000..02f560c --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/LeftZigZag.cs @@ -0,0 +1,60 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A left-zigzag tetromino + /// X X X + /// X X X X + /// X + /// + public class LeftZigZag : Tetromino + { + public LeftZigZag(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.LeftZigZag; + + public override string CssClass => "tetris-red-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + switch (Orientation) + { + case TetrominoOrientation.LeftRight: + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + break; + + case TetrominoOrientation.DownUp: + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow + 1, CenterPieceColumn + 1); + break; + + case TetrominoOrientation.RightLeft: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 1, CenterPieceColumn + 1); + break; + + case TetrominoOrientation.UpDown: + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn - 1); + break; + } + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/ReverseLShaped.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/ReverseLShaped.cs new file mode 100644 index 0000000..4764348 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/ReverseLShaped.cs @@ -0,0 +1,60 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A reverse-L-shaped tetromino, also called a J-shaped tetromino + /// X X X X X X X + /// X X X X X X + /// X X X + /// + public class ReverseLShaped : Tetromino + { + public ReverseLShaped(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.ReverseLShaped; + + public override string CssClass => "tetris-darkblue-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + switch(Orientation) + { + case TetrominoOrientation.LeftRight: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 2); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + break; + + case TetrominoOrientation.DownUp: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 2, CenterPieceColumn); + break; + + case TetrominoOrientation.RightLeft: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn - 2); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + break; + + case TetrominoOrientation.UpDown: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 2, CenterPieceColumn); + break; + } + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/RightZigZag.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/RightZigZag.cs new file mode 100644 index 0000000..07e604e --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/RightZigZag.cs @@ -0,0 +1,60 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A right-zig-zag tetromino + /// X X X + /// X X X X + /// X + /// + public class RightZigZag : Tetromino + { + public RightZigZag(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.RightZigZag; + + public override string CssClass => "tetris-green-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + switch(Orientation) + { + case TetrominoOrientation.LeftRight: + cells.Add(CenterPieceRow, CenterPieceColumn-1 ); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn + 1); + break; + + case TetrominoOrientation.DownUp: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 1, CenterPieceColumn + 1); + break; + + case TetrominoOrientation.RightLeft: + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 1, CenterPieceColumn - 1); + break; + + case TetrominoOrientation.UpDown: + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn - 1); + break; + } + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Straight.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Straight.cs new file mode 100644 index 0000000..b42b1ae --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Straight.cs @@ -0,0 +1,60 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A straight-line tetromino + /// X X X X X + /// X + /// X + /// X + /// + public class Straight : Tetromino + { + public Straight(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.Straight; + + public override string CssClass => "tetris-lightblue-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + if (Orientation == TetrominoOrientation.LeftRight) + { + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn - 2); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + } + else if (Orientation == TetrominoOrientation.DownUp) + { + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 2, CenterPieceColumn); + } + else if(Orientation == TetrominoOrientation.RightLeft) + { + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 2); + } + else //UpDown + { + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow - 2, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + } + + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/TShaped.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/TShaped.cs new file mode 100644 index 0000000..1b23c21 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/TShaped.cs @@ -0,0 +1,59 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + /// + /// A "t-shaped" tetromino + /// X X X X X X + /// X X X X X X X X + /// X X + /// + public class TShaped : Tetromino + { + public TShaped(Grid grid) : base(grid) { } + + public override TetrominoStyle Style => TetrominoStyle.TShaped; + + public override string CssClass => "tetris-purple-cell"; + + public override CellCollection CoveredCells + { + get + { + CellCollection cells = new CellCollection(); + cells.Add(CenterPieceRow, CenterPieceColumn); + + if (Orientation == TetrominoOrientation.UpDown) + { + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + } + else if (Orientation == TetrominoOrientation.LeftRight) + { + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + } + else if (Orientation == TetrominoOrientation.DownUp) + { + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + cells.Add(CenterPieceRow + 1, CenterPieceColumn); + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + } + else //RightLeft + { + cells.Add(CenterPieceRow, CenterPieceColumn - 1); + cells.Add(CenterPieceRow, CenterPieceColumn + 1); + cells.Add(CenterPieceRow - 1, CenterPieceColumn); + } + + return cells; + } + } + } +} diff --git a/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Tetromino.cs b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Tetromino.cs new file mode 100644 index 0000000..ac125c7 --- /dev/null +++ b/W2-M2-Tetris-new/Models/Tetris/Tetrominos/Tetromino.cs @@ -0,0 +1,218 @@ +using W1_M2_Tetris.Models.Tetris.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace W1_M2_Tetris.Models.Tetris.Tetrominos +{ + public class Tetromino + { + /// + /// Represents the grid on which this tetromino can move. + /// + public Grid Grid { get; set; } + + /// + /// The current orientation of this tetromino. Tetrominos rotate about their center. + /// + public TetrominoOrientation Orientation { get; set; } = TetrominoOrientation.LeftRight; + + /// + /// The X-coordinate of the center piece. + /// + public int CenterPieceRow { get; set; } + + /// + /// The Y-coordinate of the center piece. + /// + public int CenterPieceColumn { get; set; } + + /// + /// The style of this tetromino, e.g. Straight, Block, T-Shaped, etc. + /// + public virtual TetrominoStyle Style { get; } + + /// + /// The CSS class that is unique to this style of tetromino. + /// + public virtual string CssClass { get; } + + /// + /// A collection of all spaces currently occupied by this tetromino. + /// This collection is calculated by each style. + /// + public virtual CellCollection CoveredCells { get; } + + public Tetromino(Grid grid) + { + Grid = grid; + CenterPieceRow = grid.Height; + CenterPieceColumn = grid.Width / 2; + } + + /// + /// Rotates the tetromino around the center piece. Tetrominos always rotate clockwise. + /// + public void Rotate() + { + switch(Orientation) + { + case TetrominoOrientation.UpDown: + Orientation = TetrominoOrientation.RightLeft; + break; + + case TetrominoOrientation.RightLeft: + Orientation = TetrominoOrientation.DownUp; + break; + + case TetrominoOrientation.DownUp: + Orientation = TetrominoOrientation.LeftRight; + break; + + case TetrominoOrientation.LeftRight: + Orientation = TetrominoOrientation.UpDown; + break; + } + + var coveredSpaces = CoveredCells; + + //If the new rotation of the tetromino means it would be outside the + //play area, shift the center space so as to keep the entire tetromino visible. + if(coveredSpaces.HasColumn(-1)) + { + CenterPieceColumn += 2; + } + else if (coveredSpaces.HasColumn(12)) + { + CenterPieceColumn -= 2; + } + else if (coveredSpaces.HasColumn(0)) + { + CenterPieceColumn++; + } + else if (coveredSpaces.HasColumn(11)) + { + CenterPieceColumn--; + } + } + + /// + /// Moves the tetromino one column to the right + /// + public void MoveRight() + { + if (CanMoveRight()) + { + CenterPieceColumn++; + } + } + + /// + /// Make the tetromino drop all the way to its lowest possible point. + /// + /// The score gained from dropping the piece + public int Drop() + { + int scoreCounter = 0; + while(CanMoveDown()) + { + MoveDown(); + scoreCounter++; + } + + return scoreCounter; + } + + /// + /// Move the tetromino down one row. + /// + public void MoveDown() + { + if (CanMoveDown()) + { + CenterPieceRow--; + } + } + + /// + /// Returns whether or not the tetromino can move in any direction (down, left, right). + /// + /// + public bool CanMove() + { + return CanMoveDown() || CanMoveLeft() || CanMoveRight(); + } + + /// + /// Returns whether or not the tetromino can move down. + /// + /// + public bool CanMoveDown() + { + //For each of the covered spaces, get the space immediately below + foreach (var coord in CoveredCells.GetLowest()) + { + if (Grid.Cells.Contains(coord.Row - 1, coord.Column)) + return false; + } + + //If any of the covered spaces are currently in the lowest row, the piece cannot move down. + if (CoveredCells.HasRow(1)) + return false; + + return true; + } + + /// + /// Returns whether or not the tetromino can move right + /// + /// + public bool CanMoveRight() + { + //For each of the covered spaces, get the space immediately to the right + foreach (var cell in CoveredCells.GetRightmost()) + { + if (Grid.Cells.Contains(cell.Row, cell.Column + 1)) + return false; + } + + //If any of the covered spaces are currently in the rightmost column, the piece cannot move right. + if (CoveredCells.HasColumn(Grid.Width)) + return false; + + return true; + } + + /// + /// Moves the tetromino one column to the left. + /// + public void MoveLeft() + { + if (CanMoveLeft()) + { + CenterPieceColumn--; + } + } + + /// + /// Returns whether or not the tetromino can move to the left. + /// + /// + public bool CanMoveLeft() + { + //For each of the covered spaces, get the space immediately to the left + foreach (var cell in CoveredCells.GetLeftmost()) + { + if (Grid.Cells.Contains(cell.Row, cell.Column - 1)) + return false; + } + + //If any of the covered spaces are currently in the leftmost column, the piece cannot move left. + if (CoveredCells.HasColumn(1)) + return false; + + return true; + } + } +} diff --git a/W2-M2-Tetris-new/Pages/Index.razor b/W2-M2-Tetris-new/Pages/Index.razor new file mode 100644 index 0000000..9f7f421 --- /dev/null +++ b/W2-M2-Tetris-new/Pages/Index.razor @@ -0,0 +1,348 @@ +@page "/" +@using W1_M2_Tetris.Models.Tetris; +@using W1_M2_Tetris.Models.Tetris.Tetrominos; +@using W1_M2_Tetris.Pages.Partials; +@using W1_M2_Tetris.Models.Tetris.Enums; +@inject IJSRuntime _jsRuntime; + +@code { + Grid grid = new Grid(); + + //Creates new tetrominos as the game needs them + TetrominoGenerator generator = new TetrominoGenerator(); + + //Represents the currently-falling tetromino + Tetromino currentTetromino; + + //Represents the next three tetromino styles. + //The actual tetrominos will be created only when they become the current tetromino. + TetrominoStyle nextStyle; + TetrominoStyle secondNextStyle; + TetrominoStyle thirdNextStyle; + + //The standard delay is how long the game waits before dropping the current tetromino by one row. + int standardDelay = 1000; + + //This flag is set if the player "hard drops" a tetromino all the way to the bottom + bool skipDelay = false; + + //The level increases for each 4000 points scored. Every time the level increases, + //the standard delay gets shorter. + int level = 1; + int score = 0; + int previousHighScore = 0; + string previousScoreCookieValue = "Nothing"; + + //This flag changes based on whether or not the user checks the "mute audio" checkbox. + bool playAudio = true; + + protected ElementReference gameBoardDiv; // set by the @ref attribute + + protected override async Task OnInitializedAsync() + { + //Get the previous high score cookie if one exists + previousScoreCookieValue = await _jsRuntime.InvokeAsync("ReadCookie", "tetrisHighScore"); + bool hasHighScore = int.TryParse(previousScoreCookieValue, out previousHighScore); + } + + protected async override Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await _jsRuntime.InvokeVoidAsync("SetFocusToElement", gameBoardDiv); + } + } + + public void NewGame() + { + grid = new Grid(); + + generator = new TetrominoGenerator(); + + currentTetromino = null; + + level = 1; + score = 0; + } + + public async Task RunGame() + { + //Start playing the theme music + if (playAudio) + await _jsRuntime.InvokeAsync("PlayAudio", "theme"); + + //Generate the styles of the first three tetrominos that will be dropped + nextStyle = generator.Next(); + secondNextStyle = generator.Next(nextStyle); + thirdNextStyle = generator.Next(nextStyle, secondNextStyle); + + //Start playing the game + grid.State = GameState.Playing; + + //Focus the browser on the board div + await _jsRuntime.InvokeVoidAsync("SetFocusToElement", gameBoardDiv); + + //Where there is no tetromino with a row of 21 or greater + while (!grid.Cells.HasRow(21)) //Game loop + { + //Create the next tetromino to be dropped from the already-determined nextStyle, + //and move the styles "up" in line + currentTetromino = generator.CreateFromStyle(nextStyle, grid); + nextStyle = secondNextStyle; + secondNextStyle = thirdNextStyle; + thirdNextStyle = generator.Next(currentTetromino.Style, nextStyle, secondNextStyle); + + StateHasChanged(); + + //Run the current tetromino until it can't move anymore + await RunCurrentTetromino(); + + //If any rows are filled, remove them from the board + await ClearCompleteRows(); + + //If the score is high enough, move the user to a new level + LevelChange(); + } + + //Once there is a tetromino with a row of 21 or greater, the game is over. + grid.State = GameState.GameOver; + + //If the current high score is larger than the old high score, update the cookie + if(score > previousHighScore) + await _jsRuntime.InvokeAsync("WriteCookie", "tetrisHighScore", score, 14); + } + + public async Task ToggleAudio() + { + playAudio = !playAudio; + + if(playAudio) + await _jsRuntime.InvokeAsync("PlayAudio", "theme"); + else + await _jsRuntime.InvokeAsync("PauseAudio", "theme"); + + //Focus the browser on the board div + await _jsRuntime.InvokeVoidAsync("SetFocusToElement", gameBoardDiv); + } + + //Delays the game up to the passed-in amount of milliseconds in 50 millisecond intervals + public async Task Delay(int millis) + { + int totalDelay = 0; + while (totalDelay < millis && !skipDelay) + { + totalDelay += 50; + await Task.Delay(50); + } + skipDelay = false; + } + + public async Task RunCurrentTetromino() + { + //While the tetromino can still move down + while (currentTetromino.CanMoveDown()) + { + //Wait for the standard delay + await Delay(standardDelay); + + //Move the tetromino down one row + currentTetromino.MoveDown(); + + //Update the display + StateHasChanged(); + + //If the tetromino can no longer move down BUT can still move in other directions, + //delay for an additional half-second to let the user move if they want. + if (!currentTetromino.CanMoveDown() && currentTetromino.CanMove()) + await Delay(500); + } + + //"Solidify" the current tetromino by adding its covered squares to the board's cells + grid.Cells.AddMany(currentTetromino.CoveredCells.GetAll(), currentTetromino.CssClass); + } + + public void LevelChange() + { + //The user goes up a level for every 4000 points they score. + int counter = 1; + int scoreCopy = score; + while(scoreCopy > 4000) + { + counter++; + scoreCopy -= 4000; + } + + int newLevel = counter; + if(newLevel != level) //If the user has gone up a level + { + //Reduce the drop delay by 100 milliseconds for every level the User has made. + standardDelay = 1000 - ((newLevel - 1) * 100); + + //Set the new level + level = newLevel; + } + } + + public async Task ClearCompleteRows() + { + //For each row + List rowsComplete = new List(); + for (int i = 1; i <= grid.Height; i++) + { + //If every position in that row is filled... + if (grid.Cells.GetAllInRow(i).Count == grid.Width) + { + //Add the "complete" animation CSS class + grid.Cells.SetCssClass(i, "tetris-clear-row"); + + //Mark that row as complete + rowsComplete.Add(i); + } + } + + //If there are any complete rows + if(rowsComplete.Any()) + { + StateHasChanged(); + + //Collapse the "higher" cells down to fill in the completed rows. + grid.Cells.CollapseRows(rowsComplete); + + //Calculate the score for the completed row(s) + switch (rowsComplete.Count) + { + case 1: + score += 40 * level; + break; + + case 2: + score += 100 * level; + break; + + case 3: + score += 300 * level; + break; + + case 4: + score += 1200 * level; + break; + } + + await Task.Delay(1000); + } + grid.State = GameState.Playing; + } + + protected async Task KeyDown(KeyboardEventArgs e) + { + if (grid.State == GameState.Playing) + { + if (e.Key == "ArrowRight") + { + currentTetromino.MoveRight(); + } + if (e.Key == "ArrowLeft") + { + currentTetromino.MoveLeft(); + } + if(e.Key == "ArrowDown" || e.Key == " ") + { + int addlScore = currentTetromino.Drop(); + score += addlScore; + skipDelay = true; + StateHasChanged(); + } + if(e.Key == "ArrowUp") + { + currentTetromino.Rotate(); + } + if(e.Key == "m") + { + await ToggleAudio(); + } + StateHasChanged(); + } + } +} + + + +