Skip to content

Commit

Permalink
Game of Life (#432)
Browse files Browse the repository at this point in the history
* New sample.

* Win support.
  • Loading branch information
davidbritch committed Feb 12, 2024
1 parent 5390ebe commit 24c6a40
Show file tree
Hide file tree
Showing 42 changed files with 1,504 additions and 0 deletions.
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()
{
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;
}
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;
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

0 comments on commit 24c6a40

Please sign in to comment.