Skip to content

Instantly share code, notes, and snippets.

@rdavisau
Last active March 4, 2022 20:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rdavisau/b6e23ca79fe12b54de4e to your computer and use it in GitHub Desktop.
Save rdavisau/b6e23ca79fe12b54de4e to your computer and use it in GitHub Desktop.
<Query Kind="Program">
<Reference>&lt;RuntimeDirectory&gt;\System.Windows.Forms.dll</Reference>
<Reference>&lt;RuntimeDirectory&gt;\System.Security.dll</Reference>
<Reference>&lt;RuntimeDirectory&gt;\System.Configuration.dll</Reference>
<Reference>&lt;RuntimeDirectory&gt;\Accessibility.dll</Reference>
<Reference>&lt;RuntimeDirectory&gt;\System.Runtime.Serialization.Formatters.Soap.dll</Reference>
<Reference>&lt;RuntimeDirectory&gt;\System.Deployment.dll</Reference>
<NuGetReference>DynamicLINQ</NuGetReference>
<NuGetReference>DynamicQuery</NuGetReference>
<NuGetReference>Newtonsoft.Json</NuGetReference>
<NuGetReference>Rx-Main</NuGetReference>
<Namespace>System.Diagnostics</Namespace>
<Namespace>System.Drawing</Namespace>
<Namespace>System.Drawing.Imaging</Namespace>
<Namespace>System.Reactive</Namespace>
<Namespace>System.Reactive.Linq</Namespace>
<Namespace>System.Reactive.Subjects</Namespace>
<Namespace>System.Runtime.InteropServices</Namespace>
<Namespace>System.Windows.Forms</Namespace>
<Namespace>Newtonsoft.Json</Namespace>
<Namespace>System.Threading.Tasks</Namespace>
</Query>
/*
INSTRUCTIONS:
1. open chrome, get the dinosaur 'no internet' page happening
2. we need to tell the script where the dinosaur is; we use a highly technical approach -
putting the mouse just behind the bottom left* of the dinosaur and then pressing enter in LINQPad.
when the first if statement is `if (true)`, the script waits for you to press enter in the readline box and takes
the current cursor position. so the approach is
- press play on LINQPad, click inside the readline box
- move your cursor to the correct position behind the dinosaur
- press enter
that mouse position is saved so for as long as you don't move the chrome window you can change `if (true)` to `if (false)`
and it will keep using the old position. alternatively, experiment with different positions to improve the dinosaur's performance
3. that's pretty much it - once location is set the script will press space when it 'thinks' there's a threat nearby
4. it's not a very smart script
note: doesn't work with font scaling - i guess the dimensions change. some of the nugets/references probably aren't needed
* i 'think' it's the bottom left - if the boundaries around the dinosaur look like this, it is correct: http://i.imgur.com/choOOMU.png
*/
[DllImport("user32.dll")]
static extern bool GetCursorPos(ref Point lpPoint);
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
async void Main()
{
Point monitorLocation = new Point();
if (true)
{
Console.ReadLine();
GetCursorPos(ref monitorLocation);
File.WriteAllText("cursor.txt", JsonConvert.SerializeObject(monitorLocation));
}
else monitorLocation = JsonConvert.DeserializeObject<Point>(File.ReadAllText("cursor.txt"));
var bounds = new {
TopPoint = new Point(monitorLocation.X, monitorLocation.Y - 150),
ZeroPoint = new Point(0,0),
Size = new Size(600,150),
};
var barrierPoint = new {
Top = new Point(65,bounds.Size.Height),
Bottom = new Point(65, bounds.Size.Height-50)
};
var groundPoint = new {
Start = new Point(0, bounds.Size.Height - 15),
End = new Point(bounds.Size.Width, bounds.Size.Height - 15)
};
var topOfDinoPoint = new {
Start = new Point(0, bounds.Size.Height - 50),
End = new Point(bounds.Size.Width, bounds.Size.Height - 50)
};
var centerOfDino = new Point(barrierPoint.Top.X - 15 , barrierPoint.Top.Y + ((barrierPoint.Bottom.Y - barrierPoint.Top.Y)/2) - 17 );
var cactusColor = ColorTranslator.FromHtml("#535353");
var content = new DumpContainer();
var stats = new { DinoCam = content, CURRENT_STATUS = new DumpContainer(), DistanceToThreat = new DumpContainer() }.Dump(); // , ThreatWidth = new DumpContainer()}.Dump();
var p = new Pen(Color.Green, 1f);
var redP = new Pen(Color.Red) { DashPattern = new [] { 2.0f, 2.0f } };
var alphaRedP = new SolidBrush(Color.FromArgb(150, Color.Red));
var distanceToSearch = 400 ;
var minY = topOfDinoPoint.Start.Y;
var maxY = groundPoint.Start.Y;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Bitmap b = null;
var needToJump = false; var actionString = "CHILLING"; var distToThreatString = "ALL CLEAR BABY"; var threatWidthString = "";
var threatWidth = 0;
var threatDistance = 0;
Action<Graphics> updateDinoCam = g =>
{
stats.CURRENT_STATUS.Content = needToJump ? "JUMPING" : "CHILLING";
stats.DistanceToThreat.Content = threatDistance == 0 ? distToThreatString : threatDistance.ToString();
g.DrawLine(p, barrierPoint.Top, barrierPoint.Bottom ); // draw dino collision point
g.DrawLine(p, groundPoint.Start, groundPoint.End); // draw ground bound
g.DrawLine(p, topOfDinoPoint.Start, topOfDinoPoint.End); // draw dino head bound
content.Content = b;
};
while (true)
{
b = new Bitmap(bounds.Size.Width, bounds.Size.Height);
using (var g = Graphics.FromImage(b))
{
g.CopyFromScreen(bounds.TopPoint, bounds.ZeroPoint, bounds.Size); // snap screen
// find the nearest cactus
var threat = Enumerable.Range(barrierPoint.Top.X, distanceToSearch)
.SelectMany(j=> Enumerable.Range(minY, maxY - minY).Select(i=> new { X = j, Y = i }))
.FirstOrDefault(pt => b.GetPixel(pt.X,pt.Y) == cactusColor);
if (threat == null) { updateDinoCam(g); continue; } // no cactus, nothing to do..
// find end of cactus
var threatPt = new Point(threat.X, threat.Y);
var lastCactusPixel =
Enumerable.Range(threat.X, 100)
.Where(x => x > 0 && x < bounds.Size.Width)
.Select(x => new { Point = new Point(x, threat.Y), IsCactus = b.GetPixel(x, threat.Y) == cactusColor })
.FirstWithLookhead(10, (pix, nextPixels) => pix.IsCactus && nextPixels.All(ppx=> !ppx.IsCactus));
threatWidth = lastCactusPixel.Point.X - threatPt.X;
threatDistance = threat.X - barrierPoint.Top.X;
// highlight threat on dinocam
g.DrawLine(redP, centerOfDino, threatPt);
g.DrawLine(redP, centerOfDino, new Point(lastCactusPixel.Point.X, lastCactusPixel.Point.Y));
g.FillRectangle(alphaRedP, new Rectangle(new Point(threatPt.X, threatPt.Y -5) , new Size(threatWidth, 10)));
// if we need to jump, Lets Do That
needToJump = IsThisTooCloseForComfort(threatWidth, threatDistance);
if (needToJump)
Keyboard.HoldKey((byte)Keys.Space, 300); // JUMP!!!!
updateDinoCam(g);
}
}
}
public bool IsThisTooCloseForComfort (int threatWidth, int distance)
{
// small cactus
if (threatWidth < 25 && (distance < 115))
return true;
else if (threatWidth < 40 && (distance < 105))
return true;
// medium cactus
else if (threatWidth < 55 && (distance < 95))
return true;
// large cactus
else if (threatWidth < 100 && (distance < 75))
return true;
return false;
}
// Define other methods and classes here
public static class Ext
{
public static T FirstWithLookhead<T>(this IEnumerable<T> items, int lookAhead, Func<T, List<T>, bool> predicate)
{
var ahead = new List<T>();
foreach (var item in items)
{
ahead.Add(item);
if (ahead.Count > lookAhead)
{
var theItem = ahead[0];
ahead.Remove(theItem);
var result = predicate(theItem, ahead);
if (result)
return theItem;
}
}
while (ahead.Count > 0)
{
var theItem = ahead[0];
ahead.Remove(theItem);
var result = predicate(theItem, ahead);
if (result)
return theItem;
}
return default(T);
}
public static T Do<T>(this T obj, Action<T> action)
{
action(obj);
return obj;
}
public static Color Dump(this Color colour, string caption = null)
{
Util.RawHtml(String.Format("<div style='text-align:center;display:block;width:20px;height:20px;background-color:#ff6600'>hi</div>"))
.Dump(caption);
return colour;
}
public static object DivForColor(this Color colour)
{
return Util.RawHtml(String.Format("<div style='text-align:center;display:block;width:20px;height:20px;background-color:{0}'></div>",
ColorTranslator.ToHtml(colour)));
}
static Bitmap screenPixel = new Bitmap(1,1, PixelFormat.Format32bppArgb);
public static Color GetColorAt(Point location)
{
using (Graphics gdest = Graphics.FromImage(screenPixel))
{
using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hSrcDC = gsrc.GetHdc();
IntPtr hDC = gdest.GetHdc();
int retval = UserQuery.BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
gdest.ReleaseHdc();
gsrc.ReleaseHdc();
}
}
return screenPixel.GetPixel(0, 0);
}
public static bool IsColorWithinRange(Color c, Point p, int range)
{
var xs = Enumerable.Range(0,range).Select(x=> p.X + x);
var ys = Enumerable.Range(range/2,(int)(range/1.5) ).Select(y=> p.Y + y);
return
xs.SelectMany(x=> ys.Select(y=> new Point(x,y)))
.Any(pt=> GetColorAt(pt) == c);
}
}
public class Keyboard
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int PauseBetweenStrokes = 50;
const int KEY_DOWN_EVENT = 0x0001; //Key down flag
const int KEY_UP_EVENT = 0x0002; //Key up flag
public static void HoldKey(byte key, int duration)
{
keybd_event(key, 0, KEY_DOWN_EVENT, 0);
Task.Delay(duration).ContinueWith(_=> keybd_event(key, 0, KEY_UP_EVENT, 0));
Task.Delay(50).Wait();
}
}
@rdavisau
Copy link
Author

rdavisau commented Jan 9, 2020

🤠

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment