Last active
December 14, 2016 05:16
-
-
Save pigeonhands/e2b29efe81ec87d1e336 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Globalization; | |
using System.IO; | |
using System.Net; | |
using System.Runtime.Serialization.Json; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace SatoshiMines | |
{ | |
public delegate void OnException(SatoshiMinesBot sender, Exception ex); | |
public delegate void OnCheckBalance(SatoshiMinesBot sender); | |
public delegate void OnGameStart(SatoshiMinesBot sender); | |
public delegate void OnBet(SatoshiMinesBot sender, BetData bet); | |
public delegate void OnBval(SatoshiMinesBot sender); | |
public delegate void OnCashout(SatoshiMinesBot sender, CashOutData cashout); | |
/// <summary> | |
/// SatoshiMines bot class | |
/// Made by BahNahNah | |
/// </summary> | |
public class SatoshiMinesBot | |
{ | |
#region " Properties " | |
public string PlayerHash { get; set; } | |
public GameData CurrentGame { get; private set; } | |
public BetData LastBet { get; private set; } | |
public float LastCheckedBalance { get; private set; } | |
/// <summary> | |
/// The ammount to bet in bits (a millionth of a BTC) | |
/// </summary> | |
public int BetAmmount { get { return (int)(BetCostBTC * 1000000); } set { BetCostBTC = value / 1000000; } } | |
public SMines Mines { get; set; } | |
public string CurrentBDVal { get; private set; } | |
public int LastSquareBet { get; private set; } | |
public int NumberOfSquaresBet { get; private set; } | |
public int[] SequentialBombsOnSquare { get; private set; } | |
/// <summary> | |
/// Played squares are 1, and non-played squares are 0 | |
/// </summary> | |
public int[] CurrentBetGrid { get; private set; } | |
/// <summary> | |
/// Used for callabcks. Does not effect bot. | |
/// </summary> | |
public bool ShouldRun { get; set; } | |
#endregion | |
#region " Fields " | |
private HttpWebRequest _webRequest = null; | |
private Regex rgBval = new Regex("var bdval = '(\\d+)'"); | |
private CultureInfo betFormat = new CultureInfo("en-US"); | |
private double BetCostBTC = 0; | |
private Random Random = new Random(); | |
#endregion | |
#region " Events " | |
public event OnCheckBalance OnCheckBalance; | |
public event OnException OnException; | |
public event OnGameStart OnGameStart; | |
public event OnBval OnBVal; | |
public event OnBet OnBet; | |
public event OnCashout OnCashout; | |
#endregion | |
#region " Constructors " | |
public SatoshiMinesBot() | |
{ | |
SequentialBombsOnSquare = new int[25]; | |
CurrentBetGrid = new int[25]; | |
Mines = SMines.Three; | |
} | |
public SatoshiMinesBot(string _playerHash) : this() | |
{ | |
PlayerHash = _playerHash; | |
} | |
#endregion | |
#region " Public Methods " | |
public bool ValidPlayerHash() | |
{ | |
return UpdateBalance(); | |
} | |
public bool UpdateBVal() | |
{ | |
return TryGetBVal(); | |
} | |
public bool StartGame() | |
{ | |
NumberOfSquaresBet = 0; | |
return AttemptNewGame(); | |
} | |
/// <summary> | |
/// Place a bet on a square number (from 0 - 24) | |
/// </summary> | |
/// <param name="s">Square to bet on</param> | |
/// <returns></returns> | |
public bool Bet(int s) | |
{ | |
if (s > CurrentBetGrid.Length || s < 0) | |
return false; | |
LastSquareBet = s; | |
CurrentBetGrid[s] = 1; | |
return AttemptBet(s + 1); | |
} | |
public bool BetRandomSquare() | |
{ | |
if (!SquareAvalible()) | |
return false; | |
int s = Random.Next(0, 25); | |
while (CurrentBetGrid[s] != 0) | |
s = Random.Next(0, 25); | |
return Bet(s); | |
} | |
/// <summary> | |
/// Returns true if there is a square that has not been bet on | |
/// </summary> | |
/// <returns></returns> | |
public bool SquareAvalible() | |
{ | |
bool sq = false; | |
lock (this) | |
{ | |
foreach (int i in CurrentBetGrid) | |
{ | |
if (i == 0) | |
{ | |
sq = true; | |
break; | |
} | |
} | |
} | |
return sq; | |
} | |
public bool Cashout() | |
{ | |
return AttemptCashout(); | |
} | |
public bool UpdateBalance() | |
{ | |
try | |
{ | |
if (string.IsNullOrWhiteSpace(PlayerHash)) | |
return false; | |
string resp = string.Empty; | |
using (WebClient wc = new WebClient()) | |
{ | |
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; | |
resp = wc.UploadString(new Uri("https://satoshimines.com/action/refresh_balance.php"), "POST", string.Format("secret={0}", PlayerHash)); | |
} | |
BalanceData b = Deserialize<BalanceData>(resp); | |
if (b.status == "error") | |
return false; | |
LastCheckedBalance = b.balance; | |
OnCheckBalance?.Invoke(this); | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
return false; | |
} | |
} | |
#endregion | |
#region " Private Methods " | |
private bool AttemptNewGame() | |
{ | |
try | |
{ | |
_webRequest = (HttpWebRequest)WebRequest.Create("https://satoshimines.com/action/newgame.php"); | |
UploadPost(NewGameCallback, "player_hash={0}&bet={1}&num_mines={2}", PlayerHash, BetCostBTC.ToString("0.000000", betFormat), (int)Mines); | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
return false; | |
} | |
} | |
private bool AttemptBet(int square) | |
{ | |
try | |
{ | |
_webRequest = (HttpWebRequest)WebRequest.Create("https://satoshimines.com/action/checkboard.php"); | |
UploadPost(PlaceBetCallback, "game_hash={0}&guess={1}&v04=1", CurrentGame.game_hash, square); | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
return false; | |
} | |
} | |
private bool AttemptCashout() | |
{ | |
try | |
{ | |
_webRequest = (HttpWebRequest)WebRequest.Create("https://satoshimines.com/action/cashout.php"); | |
UploadPost(CashoutCallback, "game_hash={0}", CurrentGame.game_hash); | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
return false; | |
} | |
} | |
private bool TryGetBVal() | |
{ | |
try | |
{ | |
using (WebClient bvalRequest = new WebClient()) | |
{ | |
bvalRequest.DownloadStringCompleted += BvalRequest_DownloadStringCompleted; | |
bvalRequest.DownloadStringTaskAsync(string.Format("https://www.satoshimines.com/play/{0}", PlayerHash)); | |
} | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
return false; | |
} | |
} | |
private void UploadPost(AsyncCallback after, string postString, params object[] args) | |
{ | |
byte[] post = Encoding.UTF8.GetBytes(string.Format(postString + "&bd=" + CurrentBDVal, args)); | |
_webRequest.ContentLength = post.Length; | |
_webRequest.Method = "POST"; | |
_webRequest.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; | |
_webRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.132 Safari/537.36"; | |
_webRequest.BeginGetRequestStream((AR) => OnRequestStream(AR, post, after), null); | |
} | |
#endregion | |
#region " Callbacks " | |
private void OnRequestStream(IAsyncResult AR, byte[] post, AsyncCallback after) | |
{ | |
using (Stream s = _webRequest.EndGetRequestStream(AR)) | |
{ | |
s.Write(post, 0, post.Length); | |
s.Flush(); | |
} | |
_webRequest.BeginGetResponse(after, null); | |
} | |
private void NewGameCallback(IAsyncResult AR) | |
{ | |
try | |
{ | |
HttpWebResponse _response = (HttpWebResponse)_webRequest.EndGetResponse(AR); | |
CurrentGame = Deserialize<GameData>(_response.GetResponseStream()); | |
if (CurrentGame == null) | |
throw new Exception("Deserialize failed, object is null."); | |
if (CurrentGame.status != "success") | |
throw new Exception("Json Error: " + CurrentGame.message); | |
OnGameStart?.Invoke(this); | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
} | |
} | |
private void PlaceBetCallback(IAsyncResult AR) | |
{ | |
try | |
{ | |
LastBet = Deserialize<BetData>(_webRequest.EndGetResponse(AR).GetResponseStream()); | |
if (LastBet == null) | |
throw new Exception("Failed to parse bet responce."); | |
if (LastBet.status != "success") | |
throw new Exception("Bet Error: " + LastBet.message); | |
NumberOfSquaresBet++; | |
OnBet?.Invoke(this, LastBet); | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
} | |
} | |
private void CashoutCallback(IAsyncResult AR) | |
{ | |
try | |
{ | |
CashOutData cashout = Deserialize<CashOutData>(_webRequest.EndGetResponse(AR).GetResponseStream()); | |
OnCashout?.Invoke(this, cashout); | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
} | |
} | |
private void BvalRequest_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) | |
{ | |
try | |
{ | |
string reqVal = e.Result; | |
Match bdMatch = rgBval.Match(reqVal); | |
if (!bdMatch.Success) | |
throw new Exception("Regex failed to match bdvalue."); | |
CurrentBDVal = bdMatch.Groups[1].Value; | |
if (string.IsNullOrWhiteSpace(CurrentBDVal)) | |
throw new Exception("Invalid bdvalue."); | |
OnBVal?.Invoke(this); | |
} | |
catch (Exception ex) | |
{ | |
OnException?.Invoke(this, ex); | |
} | |
} | |
#endregion | |
#region " Deseralization " | |
private static T Deserialize<T>(string json) | |
{ | |
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) | |
{ | |
return Deserialize<T>(ms); | |
} | |
} | |
private static T Deserialize<T>(Stream ds) | |
{ | |
var s = new DataContractJsonSerializer(typeof(T)); | |
return (T)s.ReadObject(ds); | |
} | |
#endregion | |
} | |
#region " Data Structures " | |
public class BalanceData | |
{ | |
public string status { get; set; } | |
public float balance { get; set; } | |
} | |
public class BetData | |
{ | |
public string status { get; set; } | |
public int guess { get; set; } | |
public string outcome { get; set; } | |
public double stake { get; set; } | |
public double next { get; set; } | |
public string message { get; set; } | |
public double change { get; set; } | |
public string bombs { get; set; } | |
} | |
public class CashOutData | |
{ | |
public string status { get; set; } | |
public double win { get; set; } | |
public string mines { get; set; } | |
public string message { get; set; } | |
public string random_string { get; set; } | |
public string game_id { get; set; } | |
} | |
public class GameData | |
{ | |
public string status { get; set; } | |
public int id { get; set; } | |
public string game_hash { get; set; } | |
public string secret { get; set; } | |
public string bet { get; set; } | |
public string stake { get; set; } | |
public string next { get; set; } | |
public string betNumber { get; set; } | |
public string gametype { get; set; } | |
public int num_mines { get; set; } | |
public string message { get; set; } | |
} | |
#endregion | |
public enum SMines | |
{ | |
One = 1, | |
Three = 3, | |
Five = 5, | |
TwentyFour = 24 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment