Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Game of Life #432

Merged
merged 2 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34525.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameOfLife", "GameOfLife\GameOfLife.csproj", "{236EDA58-32B7-4789-8327-FCF9016E8621}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{236EDA58-32B7-4789-8327-FCF9016E8621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{236EDA58-32B7-4789-8327-FCF9016E8621}.Debug|Any CPU.Build.0 = Debug|Any CPU
{236EDA58-32B7-4789-8327-FCF9016E8621}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{236EDA58-32B7-4789-8327-FCF9016E8621}.Release|Any CPU.ActiveCfg = Release|Any CPU
{236EDA58-32B7-4789-8327-FCF9016E8621}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F4AE3140-D3C9-48F6-A9BB-B90F47B46A66}
EndGlobalSection
EndGlobal
25 changes: 25 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/AboutPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GameOfLife.AboutPage"
Title="About">
<VerticalStackLayout Padding="20"
BackgroundColor="White">
<Label Text="The Game of Life"
FontSize="Large"
HorizontalTextAlignment="Center" />
<Label Text="This is an implementation of the Game of Life for .NET MAUI. Life is a cellular automaton invented by mathematician John Conway in 1970 and popularized in Scientific American." />
<Label Text="Tap cells to make them &quot;alive&quot;. A clustered population of live cells works the best. Then press the Run! button. Rules are applied to the live cells to generate successive populations. A population might grow, or shrink, or stagnate, or disappear." />
<Label Text="For more information, see the Wikipedia article:" />
<Label Text="https://en.wikipedia.org/wiki/Conway's_Game_of_Life"
TextColor="Blue"
FontAttributes="Italic"
HorizontalTextAlignment="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnHyperlinkTapped" />
</Label.GestureRecognizers>
</Label>
<Button Text="OK"
Clicked="OnCloseButtonClicked" />
</VerticalStackLayout>
</ContentPage>
20 changes: 20 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/AboutPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace GameOfLife;

public partial class AboutPage : ContentPage
{
public AboutPage()
{
InitializeComponent();
}

async void OnHyperlinkTapped(object sender, EventArgs args)
{
Label label = (Label)sender;
await Launcher.OpenAsync(label.Text);
}

async void OnCloseButtonClicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
26 changes: 26 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GameOfLife"
x:Class="GameOfLife.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style TargetType="Label">
<Setter Property="TextColor" Value="Black" />
<Setter Property="Margin" Value="0, 10" />
</Style>

<Style TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="Margin" Value="0, 5" />
</Style>

</ResourceDictionary>
</Application.Resources>
</Application>

12 changes: 12 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace GameOfLife;

public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new AppShell();
}
}

16 changes: 16 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/AppShell.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="GameOfLife.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:GameOfLife"
Shell.FlyoutBehavior="Disabled"
Title="GameOfLife">

<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />

</Shell>

10 changes: 10 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/AppShell.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace GameOfLife;

public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}

39 changes: 39 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/GameCell.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace GameOfLife
{
class GameCell : BoxView
{
public int Row { get; set; }
public int Col { get; set; }

bool isAlive;
public bool IsAlive
{
get
{
return isAlive;
}
set
{
if (isAlive != value)
{
isAlive = value;
BackgroundColor = isAlive ? Colors.Black : Colors.White;
}
}
}

public event EventHandler Tapped;

public GameCell()

Check warning on line 27 in 8.0/Apps/GameOfLife/GameOfLife/GameCell.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable event 'Tapped' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.

Check warning on line 27 in 8.0/Apps/GameOfLife/GameOfLife/GameCell.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Non-nullable event 'Tapped' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.

Check warning on line 27 in 8.0/Apps/GameOfLife/GameOfLife/GameCell.cs

View workflow job for this annotation

GitHub Actions / build (macos-13)

Non-nullable event 'Tapped' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.

Check warning on line 27 in 8.0/Apps/GameOfLife/GameOfLife/GameCell.cs

View workflow job for this annotation

GitHub Actions / build (macos-13)

Non-nullable event 'Tapped' must contain a non-null value when exiting constructor. Consider declaring the event as nullable.
{
BackgroundColor = Colors.White;

TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += (sender, args) =>
{
Tapped?.Invoke(this, EventArgs.Empty);
};
GestureRecognizers.Add(tapGesture);
}
}
}
140 changes: 140 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/GameGrid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
namespace GameOfLife
{
class GameGrid
{
// Change to true for grid-wrapping logic
const bool Wrap = false;

// Internal structure for encapsulting integer cell coordinates
// Keep this a structure for automatic equality comparison!
struct Coordinate
{
public int X { get; private set; }
public int Y { get; private set; }

public Coordinate(int x, int y)
{
X = x;
Y = y;
}
}

// The current population is stored in two ways, both of which are valid and consistent after every method call.

// This is a List of the coordinates of living cells:
List<Coordinate> coordinates = new List<Coordinate>();

// This is an array for for performing the Tick algorithm efficiently:
int cols = 10;
int rows = 10;
bool[,] grid = new bool[10, 10];

public void SetSize(int cols, int rows)
{
if (cols <= 0 || rows <= 0)
throw new ArgumentException("GameGrid.SetSize: Arguments must be greater than zero");

// If !Wrap, remove items from coordinates if X or Y greater than new cols and rows
if (!Wrap)
{
List<Coordinate> removeList = new List<Coordinate>();
foreach (Coordinate coordinate in coordinates)
{
if (coordinate.X < 0 || coordinate.X >= cols ||
coordinate.Y < 0 || coordinate.Y >= rows)
{
removeList.Add(coordinate);
}
}
foreach (Coordinate coordinate in removeList)
{
coordinates.Remove(coordinate);
}
}

this.cols = cols;
this.rows = rows;
CreateGridArray();
}

public void SetStatus(int x, int y, bool isAlive)
{
Coordinate coordinate = new Coordinate(x, y);

if (isAlive && !coordinates.Contains(coordinate))
coordinates.Add(coordinate);
if (!isAlive && coordinates.Contains(coordinate))
coordinates.Remove(coordinate);

CreateGridArray();
}

public bool IsAlive(int x, int y)
{
return grid[x, y];
}

public void Clear()
{
coordinates.Clear();
CreateGridArray();
}

public bool Tick()
{
coordinates.Clear();

if (grid == null)
return false;

for (int x = 0; x < cols; x++)
{
for (int y = 0; y < rows; y++)
{
int count = 0;

for (int xi = x - 1; xi <= x + 1; xi++)
for (int yi = y - 1; yi <= y + 1; yi++)
{
if (Wrap)
{
count += grid[(xi + cols) % cols, (yi + rows) % rows] ? 1 : 0;

Check warning on line 101 in 8.0/Apps/GameOfLife/GameOfLife/GameGrid.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Unreachable code detected

Check warning on line 101 in 8.0/Apps/GameOfLife/GameOfLife/GameGrid.cs

View workflow job for this annotation

GitHub Actions / build (macos-13)

Unreachable code detected
}
else
{
if (xi >= 0 && yi >= 0 && xi < cols && yi < rows)
{
count += grid[xi, yi] ? 1 : 0;
}
}
}

if (count == 3 || (count == 4 && grid[x, y]))
{
// Modulo arithmetic is necessary when Wrap is true
coordinates.Add(new Coordinate(x % cols, y % rows));
}
}
}

CreateGridArray();
return coordinates.Count > 0;
}

void CreateGridArray()
{
if (rows <= 0 || cols <= 0)
{
grid = null;

Check warning on line 128 in 8.0/Apps/GameOfLife/GameOfLife/GameGrid.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Cannot convert null literal to non-nullable reference type.

Check warning on line 128 in 8.0/Apps/GameOfLife/GameOfLife/GameGrid.cs

View workflow job for this annotation

GitHub Actions / build (macos-13)

Cannot convert null literal to non-nullable reference type.
return;
}

grid = new bool[cols, rows];
foreach (Coordinate coordinate in coordinates)
{
// Modulo arithmetic is necessary when Wrap is true
grid[coordinate.X % cols, coordinate.Y % rows] = true;
}
}
}
}
65 changes: 65 additions & 0 deletions 8.0/Apps/GameOfLife/GameOfLife/GameOfLife.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->

<!-- Note for MacCatalyst:
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifer>.
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->

<OutputType>Exe</OutputType>
<RootNamespace>GameOfLife</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<!-- Display name -->
<ApplicationTitle>GameOfLife</ApplicationTitle>

<!-- App Identifier -->
<ApplicationId>com.companyname.gameoflife</ApplicationId>

<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>

<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />

<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />

<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />

<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />

<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
</ItemGroup>

</Project>
Loading
Loading