Compare commits

...

24 Commits
Test ... master

Author SHA1 Message Date
Shuozhe 1a110b213a added Brain for second Player 2021-07-25 01:21:22 +02:00
Shuozhe 0edb73d8a3 added tttBrain 2021-07-22 00:38:22 +02:00
Shuozhe 2492dfc796 Merge branch 'master' of https://gitea.hello-world.games/net/ProjectGrid 2021-07-15 23:37:02 +02:00
Shuozhe 1ed6178735 modified .gitignore 2021-07-15 23:35:54 +02:00
net 2e5f919b5a fixed wrong renamings 2021-07-15 15:58:27 +02:00
Shuozhe 8cf5c40b7d start implmenting creeps 2021-07-13 14:46:01 +02:00
Shuozhe bfcbd65763 .. 2021-07-10 00:46:41 +02:00
Shuozhe 8483168c96 added score 2021-07-09 00:32:33 +02:00
Shuozhe 90218f1af2 winning ends game now 2021-07-03 11:35:37 +02:00
Shuozhe bfcd8f8761 .. 2021-07-01 00:38:33 +02:00
Shuozhe 709ba026fa added seperate vuejs solution
mend
2021-06-30 15:36:49 +02:00
Shuozhe 77146fdafd got basic game working 2021-06-29 18:24:37 +02:00
Shuozhe ea6ef5b34a got basic commands working 2021-06-29 15:54:01 +02:00
Shuozhe 1ef728dc50 got c# backend working (more or less..) 2021-06-26 00:25:59 +02:00
Shuozhe 3d3ce211b3 refactor mostly.. 2021-06-24 01:12:54 +02:00
Shuozhe 63913b432c removes duplicates 2021-06-21 11:49:55 +02:00
Shuozhe d61c096f69 .. 2021-06-20 12:53:34 +02:00
Shuozhe Nan 0bb789cfb9 forgot some files 2021-06-18 16:12:19 +02:00
Shuozhe Nan 595fa95609 started ttt 2021-06-18 09:47:33 +02:00
Shuozhe 18eb69bd84 added tictactoc sammple 2021-06-17 16:24:32 +02:00
Shuozhe Nan 5c0b13fd8d added frontend into clientApp 2021-06-17 01:27:00 +02:00
net 9e642d9ee6 fixed something? 2021-06-16 21:51:03 +02:00
net 28672466a2 added TileData 2021-06-15 22:08:01 +02:00
net c01db4a04b fixed compile errors 2021-06-15 17:22:39 +02:00
49 changed files with 28201 additions and 130 deletions

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ProjectGrid.Data;
using ProjectGrid.Models;
namespace ProjectGrid.Controllers
{
[ApiController]
public class TicTacTocController : ControllerBase
{
private readonly ILogger<TicTacTocController> _logger;
private readonly TicTacTocManager _manager;
public TicTacTocController(ILogger<TicTacTocController> logger, TicTacTocManager manager)
{
_logger = logger;
_manager = manager;
}
[HttpGet]
[Route("api/ttt/GetBoard")]
public TicTacTocResponse GetBoard()
{
_logger.LogTrace("GetBoard called.");
return _manager.GetBoard();
}
[HttpGet]
[Route("api/ttt/Restart")]
public void RestartGame(TicTacToc.Mode mode = TicTacToc.Mode.CROSS_PLAYER)
{
_logger.LogTrace("RestartGame called.");
_manager.Restart(mode);
}
[HttpPost]
[Route("api/ttt/SetPiece")]
[Consumes("application/json")]
public TicTacTocResponse PostMove(TicTacTocRequest move)
{
_logger.LogTrace($"PostMove called. {move.DebugString()}");
return _manager.NextMove(move);
}
}
}

View File

@ -17,7 +17,7 @@ namespace ProjectGrid.Controllers
private readonly ILogger<UsersController> _logger;
//static readonly Models.IUserRepository repository = new Models.UserRepository();
private readonly Models.IUserRepository repository;
private readonly IUserRepository repository;
public UsersController(ILogger<UsersController> logger, DataAccessContext context)
{

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ProjectGrid.Models;
namespace ProjectGrid.Data
{
public partial class DataAccessContext : DbContext
{
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ProjectGrid.Models;
namespace ProjectGrid.Data
{
public partial class DataAccessContext : ITicTacToctRepository
{
public bool AddPiece(TicTacTocRequest request)
{
throw new System.NotImplementedException();
}
public TicTacTocBoard GetBoard()
{
throw new System.NotImplementedException();
}
}
}

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using ProjectGrid.Models;
namespace ProjectGrid.Data
{
public partial class DataAccessContext : DbContext, IUserRepository
{
public DbSet<UserData> Users { get; set; }
public IEnumerable<UserModel> GetAll()
{
return Users.Select<UserData, UserModel>(data => data.ToModel());
}
public UserModel Add(UserModel user)
{
// TODO: check if exist
Users.Add(new UserData(user));
SaveChanges();
return user;
}
}
}

View File

@ -7,28 +7,14 @@ using ProjectGrid.Models;
namespace ProjectGrid.Data
{
public class DataAccessContext : DbContext, IUserRepository
public partial class DataAccessContext : DbContext, IUserRepository
{
public DataAccessContext(DbContextOptions<DataAccessContext> options) : base(options) { }
public DbSet<UserData> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserData>().ToTable("USER");
}
public IEnumerable<UserModel> GetAll()
{
return Users.Select<UserData, UserModel>(data => data.ToModel());
}
public UserModel Add(UserModel user)
{
// TODO: check if exist
Users.Add(new UserData(user));
SaveChanges();
return user;
}
}
}

View File

@ -0,0 +1,11 @@
using ProjectGrid.Models;
namespace ProjectGrid.Data
{
public interface ITicTacToctRepository
{
TicTacTocBoard GetBoard();
bool AddPiece(TicTacTocRequest user);
}
}

12
Data/IUserRepository.cs Normal file
View File

@ -0,0 +1,12 @@
using ProjectGrid.Models;
using System.Collections.Generic;
namespace ProjectGrid.Data
{
public interface IUserRepository
{
IEnumerable<UserModel> GetAll();
UserModel Add(UserModel user);
}
}

View File

@ -1,16 +1,21 @@
using ProjectGrid.Models;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace ProjectGrid.Data
{
[Table("Map", Schema = "Map")]
public class MapData
{
public int? Id { get; set; }
[Key]
[Column("MapId")]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[Required]
public uint Width { get; set; }
[Required]
public uint Height { get; set; }
public MapData() { }
}
}

27
Data/TileData.cs Normal file
View File

@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace ProjectGrid.Data
{
[Table("Tile", Schema = "Map")]
public class TileData
{
[Key]
[Column("TileId")]
public int Id { get; set; }
public int MapId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[ForeignKey("MapId")]
public virtual MapData map { get; set; }
[Required]
[Column("PosX")]
public uint X { get; set; }
[Required]
[Column("PosY")]
public uint Y { get; set; }
}
}

View File

@ -0,0 +1,92 @@
using ProjectGrid.Models;
using ProjectGrid.TicTacToc;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ProjectGrid.AI
{
public class TicTacTocBrain
{
private TicTacTocBoard _board;
private int _player;
private List<int> _prio;
public TicTacTocBrain(TicTacTocBoard board, int player)
{
_board = board;
_player = player;
var rand = new Random();
_prio = (new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }).OrderBy(i => rand.Next()).ToList();
}
public int Turn()
{
if (_board.Field[4] == (int)Player.EMPTY)
{
//_board.SetFieldValue(_player, 5);
return 4;
}
int blocking = -1;
for (int x = 0; x < TicTacTocBoard._winning.GetLength(0); x++)
{
var _1 = _board.Field[TicTacTocBoard._winning[x, 0]];
var _2 = _board.Field[TicTacTocBoard._winning[x, 1]];
var _3 = _board.Field[TicTacTocBoard._winning[x, 2]];
// any field set?
if (_1 + _2 + _3 == 0)
continue;
var result = MatchWinning(_1, _2, _3);
if (result.Item1 >= 0)
return TicTacTocBoard._winning[x, result.Item1];
if (result.Item2 >= 0)
blocking = TicTacTocBoard._winning[x, result.Item2];
}
if (blocking >= 0)
return blocking;
foreach (var i in _prio)
if (_board.Field[i] == 0)
return i;
Debug.Fail("Brain found no valid move!");
return -1;
}
private (int win, int block) MatchWinning(int _1, int _2, int _3)
{
(int win, int block) result = (-1, -1);
if (_1 == _2 && _1 != 0 && _3 == 0)
{
if (_1 == _player)
result.win = 2;
else
result.block = 2;
}
else if (_1 == _3 && _1 != 0 && _2 == 0)
{
if (_1 == _player)
result.win = 1;
else
result.block = 1;
}
else if (_2 == _3 && _2 != 0 && _1 == 0)
{
if (_1 == _player)
result.win = 0;
else
result.block = 0;
}
return result;
}
}
}

View File

@ -0,0 +1,22 @@
using ProjectGrid.Models;
using System;
using System.Collections.Generic;
namespace ProjectGrid
{
public interface ICreeperMapManager
{
}
public class CreeperMapManager : ICreeperMapManager
{
private enum State
{
PLAYING,
GAME_OVER
}
private State _state;
}
}

103
Logic/TicTacTocBoard.cs Normal file
View File

@ -0,0 +1,103 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace ProjectGrid.Models
{
/// <summary>
/// Holds data for a TicTacTocBoard
/// 0: empty field, > 0 players
/// </summary>
public class TicTacTocBoard
{
private List<int> _field;
public List<int> Field => _field;
private int _lastSetValue;
public int LastSetValue => _lastSetValue;
public bool Full => !!!_field.Contains(0);
private int PosToIdx(int x, int y)
{
Debug.Assert(x >= 0 && x <= 3
&& y >= 0 && y <= 3,
$"{x}:{y} outside of playarea!");
return x + y * 3;
}
private int GetField(int x, int y) => _field[PosToIdx(x, y)];
private void SetField(int value, int x, int y)
{
_field[PosToIdx(x, y)] = value;
_lastSetValue = value;
}
private void SetField(int value, int idx)
{
_field[idx] = value;
_lastSetValue = value;
}
// 0 1 2
// 3 4 5
// 6 7 8
public static readonly int[,] _winning = new int[,] {
{ 0, 1, 2 },
{ 3, 4, 5 },
{ 6, 7 ,8 },
{ 0, 3 ,6 },
{ 1, 4 ,7 },
{ 2, 5 ,8 },
{ 0, 4 ,8 },
{ 2, 4 ,6 },
};
public TicTacTocBoard()
{
_field = new List<int>(new int[9] {
0, 0, 0,
0, 0, 0,
0, 0, 0,
});
_lastSetValue = 0;
}
//public bool SetFieldValue(int value, int x, int y, bool force = false)
public bool SetFieldValue(int value, int idx, bool force = false)
{
int field = _field[idx];
if (0 == field || force)
{
SetField(value, idx);
return true;
}
return false;
}
public List<int> ValueWon(int value)
{
Debug.Assert(value > 0, "ValueWon called for Empty field 0");
int x = 0;
for (; x < _winning.GetLength(0); x++)
{
bool won = true;
for (int y = 0; y < _winning.GetLength(1); y++)
{
if (_field[_winning[x, y]] != value)
{
won = false;
break;
}
}
if (won)
{
return new List<int>() { _winning[x, 0], _winning[x, 1], _winning[x, 2] };
}
}
return null;
}
}
}

123
Logic/TicTacTocManager.cs Normal file
View File

@ -0,0 +1,123 @@
using ProjectGrid.AI;
using ProjectGrid.Models;
using ProjectGrid.TicTacToc;
using System;
using System.Collections.Generic;
namespace ProjectGrid
{
public interface ITicTacTocManager
{
public void Restart(Mode mode);
public TicTacTocResponse NextMove(TicTacTocRequest move);
public TicTacTocResponse GetBoard();
}
public class TicTacTocManager : ITicTacTocManager
{
private enum State
{
PLAYING,
GAME_OVER
}
private State _state;
private Mode _mode;
private TicTacTocBrain _brain;
//private ITicTacToctRepository _repo;
private int _currentPlayer;
private TicTacTocBoard _board;
public TicTacTocBoard Board => _board;
public int[] _playerScore = new int[] { 0, 0, 0 };
public TicTacTocManager(/*ITicTacToctRepository repo*/)
{
//_repo = repo;
_currentPlayer = 1;
Restart(Mode.CROSS_PLAYER);
}
public TicTacTocResponse NextMove(TicTacTocRequest move)
{
TicTacTocResponse response = new TicTacTocResponse();
if (_state != State.GAME_OVER)
{
if (_board.SetFieldValue(_currentPlayer, move.Field))
{
response.Winning = _board.ValueWon(_currentPlayer);
if (_currentPlayer > 0 && response.Winning != null)
{
response.PlayerWon = _currentPlayer;
_state = State.GAME_OVER;
_playerScore[_currentPlayer]++;
}
else if (null != _brain)
{
if (_board.Full)
{
_playerScore[0]++;
_state = State.GAME_OVER;
response.PlayerWon = 0;
return response;
}
int ai = 3 - _currentPlayer;
var turn = _brain.Turn();
Console.WriteLine($"Brain made move {turn} for player {ai}");
_board.SetFieldValue(ai, turn);
response.Winning = _board.ValueWon(ai);
if (response.Winning != null)
{
response.PlayerWon = ai;
_playerScore[ai]++;
_state = State.GAME_OVER;
}
}
else
{
// switch between 1 and 2
_currentPlayer = 3 - _currentPlayer;
}
}
if (_board.Full)
{
_playerScore[0]++;
_state = State.GAME_OVER;
}
}
response.Board = _board.Field;
response.PlayerScore = new List<int>(_playerScore);
return response;
}
public void Restart(Mode mode)
{
_mode = mode;
_currentPlayer = 1;
_board = new TicTacTocBoard();
_state = State.PLAYING;
_brain = null;
if (Mode.TWO_PLAYER != mode)
_brain = new TicTacTocBrain(_board, 3 - (int)mode);
}
public TicTacTocResponse GetBoard()
{
TicTacTocResponse response = new TicTacTocResponse();
response.Board = _board.Field;
return response;
}
}
}

18
Logic/TicTacTocTypes.cs Normal file
View File

@ -0,0 +1,18 @@
using ProjectGrid.Models;
namespace ProjectGrid.TicTacToc
{
public enum Mode
{
TWO_PLAYER = 0,
CROSS_PLAYER = 1,
CIRCLE_PLAYER = 2,
}
public enum Player
{
EMPTY = 0,
CROSS = 1,
CIRCLE = 2,
}
}

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
namespace ProjectGrid.Models
{
public interface IUserRepository
{
IEnumerable<UserModel> GetAll();
UserModel Add(UserModel user);
}
}

View File

@ -0,0 +1,14 @@
namespace ProjectGrid.Models
{
public class TicTacTocRequest
{
//public int PosX { get; set; }
//public int PosY { get; set; }
public int Field { get; set; }
public int Player { get; set; }
public string DebugString() => $"Field: {Field}, Player: {Player}";//$"Pos: [{PosX}|{PosY}; Player: {Player}";
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace ProjectGrid.Models
{
public class TicTacTocResponse
{
public List<int> Board { get; set; }
public List<int> Winning { get; set; }
public int NextPlayer { get; set; }
public int PlayerWon { get; set; }
public List<int> PlayerScore { get; set; }
}
}

View File

@ -1,13 +1,13 @@
namespace ProjectGrid.Models
{
public class UserModel
{
public int Id { get; set; }
public class UserModel
{
public int Id { get; set; }
public string firstName { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
}
public string email { get; set; }
}
}

View File

@ -1,34 +1,35 @@
using ProjectGrid.Data;
using System;
using System.Collections.Generic;
namespace ProjectGrid.Models
{
public class UserRepository: IUserRepository
public class UserRepository : IUserRepository
{
private List<UserModel> users = new List<UserModel>();
private int _nextId = 1;
public UserRepository()
{
private List<UserModel> users = new List<UserModel>();
private int _nextId = 1;
public UserRepository()
{
Add(new UserModel { firstName= "first1", lastName="last1", email="email1@gmail.com"});
Add(new UserModel { firstName= "first2", lastName="last2", email="email2@gmail.com"});
Add(new UserModel { firstName= "first3", lastName="last3", email="email3@gmail.com"});
}
public IEnumerable<UserModel> GetAll()
{
return users;
}
public UserModel Add(UserModel item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
item.Id = _nextId++;
users.Add(item);
return item;
}
Add(new UserModel { firstName = "first1", lastName = "last1", email = "email1@gmail.com" });
Add(new UserModel { firstName = "first2", lastName = "last2", email = "email2@gmail.com" });
Add(new UserModel { firstName = "first3", lastName = "last3", email = "email3@gmail.com" });
}
public IEnumerable<UserModel> GetAll()
{
return users;
}
public UserModel Add(UserModel item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
item.Id = _nextId++;
users.Add(item);
return item;
}
}
}

View File

@ -30,7 +30,6 @@ namespace ProjectGrid
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while seeding the database.");
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -17,16 +17,70 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.17.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Compile Remove="clientapp\**" />
<Content Remove="$(SpaRoot)**" />
<Content Remove="clientapp\**" />
<EmbeddedResource Remove="clientapp\**" />
<None Remove="$(SpaRoot)**" />
<None Remove="clientapp\**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<ItemGroup>
<None Remove="clientapp\.editorconfig" />
<None Remove="clientapp\.gitignore" />
<None Remove="clientapp\.vs\clientapp\v16\.suo" />
<None Remove="clientapp\.vs\ProjectGrid.frontend\v16\.suo" />
<None Remove="clientapp\.vs\ProjectSettings.json" />
<None Remove="clientapp\.vs\slnx.sqlite" />
<None Remove="clientapp\.vs\tasks.vs.json" />
<None Remove="clientapp\.vs\VSWorkspaceState.json" />
<None Remove="clientapp\babel.config.js" />
<None Remove="clientapp\bin\Microsoft.NodejsTools.WebRole.dll" />
<None Remove="clientapp\dist\css\app.91da2c62.css" />
<None Remove="clientapp\dist\css\chunk-vendors.55204a1e.css" />
<None Remove="clientapp\dist\favicon.ico" />
<None Remove="clientapp\dist\index.html" />
<None Remove="clientapp\dist\js\chunk-vendors.e49ff54c.js" />
<None Remove="clientapp\dist\js\chunk-vendors.e49ff54c.js.map" />
<None Remove="clientapp\obj\Debug\ProjectGrid.frontend.njsproj.AssemblyReference.cache" />
<None Remove="clientapp\obj\Debug\ProjectGrid.frontend.njsproj.CoreCompileInputs.cache" />
<None Remove="clientapp\obj\Debug\ProjectGrid.frontend.njsproj.FileListAbsolute.txt" />
<None Remove="clientapp\package-lock.json" />
<None Remove="clientapp\package.json" />
<None Remove="clientapp\ProjectGrid.frontend.njsproj" />
<None Remove="clientapp\ProjectGrid.frontend.njsproj.user" />
<None Remove="clientapp\ProjectGrid.frontend.sln" />
<None Remove="clientapp\public\favicon.ico" />
<None Remove="clientapp\public\index.html" />
<None Remove="clientapp\README.md" />
<None Remove="clientapp\src\App.vue" />
<None Remove="clientapp\src\assets\logo.png" />
<None Remove="clientapp\src\assets\styles\global.css" />
<None Remove="clientapp\src\components\CreateUser.vue" />
<None Remove="clientapp\src\components\Dashboard.vue" />
<None Remove="clientapp\src\components\DisplayBoard.vue" />
<None Remove="clientapp\src\components\GameUI.vue" />
<None Remove="clientapp\src\components\Header.vue" />
<None Remove="clientapp\src\components\Users.vue" />
<None Remove="clientapp\src\Game.js" />
<None Remove="clientapp\src\main.js" />
<None Remove="clientapp\src\Player.js" />
<None Remove="clientapp\src\services\TicTacTocService.js" />
<None Remove="clientapp\src\services\UserService.js" />
<None Remove="clientapp\vue.config.js" />
</ItemGroup>
<ItemGroup>
<Folder Include="Util\" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">

View File

@ -15,58 +15,65 @@ using ProjectGrid.Data;
namespace ProjectGrid
{
public class Startup
public class Startup
{
ILogger _logger;
public Startup()
{
ILogger _logger;
public Startup()
{
Configuration = new ConfigurationBuilder()
.AddJsonFile("appSettings.json") // Get Connectionstring from appsetting.json
.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
// Cant log here..
//_logger.LogInformation($"Try to connect to Database with {connectionString}");
services.AddDbContext<DataAccessContext>(options => options.UseSqlServer(connectionString));
//_logger.LogInformation($"DataAccessContext registered with {connectionString}");
// TODO: for Testing
//services.AddDatabaseDeveloperPageExceptionFilter();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ProjectGrid", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
_logger = logger;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ProjectGrid v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Configuration = new ConfigurationBuilder()
.AddJsonFile("appSettings.json") // Get Connectionstring from appsetting.json
.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
// Cant log here..
//_logger.LogInformation($"Try to connect to Database with {connectionString}");
services.AddDbContext<DataAccessContext>(options => options.UseSqlServer(connectionString));
//_logger.LogInformation($"DataAccessContext registered with {connectionString}");
// TODO: for Testing
//services.AddDatabaseDeveloperPageExceptionFilter();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ProjectGrid", Version = "v1" });
});
// Manager
services.AddSingleton<TicTacTocManager>(new TicTacTocManager());
services.AddScoped<ITicTacTocManager, TicTacTocManager>();
// DataAccess
services.AddScoped<ITicTacToctRepository, DataAccessContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
_logger = logger;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ProjectGrid v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

5
clientapp/.editorconfig Normal file
View File

@ -0,0 +1,5 @@
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\net\repository\ProjectGrid\clientapp codebase based on best match to current usage at 30.06.2021
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]

View File

@ -2,7 +2,6 @@
node_modules
/dist
# local env files
.env.local
.env.*.local
@ -18,6 +17,4 @@ pnpm-debug.log*
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,107 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<Name>ProjectGrid.frontend</Name>
<RootNamespace>ProjectGrid.frontend</RootNamespace>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>9999c154-0e07-43eb-8462-3b128c7fe175</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>node_modules\@vue\cli-service\bin\vue-cli-service.js</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
<NodejsPort>1337</NodejsPort>
<StartWebBrowser>true</StartWebBrowser>
<ScriptArguments>serve</ScriptArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Content Include="public\favicon.ico" />
<Content Include="public\index.html" />
<Content Include="src\App.vue" />
<Content Include="package.json" />
<Content Include="README.md" />
<Content Include="src\assets\logo.png" />
<Content Include="src\assets\styles\global.css" />
<Content Include="src\Game.js" />
<Content Include="src\Player.js" />
<Content Include="src\services\TicTacTocService.js" />
<Content Include="src\services\UserService.js" />
</ItemGroup>
<ItemGroup>
<Folder Include="dist\" />
<Folder Include="public\" />
<Folder Include="src\" />
<Folder Include="src\assets\" />
<Folder Include="src\assets\styles\" />
<Folder Include="src\components\" />
<Folder Include="src\services\" />
</ItemGroup>
<ItemGroup>
<Content Include="babel.config.js" />
<Content Include="src\components\CreateUser.vue" />
<Content Include="src\components\Dashboard.vue" />
<Content Include="src\components\DisplayBoard.vue" />
<Content Include="src\components\GameUI.vue" />
<Content Include="src\components\Header.vue" />
<Content Include="src\components\Users.vue" />
<Content Include="src\main.js" />
</ItemGroup>
<PropertyGroup>
<PostBuildEvent>
npm run build
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsToolsV2.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>0</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:48022/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>True</UseCustomServer>
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
<WebProjectProperties>
<StartPageUrl>
</StartPageUrl>
<StartAction>CurrentPage</StartAction>
<AspNetDebugging>True</AspNetDebugging>
<SilverlightDebugging>False</SilverlightDebugging>
<NativeDebugging>False</NativeDebugging>
<SQLDebugging>False</SQLDebugging>
<ExternalProgram>
</ExternalProgram>
<StartExternalURL>
</StartExternalURL>
<StartCmdLineArguments>
</StartCmdLineArguments>
<StartWorkingDirectory>
</StartWorkingDirectory>
<EnableENC>False</EnableENC>
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31424.327
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ProjectGrid.frontend", "ProjectGrid.frontend.njsproj", "{9999C154-0E07-43EB-8462-3B128C7FE175}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9999C154-0E07-43EB-8462-3B128C7FE175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9999C154-0E07-43EB-8462-3B128C7FE175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9999C154-0E07-43EB-8462-3B128C7FE175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9999C154-0E07-43EB-8462-3B128C7FE175}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9716124F-38C8-4975-AA1C-4BAD109852D4}
EndGlobalSection
EndGlobal

24
clientapp/README.md Normal file
View File

@ -0,0 +1,24 @@
# clientapp
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

26709
clientapp/package-lock.json generated

File diff suppressed because it is too large Load Diff

44
clientapp/package.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "clientapp",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.21.2",
"core-js": "^3.6.5",
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0-0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

23
clientapp/src/App.vue Normal file
View File

@ -0,0 +1,23 @@
<template>
<div id="app">
<GameUI />
</div>
</template>
<script>
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import GameUI from './components/GameUI.vue'
export default {
name: 'App',
components: {
GameUI
}
}
</script>
<style>
@import './assets/styles/global.css';
</style>

109
clientapp/src/Game.js Normal file
View File

@ -0,0 +1,109 @@
class Game {
constructor() {
this.players = []
this.winningCondition = [
["00", "01", "02"],
["00", "11", "22"],
["00", "10", "20"],
["02", "11", "20"],
["10", "11", "12"],
["02", "12", "22"],
["01", "11", "21"],
["20", "21", "22"]
];
this.currentTurn = "X";
this.drawScore = 0;
this.isGameEnded = false;
this._winningConditions =
this.winningCondition.map(x => x.join(","));
}
makeMove() {
}
changeTurn() {
this.currentTurn = this.currentTurn == this.players[0].sign ? this.players[1].sign : this.players[0].sign;
}
reset() {
this.currentTurn = this.players[0].sign;
this.players.forEach(x => {
x.clicks = [];
})
}
checkWinner(btn) {
if (btn.innerHTML == this.players[0].sign) {
this.players[0].clicks.push(btn.id);
} else {
this.players[1].clicks.push(btn.id);
}
this.players.forEach(x => {
x.sortClicks()
x.setPosition();
})
if (this.players[0].positions.length > 2 || this.players[1].positions.length > 2) {
let player1_combinations = this.getCombination(this.players[0].positions, 3, 0);
console.log(player1_combinations)
let player2_combinations = this.getCombination(this.players[1].positions, 3, 0);
//find p1,p2 common with winning conditions
let player1_common = this._winningConditions.filter(value =>
player1_combinations.includes(value)
);
let player2_common = this._winningConditions.filter(value =>
player2_combinations.includes(value)
);
return this.isGameOver(player1_common, player2_common);
} else {
return false;
}
}
isGameOver(player1_common, player2_common) {
if (player1_common.length < 1 && player2_common.length < 1)
return false;
let gameOver = false;
if (player1_common > player2_common) {
gameOver = true
this.players[0].score += 1;
alert("Player One Won");
} else if (player2_common > player1_common) {
gameOver = true
this.players[1].score += 1;
alert("Player Two Won");
} else if (this.players[0].clicks.length > 4 || this.players[1].clicks.length > 4) {
gameOver = true
this.drawScore += 1;
alert("Draw");
} else {
gameOver = false
}
return gameOver;
}
getCombination(input, len, start) {
const result = new Array(3);
let combinations = new Array();
combine(input, len, start);
function combine(input, len, start) {
if (len === 0) {
combinations.push(result.join(","));
return;
}
for (var i = start; i <= input.length - len; i++) {
result[result.length - len] = input[i];
combine(input, len - 1, i + 1);
}
}
return combinations;
}
}
export default Game;

18
clientapp/src/Player.js Normal file
View File

@ -0,0 +1,18 @@
class Player {
constructor(sign, id) {
this.id = id;
this.sign = sign;
this.clicks = [];
this.score = 0;
this.combinations = [];
this.positions = []
}
setPosition() {
this.positions = this.clicks.join(",").split(",");
}
sortClicks() {
this.clicks.sort();
}
}
export default Player;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,65 @@
.header {
padding: 2%;
background-color: rgb(131, 53, 241);
font-size: 50px;
text-align: center;
width: 100%;
color: white;
}
.footer {
padding: 2%;
background-color: red;
font-size: 50px;
text-align: center;
width: 100%
}
.dashboard {
padding: 3% 1%;
}
h1 {
text-align: center;
}
.display-board {
width: 100%;
background-color: rgba(179, 242, 163, 0.719);
padding: 5%;
}
.number {
color: red;
font-size: 75px;
text-align: center;
}
.mrgnbtm {
margin-top: 20px;
}
.gamebox button {
width: 100px;
height: 100px;
border: 1px solid #000;
display: inline-block;
font-size: 30px;
color: #ff6a00;
}
.gamebox {
margin: 0 auto;
max-width: 300px;
display: grid;
justify-items: center;
align-content: space-around;
grid-template-columns: repeat(3, 1fr);
}
.replay {
border: 1px solid #ddd;
height: 60px;
margin-top: 20px;
padding: 10px;
}

View File

@ -0,0 +1,58 @@
<template>
<div class="container">
<div class="row">
<div class="col-md-7 mrgnbtm">
<h2>Create User</h2>
<form>
<div class="row">
<div class="form-group col-md-6">
<label htmlFor="exampleInputEmail1">First Name</label>
<input type="text" class="form-control" v-model="firstName" name="firstname" id="firstname" aria-describedby="emailHelp" placeholder="First Name" />
</div>
<div class="form-group col-md-6">
<label htmlFor="exampleInputPassword1">Last Name</label>
<input type="text" class="form-control" v-model="lastName" name="lastname" id="lastname" placeholder="Last Name" />
</div>
</div>
<div class="row">
<div class="form-group col-md-12">
<label htmlFor="exampleInputEmail1">Email</label>
<input type="text" class="form-control" v-model="email" name="email" id="email" aria-describedby="emailHelp" placeholder="Email" />
</div>
</div>
<button type="button" @click='createUser()' class="btn btn-danger">Create</button>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'CreateUser',
data() {
return {
firstName: '',
lastName: '',
email: ''
}
},
methods: {
createUser() {
console.log(this.firstName)
const payload = {
firstName: this.firstName,
lastName: this.lastName,
email: this.email
}
this.$emit('createUser', payload)
this.clearForm();
},
clearForm() {
this.firstName = "";
this.lastName = "";
this.email = "";
}
}
}
</script>

View File

@ -0,0 +1,61 @@
<template>
<div class="hello">
<Header />
<div class="container mrgnbtm">
<div class="row">
<div class="col-md-8">
<CreateUser @createUser="userCreate($event)" />
</div>
<div class="col-md-4">
<DisplayBoard :numberOfUsers="numberOfUsers" @getAllUsers="getUsers()" />
</div>
</div>
</div>
<div class="row mrgnbtm">
<Users v-if="users.length > 0" :users="users" />
</div>
</div>
</template>
<script>
import Header from './Header.vue'
import CreateUser from './CreateUser.vue'
import DisplayBoard from './DisplayBoard.vue'
import Users from './Users.vue'
import { getAllUsers, createUser } from '../services/UserService'
export default {
name: 'Dashboard',
components: {
Header,
CreateUser,
DisplayBoard,
Users
},
data() {
return {
users: [],
numberOfUsers: 0
}
},
methods: {
getUsers() {
getAllUsers().then(res => {
this.users = res;
console.log(this.users)
this.numberOfUsers = this.users.length
});
},
userCreate(data) {
console.log(data);
createUser(data).then(res => {
this.getUsers();
console.log('res:::', res);
});
}
},
mounted () {
this.getUsers();
}
}
</script>

View File

@ -0,0 +1,23 @@
<template>
<div class="display-board">
<h4>Users Created</h4>
<div class="number">
{{numberOfUsers}}
</div>
<div class="btn">
<button @click='getAllUsers()' type="button" class="btn btn-warning">Get all Users</button>
</div>
</div>
</template>
<script>
export default {
name: 'DisplayBoard',
props: ['numberOfUsers'],
methods: {
getAllUsers() {
this.$emit('getAllUsers')
}
}
}
</script>

View File

@ -0,0 +1,92 @@
<template>
<div>
<div class="text-center">
<h1>Tic Tac Toe</h1>
<h3 id="turnText">Turn Of :{{this.game.currentTurn}}</h3>
<div class="score" v-if="game.players">
<span>
<u>Scores</u>
</span>
<br />
<span id="p1_score">Player One :{{this.game.players[0].score}}</span>
<br />
<span id="p2_score">Player Two :{{this.game.players[1].score}}</span>
<br />
<span id="draw_score">Draw :{{this.game.draw_score}}</span>
</div>
<button class="replay" id="restartBtn" @click="resetGame()">Restart</button>
</div>
<div class="gamebox" style="margin-top:20px">
<button id="0" @click="onClick($event)">{{btnText["0"]}}</button>
<button id="1" @click="onClick($event)">{{btnText["1"]}}</button>
<button id="2" @click="onClick($event)">{{btnText["2"]}}</button>
<button id="3" @click="onClick($event)">{{btnText["3"]}}</button>
<button id="4" @click="onClick($event)">{{btnText["4"]}}</button>
<button id="5" @click="onClick($event)">{{btnText["5"]}}</button>
<button id="6" @click="onClick($event)">{{btnText["6"]}}</button>
<button id="7" @click="onClick($event)">{{btnText["7"]}}</button>
<button id="8" @click="onClick($event)">{{btnText["8"]}}</button>
</div>
</div>
</template>
<script>
import Player from "../Player";
import Game from "../Game";
import { setPiece, restart } from '../services/TicTacTocService'
const game = new Game();
game.players.push(new Player("", 0));
game.players.push(new Player("X", 1));
game.players.push(new Player("O", 2));
export default {
name: "GameUI",
data() {
return {
game: game,
buttons: [],
btnText: []
};
},
methods: {
async onClick($event) {
let btn = $event.target;
const payload = {
Player: 1,
Field: btn.id
}
let response = await setPiece(payload);
console.log(response.board);
if (response.PlayerWon != 0) {
console.log(JSON.stringify(response));
for (let i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
this.btnText[i.toString()] = game.players[response.board[i]].sign;
}
}
this.game.draw_score = response.playerScore[0];
this.game.players[0].score = response.playerScore[1];
this.game.players[1].score = response.playerScore[2];
},
resetGame() {
//UI and backend reset
//this.game.reset();
restart();
[...this.buttons].forEach(btn => {
this.btnText[btn.id] = "";
});
}
},
mounted() {
//load all buttons and reset initially
this.$nextTick(() => {
this.buttons = this.$el.querySelectorAll(".gamebox button");
this.resetGame();
});
}
};
</script>

View File

@ -0,0 +1,11 @@
<template>
<div class="header">
Vue.js With .NET
</div>
</template>
<script>
export default {
name: 'Header'
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<div class="container">
<h2>Users</h2>
<table class="table table-bordered">
<thead>
<tr>
<th>User Id</th>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in users" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.firstName }}</td>
<td>{{ item.lastName }}</td>
<td>{{ item.email }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'Users',
props: ['users']
}
</script>

4
clientapp/src/main.js Normal file
View File

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

View File

@ -0,0 +1,17 @@
export async function getBoard() {
const response = await fetch('/api/ttt/GetBoard');
return await response.json();
}
export async function restart() {
await fetch('/api/ttt/Restart');
}
export async function setPiece(data) {
const response = await fetch(`api/ttt/SetPiece`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
return await response.json();
}

View File

@ -0,0 +1,14 @@
export async function getAllUsers() {
const response = await fetch('/api/users');
return await response.json();
}
export async function createUser(data) {
const response = await fetch(`/api/user`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
})
return await response.json();
}

13
clientapp/vue.config.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
devServer: {
//"public": "vue.hello-world.games",
"public": "localhost",
"port": 10002,
proxy: {
'^/api': {
target: 'https://localhost:5001',
changeOrigin: true
}
}
}
}

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "ProjectGrid.backend",
"lockfileVersion": 2,
"requires": true,
"packages": {}
}