mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-05-02 04:22:04 -04:00
Refactored naming for Kasino Mines and decoupled it from BotServices as it has no long lived tasks or whatever
This commit is contained in:
@@ -31,8 +31,8 @@ public class MinesCommand : ICommand
|
|||||||
public UserRight RequiredRight => UserRight.Loser;
|
public UserRight RequiredRight => UserRight.Loser;
|
||||||
public TimeSpan Timeout => TimeSpan.FromSeconds(30);
|
public TimeSpan Timeout => TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
private const string betPattern = @"(?<row>\d+),(?<col>\d+)";
|
private const string BetPattern = @"(?<row>\d+),(?<col>\d+)";
|
||||||
private const string toolUrl = "https://i.ddos.lgbt/raw/Kasino%20Mines%20Interface.html";
|
private const string ToolUrl = "https://i.ddos.lgbt/raw/Kasino%20Mines%20Interface.html";
|
||||||
|
|
||||||
public RateLimitOptionsModel? RateLimitOptions => new RateLimitOptionsModel
|
public RateLimitOptionsModel? RateLimitOptions => new RateLimitOptionsModel
|
||||||
{
|
{
|
||||||
@@ -40,6 +40,8 @@ public class MinesCommand : ICommand
|
|||||||
Window = TimeSpan.FromSeconds(10)
|
Window = TimeSpan.FromSeconds(10)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private KasinoMines? KasinoMines;
|
||||||
|
|
||||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments,
|
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
{
|
{
|
||||||
@@ -57,6 +59,8 @@ public class MinesCommand : ICommand
|
|||||||
true, autoDeleteAfter: gameDisabledCleanupDelay);
|
true, autoDeleteAfter: gameDisabledCleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KasinoMines = new KasinoMines(botInstance);
|
||||||
|
|
||||||
var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx);
|
var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx);
|
||||||
if (gambler == null)
|
if (gambler == null)
|
||||||
@@ -64,12 +68,12 @@ public class MinesCommand : ICommand
|
|||||||
bool cashout = false;
|
bool cashout = false;
|
||||||
if (message.Message.Contains("cashout")) cashout = true;
|
if (message.Message.Contains("cashout")) cashout = true;
|
||||||
//check if user has an existing game already
|
//check if user has an existing game already
|
||||||
if (!botInstance.BotServices.KasinoMines.activeGames.ContainsKey(gambler.Id))
|
if (!KasinoMines.ActiveGames.ContainsKey(gambler.Id))
|
||||||
{
|
{
|
||||||
if (arguments.TryGetValue("refresh", out var refresh))
|
if (arguments.TryGetValue("refresh", out var refresh))
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you don't have a game running. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {toolUrl}",
|
$"{user.FormatUsername()}, you don't have a game running. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {ToolUrl}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -77,7 +81,7 @@ public class MinesCommand : ICommand
|
|||||||
if (!arguments.TryGetValue("bet", out var bet))
|
if (!arguments.TryGetValue("bet", out var bet))
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {toolUrl}",
|
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {ToolUrl}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -91,7 +95,7 @@ public class MinesCommand : ICommand
|
|||||||
if (!arguments.TryGetValue("size", out var size) || !arguments.TryGetValue("mines", out var mines))
|
if (!arguments.TryGetValue("size", out var size) || !arguments.TryGetValue("mines", out var mines))
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {toolUrl}",
|
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {ToolUrl}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -104,11 +108,11 @@ public class MinesCommand : ICommand
|
|||||||
}
|
}
|
||||||
else if (arguments.TryGetValue("betString", out var betString)) //if they are using precise picks manually or from the tool to select specific squares to reveal
|
else if (arguments.TryGetValue("betString", out var betString)) //if they are using precise picks manually or from the tool to select specific squares to reveal
|
||||||
{
|
{
|
||||||
var matches = Regex.Matches(message.Message, betPattern);
|
var matches = Regex.Matches(message.Message, BetPattern);
|
||||||
if (matches.Count == 0 || matches == null) //if invalid bet string
|
if (matches.Count == 0 || matches == null) //if invalid bet string
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, invalid bet string. Example: !mines 100 10 10 1,3 1,5 2,6 - or use the tool: {toolUrl}", true, autoDeleteAfter: cleanupDelay);
|
$"{user.FormatUsername()}, invalid bet string. Example: !mines 100 10 10 1,3 1,5 2,6 - or use the tool: {ToolUrl}", true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (Match match in matches)
|
foreach (Match match in matches)
|
||||||
@@ -119,7 +123,7 @@ public class MinesCommand : ICommand
|
|||||||
else //if they didn't put anything
|
else //if they didn't put anything
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {toolUrl}",
|
$"{user.FormatUsername()}, not enough arguments. !mines <bet> <board size> <number of mines> <picks> to play simple mines. !mines <bet> <board size> <number of mines> <betString> for advanced mines. Tool: {ToolUrl}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -136,26 +140,26 @@ public class MinesCommand : ICommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//at this point all valid values so good to continue making the game
|
//at this point all valid values so good to continue making the game
|
||||||
await botInstance.BotServices.KasinoMines.CreateGame(gambler, wager, boardSize, minesCount);
|
await KasinoMines.CreateGame(gambler, wager, boardSize, minesCount);
|
||||||
var msg = await botInstance.SendChatMessageAsync(
|
var msg = await botInstance.SendChatMessageAsync(
|
||||||
$"{botInstance.BotServices.KasinoMines.activeGames[gambler.Id].ToString()}", true);
|
$"{KasinoMines.ActiveGames[gambler.Id].ToString()}", true);
|
||||||
|
|
||||||
if (pick == 0) //if using coordinates
|
if (pick == 0) //if using coordinates
|
||||||
{
|
{
|
||||||
var game = botInstance.BotServices.KasinoMines.activeGames[gambler.Id];
|
var game = KasinoMines.ActiveGames[gambler.Id];
|
||||||
foreach (var coord in precisePicks)
|
foreach (var coord in precisePicks)
|
||||||
{
|
{
|
||||||
if (game.betsPlaced.Contains(coord) || coord.r <= 0 || coord.r > game.size || coord.c <= 0 || coord.c > game.size)
|
if (game.BetsPlaced.Contains(coord) || coord.r <= 0 || coord.r > game.Size || coord.c <= 0 || coord.c > game.Size)
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, you can't place duplicate or invalid bets. Use the tool: {toolUrl}", true, autoDeleteAfter: cleanupDelay);
|
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, you can't place duplicate or invalid bets. Use the tool: {ToolUrl}", true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await botInstance.BotServices.KasinoMines.Bet(gambler.Id, precisePicks, msg, cashout);
|
await KasinoMines.Bet(gambler.Id, precisePicks, msg, cashout);
|
||||||
}
|
}
|
||||||
else //if using picks
|
else //if using picks
|
||||||
{
|
{
|
||||||
await botInstance.BotServices.KasinoMines.Bet(gambler.Id, pick, msg, cashout);
|
await KasinoMines.Bet(gambler.Id, pick, msg, cashout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -163,7 +167,7 @@ public class MinesCommand : ICommand
|
|||||||
//if there is a game already running
|
//if there is a game already running
|
||||||
if (arguments.TryGetValue("refresh", out var refresh))
|
if (arguments.TryGetValue("refresh", out var refresh))
|
||||||
{
|
{
|
||||||
await botInstance.BotServices.KasinoMines.RefreshGameMessage(gambler.Id);
|
await KasinoMines.RefreshGameMessage(gambler.Id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int pick = 0;
|
int pick = 0;
|
||||||
@@ -174,11 +178,11 @@ public class MinesCommand : ICommand
|
|||||||
}
|
}
|
||||||
else if (arguments.TryGetValue("betString", out var betString)) //if they are using precise picks manually or from the tool to select specific squares to reveal
|
else if (arguments.TryGetValue("betString", out var betString)) //if they are using precise picks manually or from the tool to select specific squares to reveal
|
||||||
{
|
{
|
||||||
var matches = Regex.Matches(message.Message, betPattern);
|
var matches = Regex.Matches(message.Message, BetPattern);
|
||||||
if (matches.Count == 0 || matches == null) //if invalid bet string
|
if (matches.Count == 0 || matches == null) //if invalid bet string
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, invalid bet string. Example: !mines 100 10 10 1,3 1,5 2,6 - or use the tool: {toolUrl}", true, autoDeleteAfter: cleanupDelay);
|
$"{user.FormatUsername()}, invalid bet string. Example: !mines 100 10 10 1,3 1,5 2,6 - or use the tool: {ToolUrl}", true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (Match match in matches)
|
foreach (Match match in matches)
|
||||||
@@ -190,34 +194,34 @@ public class MinesCommand : ICommand
|
|||||||
{
|
{
|
||||||
if (cashout)
|
if (cashout)
|
||||||
{
|
{
|
||||||
await botInstance.BotServices.KasinoMines.Cashout(botInstance.BotServices.KasinoMines.activeGames[gambler.Id]);
|
await KasinoMines.Cashout(KasinoMines.ActiveGames[gambler.Id]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you already have a game running. !mines <picks> to reveal more spaces, !mines cashout to cash out, !mines <bet string> to place precise picks. Tool: {toolUrl}",
|
$"{user.FormatUsername()}, you already have a game running. !mines <picks> to reveal more spaces, !mines cashout to cash out, !mines <bet string> to place precise picks. Tool: {ToolUrl}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var msg = await botInstance.SendChatMessageAsync(
|
var msg = await botInstance.SendChatMessageAsync(
|
||||||
$"{botInstance.BotServices.KasinoMines.activeGames[gambler.Id].ToString()}", true);
|
$"{KasinoMines.ActiveGames[gambler.Id].ToString()}", true);
|
||||||
|
|
||||||
if (pick == 0) //if using coordinates
|
if (pick == 0) //if using coordinates
|
||||||
{
|
{
|
||||||
var game = botInstance.BotServices.KasinoMines.activeGames[gambler.Id];
|
var game = KasinoMines.ActiveGames[gambler.Id];
|
||||||
foreach (var coord in precisePicks)
|
foreach (var coord in precisePicks)
|
||||||
{
|
{
|
||||||
if (game.betsPlaced.Contains(coord) || coord.r <= 0 || coord.r > game.size || coord.c <= 0 || coord.c > game.size)
|
if (game.BetsPlaced.Contains(coord) || coord.r <= 0 || coord.r > game.Size || coord.c <= 0 || coord.c > game.Size)
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, you can't place duplicate or invalid bets. Use the tool: {toolUrl}", true, autoDeleteAfter: cleanupDelay);
|
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, you can't place duplicate or invalid bets. Use the tool: {ToolUrl}", true, autoDeleteAfter: cleanupDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await botInstance.BotServices.KasinoMines.Bet(gambler.Id, precisePicks, msg, cashout);
|
await KasinoMines.Bet(gambler.Id, precisePicks, msg, cashout);
|
||||||
|
|
||||||
}
|
}
|
||||||
else //if using picks
|
else //if using picks
|
||||||
{
|
{
|
||||||
await botInstance.BotServices.KasinoMines.Bet(gambler.Id, pick, msg, cashout);
|
await KasinoMines.Bet(gambler.Id, pick, msg, cashout);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using KfChatDotNetBot.Extensions;
|
using KfChatDotNetBot.Extensions;
|
||||||
using KfChatDotNetBot.Models;
|
using KfChatDotNetBot.Models;
|
||||||
@@ -41,7 +41,6 @@ public class BotServices
|
|||||||
private ShuffleDotUs? _shuffleDotUs;
|
private ShuffleDotUs? _shuffleDotUs;
|
||||||
private YouTubePubSub? _youTubePubSub;
|
private YouTubePubSub? _youTubePubSub;
|
||||||
public KasinoRain? KasinoRain;
|
public KasinoRain? KasinoRain;
|
||||||
public KasinoMines KasinoMines;
|
|
||||||
|
|
||||||
private Task? _websocketWatchdog;
|
private Task? _websocketWatchdog;
|
||||||
private Task? _howlggGetUserTimer;
|
private Task? _howlggGetUserTimer;
|
||||||
@@ -94,8 +93,7 @@ public class BotServices
|
|||||||
BuildOwncastLiveStatusCheck(),
|
BuildOwncastLiveStatusCheck(),
|
||||||
BuildShuffleDotUs(),
|
BuildShuffleDotUs(),
|
||||||
BuildYouTubePubSub(),
|
BuildYouTubePubSub(),
|
||||||
BuildKasinoRain(),
|
BuildKasinoRain()
|
||||||
BuildKasinoMines()
|
|
||||||
];
|
];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -117,12 +115,6 @@ public class BotServices
|
|||||||
_logger.Debug("Building the Kasino Rain thingy");
|
_logger.Debug("Building the Kasino Rain thingy");
|
||||||
KasinoRain = new KasinoRain(_chatBot, _cancellationToken);
|
KasinoRain = new KasinoRain(_chatBot, _cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task BuildKasinoMines()
|
|
||||||
{
|
|
||||||
_logger.Debug("Building the Kasino mines service");
|
|
||||||
KasinoMines = new KasinoMines(_chatBot, _cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task BuildShuffle()
|
private async Task BuildShuffle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,72 +10,69 @@ using StackExchange.Redis;
|
|||||||
|
|
||||||
namespace KfChatDotNetBot.Services;
|
namespace KfChatDotNetBot.Services;
|
||||||
|
|
||||||
public class KasinoMines : IDisposable
|
public class KasinoMines
|
||||||
{
|
{
|
||||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
private Task? _minesTimerTask;
|
|
||||||
private IDatabase? _redisDb;
|
private IDatabase? _redisDb;
|
||||||
private static ChatBot _kfChatBot;
|
private static ChatBot _kfChatBot;
|
||||||
private CancellationToken _ct;
|
public Dictionary<int, KasinoMinesGame>? ActiveGames;
|
||||||
private CancellationTokenSource _minesCts = new();
|
|
||||||
public Dictionary<int, KasinoMinesGame>? activeGames;
|
|
||||||
private decimal HOUSE_EDGE = (decimal)0.98; //used to rig win rate, payout is 100% fair. with shop i plan to implement a sort of kasino shop profile holding the investments and buffs and tracking the gamblers current house edge
|
private decimal HOUSE_EDGE = (decimal)0.98; //used to rig win rate, payout is 100% fair. with shop i plan to implement a sort of kasino shop profile holding the investments and buffs and tracking the gamblers current house edge
|
||||||
public class KasinoMinesGame
|
public class KasinoMinesGame
|
||||||
{
|
{
|
||||||
public GamblerDbModel creator { get; set; }
|
public GamblerDbModel Creator { get; set; }
|
||||||
public DateTime lastInteracted = DateTime.UtcNow;
|
public DateTimeOffset LastInteracted = DateTimeOffset.UtcNow;
|
||||||
public char[,] minesBoard;
|
public char[,] MinesBoard;
|
||||||
public decimal wager { get; set; }
|
public decimal Wager { get; set; }
|
||||||
public int size { get; set; }
|
public int Size { get; set; }
|
||||||
public int mines { get; set; }
|
public int Mines { get; set; }
|
||||||
public List<(int r, int c)> betsPlaced = new();
|
public List<(int r, int c)> BetsPlaced = new();
|
||||||
public SentMessageTrackerModel? lastMessage;
|
public SentMessageTrackerModel? LastMessage;
|
||||||
|
|
||||||
|
|
||||||
public KasinoMinesGame(GamblerDbModel creator, decimal wager, int size, int mines)
|
public KasinoMinesGame(GamblerDbModel creator, decimal wager, int size, int mines)
|
||||||
{
|
{
|
||||||
this.creator = creator;
|
this.Creator = creator;
|
||||||
this.size = size;
|
this.Size = size;
|
||||||
this.mines = mines;
|
this.Mines = mines;
|
||||||
this.wager = wager;
|
this.Wager = wager;
|
||||||
minesBoard = CreateBoard();
|
MinesBoard = CreateBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ResetMessage(SentMessageTrackerModel msg)
|
public async Task ResetMessage(SentMessageTrackerModel msg)
|
||||||
{
|
{
|
||||||
await _kfChatBot.KfClient.DeleteMessageAsync(lastMessage.ChatMessageId.Value);
|
await _kfChatBot.KfClient.DeleteMessageAsync(LastMessage.ChatMessageId.Value);
|
||||||
lastMessage = msg;
|
LastMessage = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RigBoard((int r, int c) coord) //moves one of the mines to a specified coordinate for house edge rigging
|
public async Task RigBoard((int r, int c) coord) //moves one of the mines to a specified coordinate for house edge rigging
|
||||||
{
|
{
|
||||||
//find the first mine
|
//find the first mine
|
||||||
(int r, int c) originalMine = (11, 11);
|
(int r, int c) originalMine = (11, 11);
|
||||||
for (int r = 0; r < size; r++)
|
for (int r = 0; r < Size; r++)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < size; c++)
|
for (int c = 0; c < Size; c++)
|
||||||
{
|
{
|
||||||
if (minesBoard[r, c] == 'M') originalMine = (r, c);
|
if (MinesBoard[r, c] == 'M') originalMine = (r, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
minesBoard[coord.r, coord.c] = 'M';
|
MinesBoard[coord.r, coord.c] = 'M';
|
||||||
if (originalMine.r == 11)
|
if (originalMine.r == 11)
|
||||||
{
|
{
|
||||||
_logger.Error("Rigboard failed to find a mine somehow?");
|
_logger.Error("Rigboard failed to find a mine somehow?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
minesBoard[originalMine.r, originalMine.c] = 'G';
|
MinesBoard[originalMine.r, originalMine.c] = 'G';
|
||||||
|
|
||||||
}
|
}
|
||||||
public async Task Explode((int r, int c) mineLocation, SentMessageTrackerModel msg)
|
public async Task Explode((int r, int c) mineLocation, SentMessageTrackerModel msg)
|
||||||
{
|
{
|
||||||
if (lastMessage != msg)
|
if (LastMessage != msg)
|
||||||
{
|
{
|
||||||
await ResetMessage(msg);
|
await ResetMessage(msg);
|
||||||
}
|
}
|
||||||
int frames = mineLocation.c;
|
int frames = mineLocation.c;
|
||||||
if (size - mineLocation.c > frames) frames = size - mineLocation.c;
|
if (Size - mineLocation.c > frames) frames = Size - mineLocation.c;
|
||||||
string str;
|
string str;
|
||||||
bool revealedSpace;
|
bool revealedSpace;
|
||||||
int yellowWave = 1;
|
int yellowWave = 1;
|
||||||
@@ -85,13 +82,13 @@ public class KasinoMines : IDisposable
|
|||||||
for (int f = 0; f < frames; f++)
|
for (int f = 0; f < frames; f++)
|
||||||
{
|
{
|
||||||
str = "";
|
str = "";
|
||||||
for (int r = 0; r < size; r++)
|
for (int r = 0; r < Size; r++)
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
revealedSpace = false;
|
revealedSpace = false;
|
||||||
for (int c = 0; c < size; c++)
|
for (int c = 0; c < Size; c++)
|
||||||
{
|
{
|
||||||
foreach (var bet in betsPlaced)
|
foreach (var bet in BetsPlaced)
|
||||||
{
|
{
|
||||||
if (bet.r == r && bet.c == c) revealedSpace = true;
|
if (bet.r == r && bet.c == c) revealedSpace = true;
|
||||||
}
|
}
|
||||||
@@ -130,7 +127,7 @@ public class KasinoMines : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId.Value, $"{str}[br]{creator.User.FormatUsername()}");
|
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId.Value, $"{str}[br]{Creator.User.FormatUsername()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(10));
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
||||||
@@ -146,12 +143,12 @@ public class KasinoMines : IDisposable
|
|||||||
{
|
{
|
||||||
string value = "";
|
string value = "";
|
||||||
bool revealedSpace;
|
bool revealedSpace;
|
||||||
for (int r = 0; r < size; r++)
|
for (int r = 0; r < Size; r++)
|
||||||
{
|
{
|
||||||
revealedSpace = false;
|
revealedSpace = false;
|
||||||
for (int c = 0; c < size; c++)
|
for (int c = 0; c < Size; c++)
|
||||||
{
|
{
|
||||||
foreach (var bet in betsPlaced)
|
foreach (var bet in BetsPlaced)
|
||||||
{
|
{
|
||||||
if (bet.r == r && bet.c == c) revealedSpace = true;
|
if (bet.r == r && bet.c == c) revealedSpace = true;
|
||||||
}
|
}
|
||||||
@@ -160,33 +157,33 @@ public class KasinoMines : IDisposable
|
|||||||
{
|
{
|
||||||
value += "⬜";
|
value += "⬜";
|
||||||
}
|
}
|
||||||
else if (minesBoard[r, c] == 'M') value += "💣";
|
else if (MinesBoard[r, c] == 'M') value += "💣";
|
||||||
else value += "💎";
|
else value += "💎";
|
||||||
}
|
}
|
||||||
|
|
||||||
value += "[br]";
|
value += "[br]";
|
||||||
}
|
}
|
||||||
|
|
||||||
value += $"{creator.User.FormatUsername()}";
|
value += $"{Creator.User.FormatUsername()}";
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[,] CreateBoard()
|
public char[,] CreateBoard()
|
||||||
{
|
{
|
||||||
char[,] board = new char[size, size];
|
char[,] board = new char[Size, Size];
|
||||||
List<(int r, int c)> minesCoords = new List<(int r, int c)>();
|
List<(int r, int c)> minesCoords = new List<(int r, int c)>();
|
||||||
(int r, int c) coord;
|
(int r, int c) coord;
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
bool gems = !(mines < (size * size)/2); //if there are more mines than gems, generate list of gem locations instead since thats less generations
|
bool gems = !(Mines < (Size * Size)/2); //if there are more mines than gems, generate list of gem locations instead since thats less generations
|
||||||
int coordsCounter;
|
int coordsCounter;
|
||||||
if (gems) coordsCounter = size * size - mines;
|
if (gems) coordsCounter = Size * Size - Mines;
|
||||||
else coordsCounter = mines;
|
else coordsCounter = Mines;
|
||||||
while (minesCoords.Count != coordsCounter)
|
while (minesCoords.Count != coordsCounter)
|
||||||
{
|
{
|
||||||
coord = (Money.GetRandomNumber(creator, 0, size), Money.GetRandomNumber(creator, 0, size));
|
coord = (Money.GetRandomNumber(Creator, 0, Size), Money.GetRandomNumber(Creator, 0, Size));
|
||||||
if (!minesCoords.Contains(coord)) minesCoords.Add(coord);
|
if (!minesCoords.Contains(coord)) minesCoords.Add(coord);
|
||||||
else counter++;
|
else counter++;
|
||||||
if (counter >= 100000) throw new Exception($"mines failed to generate mines coordinates. Mines: {mines} | Board size: {size} | Current count of mines list {minesCoords.Count}");
|
if (counter >= 100000) throw new Exception($"mines failed to generate mines coordinates. Mines: {Mines} | Board size: {Size} | Current count of mines list {minesCoords.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var coords in minesCoords)
|
foreach (var coords in minesCoords)
|
||||||
@@ -194,9 +191,9 @@ public class KasinoMines : IDisposable
|
|||||||
if (gems) board[coords.r, coords.c] = 'G';
|
if (gems) board[coords.r, coords.c] = 'G';
|
||||||
else board[coords.r, coords.c] = 'M';
|
else board[coords.r, coords.c] = 'M';
|
||||||
}
|
}
|
||||||
for (int r = 0; r < size; r++)
|
for (int r = 0; r < Size; r++)
|
||||||
{
|
{
|
||||||
for (int c = 0; c < size; c++)
|
for (int c = 0; c < Size; c++)
|
||||||
{
|
{
|
||||||
if (gems)
|
if (gems)
|
||||||
{
|
{
|
||||||
@@ -211,16 +208,12 @@ public class KasinoMines : IDisposable
|
|||||||
|
|
||||||
return board;
|
return board;
|
||||||
}
|
}
|
||||||
public async Task DeleteMessage(SentMessageTrackerModel msg)
|
|
||||||
{
|
|
||||||
await _kfChatBot.KfClient.DeleteMessageAsync(msg.ChatMessageId.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public KasinoMines(ChatBot kfChatBot, CancellationToken ct = default)
|
public KasinoMines(ChatBot kfChatBot)
|
||||||
{
|
{
|
||||||
_kfChatBot = kfChatBot;
|
_kfChatBot = kfChatBot;
|
||||||
_ct = ct;
|
|
||||||
var connectionString = SettingsProvider.GetValueAsync(BuiltIn.Keys.BotRedisConnectionString).Result;
|
var connectionString = SettingsProvider.GetValueAsync(BuiltIn.Keys.BotRedisConnectionString).Result;
|
||||||
if (string.IsNullOrEmpty(connectionString.Value))
|
if (string.IsNullOrEmpty(connectionString.Value))
|
||||||
{
|
{
|
||||||
@@ -230,16 +223,17 @@ public class KasinoMines : IDisposable
|
|||||||
|
|
||||||
var redis = ConnectionMultiplexer.Connect(connectionString.Value);
|
var redis = ConnectionMultiplexer.Connect(connectionString.Value);
|
||||||
_redisDb = redis.GetDatabase();
|
_redisDb = redis.GetDatabase();
|
||||||
|
GetSavedGames().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshGameMessage(int gamblerId)
|
public async Task RefreshGameMessage(int gamblerId)
|
||||||
{
|
{
|
||||||
await GetSavedGames();
|
await GetSavedGames();
|
||||||
var game = activeGames[gamblerId];
|
var game = ActiveGames[gamblerId];
|
||||||
game.lastInteracted = DateTime.UtcNow;
|
game.LastInteracted = DateTimeOffset.UtcNow;
|
||||||
var msg = await _kfChatBot.SendChatMessageAsync($"{game.ToString()}", true);
|
var msg = await _kfChatBot.SendChatMessageAsync($"{game.ToString()}", true);
|
||||||
await game.ResetMessage(msg);
|
await game.ResetMessage(msg);
|
||||||
activeGames[gamblerId] = game;
|
ActiveGames[gamblerId] = game;
|
||||||
await SaveActiveGames();
|
await SaveActiveGames();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,53 +242,49 @@ public class KasinoMines : IDisposable
|
|||||||
if (_redisDb == null) throw new InvalidOperationException("Kasino mines service isn't initialized");
|
if (_redisDb == null) throw new InvalidOperationException("Kasino mines service isn't initialized");
|
||||||
var json = await _redisDb.StringGetAsync("Mines.State");
|
var json = await _redisDb.StringGetAsync("Mines.State");
|
||||||
if (string.IsNullOrEmpty(json)) return;
|
if (string.IsNullOrEmpty(json)) return;
|
||||||
activeGames = JsonSerializer.Deserialize<Dictionary<int, KasinoMinesGame>>(json.ToString());
|
ActiveGames = JsonSerializer.Deserialize<Dictionary<int, KasinoMinesGame>>(json.ToString());
|
||||||
if (activeGames == null)
|
if (ActiveGames == null)
|
||||||
{
|
{
|
||||||
_logger.Error("Potentially failed to deserialize active mines games in GetSavedGames() in KasinoMines in Services");
|
_logger.Error("Potentially failed to deserialize active mines games in GetSavedGames() in KasinoMines in Services");
|
||||||
activeGames = new Dictionary<int, KasinoMinesGame>();
|
ActiveGames = new Dictionary<int, KasinoMinesGame>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task SaveActiveGames()
|
public async Task SaveActiveGames()
|
||||||
{
|
{
|
||||||
if (_redisDb == null) throw new InvalidOperationException("Kasino mines service isn't initialized");
|
if (_redisDb == null) throw new InvalidOperationException("Kasino mines service isn't initialized");
|
||||||
var json = JsonSerializer.Serialize(activeGames);
|
var json = JsonSerializer.Serialize(ActiveGames);
|
||||||
await _redisDb.StringSetAsync("Mines.State", json, null, When.Always);
|
await _redisDb.StringSetAsync("Mines.State", json, null, When.Always);
|
||||||
}
|
}
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RemoveGame(int gamblerId)
|
public async Task RemoveGame(int gamblerId)
|
||||||
{
|
{
|
||||||
await GetSavedGames();
|
await GetSavedGames();
|
||||||
activeGames?.Remove(gamblerId);
|
ActiveGames?.Remove(gamblerId);
|
||||||
await SaveActiveGames();
|
await SaveActiveGames();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Cashout(KasinoMinesGame game)
|
public async Task Cashout(KasinoMinesGame game)
|
||||||
{
|
{
|
||||||
decimal payout = 0;
|
decimal payout = 0;
|
||||||
decimal possiblePicks = game.size * game.size - game.mines;
|
decimal possiblePicks = game.Size * game.Size - game.Mines;
|
||||||
for (int i = 0; i < game.betsPlaced.Count; i++)
|
for (int i = 0; i < game.BetsPlaced.Count; i++)
|
||||||
{
|
{
|
||||||
payout += game.wager * (possiblePicks / game.betsPlaced.Count);
|
payout += game.Wager * (possiblePicks / game.BetsPlaced.Count);
|
||||||
possiblePicks--;
|
possiblePicks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newBalance = await Money.NewWagerAsync(game.creator.Id, game.wager, payout, WagerGame.Mines);
|
var newBalance = await Money.NewWagerAsync(game.Creator.Id, game.Wager, payout, WagerGame.Mines);
|
||||||
await _kfChatBot.SendChatMessageAsync(
|
await _kfChatBot.SendChatMessageAsync(
|
||||||
$"{game.creator.User.FormatUsername()}, you won {payout.FormatKasinoCurrencyAsync()} from your {game.wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.betsPlaced.Count} gems while avoiding {game.mines} mines. Net: {(payout - game.wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}");
|
$"{game.Creator.User.FormatUsername()}, you won {payout.FormatKasinoCurrencyAsync()} from your {game.Wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.BetsPlaced.Count} gems while avoiding {game.Mines} mines. Net: {(payout - game.Wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}");
|
||||||
await RemoveGame(game.creator.Id);
|
await RemoveGame(game.Creator.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Bet(int gamblerId, int count, SentMessageTrackerModel msg, bool cashOut = false) //returns false if you hit a bomb, true if you didn't
|
public async Task<bool> Bet(int gamblerId, int count, SentMessageTrackerModel msg, bool cashOut = false) //returns false if you hit a bomb, true if you didn't
|
||||||
{
|
{
|
||||||
await GetSavedGames();
|
await GetSavedGames();
|
||||||
var game = activeGames[gamblerId];
|
var game = ActiveGames[gamblerId];
|
||||||
game.lastInteracted = DateTime.UtcNow;
|
game.LastInteracted = DateTimeOffset.UtcNow;
|
||||||
if (game.lastMessage != msg)
|
if (game.LastMessage != msg)
|
||||||
{
|
{
|
||||||
await game.ResetMessage(msg);
|
await game.ResetMessage(msg);
|
||||||
}
|
}
|
||||||
@@ -302,8 +292,8 @@ public class KasinoMines : IDisposable
|
|||||||
(int r, int c) coord;
|
(int r, int c) coord;
|
||||||
while (betCoords.Count != count)//creates a list of coordinates to bet on using the coordinate bet function
|
while (betCoords.Count != count)//creates a list of coordinates to bet on using the coordinate bet function
|
||||||
{
|
{
|
||||||
coord = (Money.GetRandomNumber(game.creator, 0, game.size), Money.GetRandomNumber(game.creator, 0, game.size));
|
coord = (Money.GetRandomNumber(game.Creator, 0, game.Size), Money.GetRandomNumber(game.Creator, 0, game.Size));
|
||||||
if (!betCoords.Contains(coord) && !game.betsPlaced.Contains(coord)) betCoords.Add(coord);
|
if (!betCoords.Contains(coord) && !game.BetsPlaced.Contains(coord)) betCoords.Add(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Bet(gamblerId, betCoords, msg, cashOut);
|
return await Bet(gamblerId, betCoords, msg, cashOut);
|
||||||
@@ -312,64 +302,59 @@ public class KasinoMines : IDisposable
|
|||||||
public async Task<bool> Bet(int gamblerId, List<(int r, int c)> coords, SentMessageTrackerModel msg, bool cashOut = false)
|
public async Task<bool> Bet(int gamblerId, List<(int r, int c)> coords, SentMessageTrackerModel msg, bool cashOut = false)
|
||||||
{
|
{
|
||||||
await GetSavedGames();
|
await GetSavedGames();
|
||||||
var game = activeGames[gamblerId];
|
var game = ActiveGames[gamblerId];
|
||||||
game.lastInteracted = DateTime.UtcNow;
|
game.LastInteracted = DateTimeOffset.UtcNow;
|
||||||
if (game.lastMessage != msg)
|
if (game.LastMessage != msg)
|
||||||
{
|
{
|
||||||
await game.ResetMessage(msg);
|
await game.ResetMessage(msg);
|
||||||
}
|
}
|
||||||
foreach (var coord in coords) //the main portion of the game
|
foreach (var coord in coords) //the main portion of the game
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
if (game.minesBoard[coord.r, coord.c] == 'M')
|
if (game.MinesBoard[coord.r, coord.c] == 'M')
|
||||||
{
|
{
|
||||||
game.betsPlaced.Add(coord);
|
game.BetsPlaced.Add(coord);
|
||||||
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
||||||
game.Explode((coord.r, coord.c), msg);
|
game.Explode((coord.r, coord.c), msg);
|
||||||
var newBalance = await Money.NewWagerAsync(game.creator.Id, game.wager, -game.wager, WagerGame.Mines);
|
var newBalance = await Money.NewWagerAsync(game.Creator.Id, game.Wager, -game.Wager, WagerGame.Mines);
|
||||||
await _kfChatBot.SendChatMessageAsync(
|
await _kfChatBot.SendChatMessageAsync(
|
||||||
$"{game.creator.User.FormatUsername()}, you lost your {game.wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.betsPlaced.Count} gems until you hit one of {game.mines} mines. Net: {(-game.wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}",
|
$"{game.Creator.User.FormatUsername()}, you lost your {game.Wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.BetsPlaced.Count} gems until you hit one of {game.Mines} mines. Net: {(-game.Wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}",
|
||||||
true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
await RemoveGame(gamblerId);
|
await RemoveGame(gamblerId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Money.GetRandomNumber(game.creator, 0, 100) < 100 * HOUSE_EDGE)//if you didn't lose, check to see if the switch was flipped
|
if (Money.GetRandomNumber(game.Creator, 0, 100) < 100 * HOUSE_EDGE)//if you didn't lose, check to see if the switch was flipped
|
||||||
{
|
{
|
||||||
game.betsPlaced.Add(coord);
|
game.BetsPlaced.Add(coord);
|
||||||
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
||||||
await game.RigBoard(coord);
|
await game.RigBoard(coord);
|
||||||
await Task.Delay(50);
|
await Task.Delay(50);
|
||||||
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
||||||
game.Explode(coord, msg);
|
game.Explode(coord, msg);
|
||||||
var newBalance = await Money.NewWagerAsync(game.creator.Id, game.wager, -game.wager, WagerGame.Mines);
|
var newBalance = await Money.NewWagerAsync(game.Creator.Id, game.Wager, -game.Wager, WagerGame.Mines);
|
||||||
await _kfChatBot.SendChatMessageAsync(
|
await _kfChatBot.SendChatMessageAsync(
|
||||||
$"{game.creator.User.FormatUsername()}, you lost your {game.wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.betsPlaced.Count} gems until you hit one of {game.mines} mines. Net: {(-game.wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}",
|
$"{game.Creator.User.FormatUsername()}, you lost your {game.Wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.BetsPlaced.Count} gems until you hit one of {game.Mines} mines. Net: {(-game.Wager).FormatKasinoCurrencyAsync()}. Balance: {newBalance.FormatKasinoCurrencyAsync()}",
|
||||||
true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
game.betsPlaced.Add(coord);
|
game.BetsPlaced.Add(coord);
|
||||||
}
|
}
|
||||||
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageId!.Value, game.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
activeGames[gamblerId] = game;
|
ActiveGames[gamblerId] = game;
|
||||||
if (cashOut) await Cashout(game);
|
if (cashOut) await Cashout(game);
|
||||||
else await SaveActiveGames();
|
else await SaveActiveGames();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInitialized()
|
|
||||||
{
|
|
||||||
return _redisDb != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateGame(GamblerDbModel gambler, decimal bet, int size, int mines)
|
public async Task CreateGame(GamblerDbModel gambler, decimal bet, int size, int mines)
|
||||||
{
|
{
|
||||||
await GetSavedGames();
|
await GetSavedGames();
|
||||||
activeGames?.Add(gambler.Id, new KasinoMinesGame(gambler, bet, size, mines));
|
ActiveGames?.Add(gambler.Id, new KasinoMinesGame(gambler, bet, size, mines));
|
||||||
await SaveActiveGames();
|
await SaveActiveGames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user