110,534
社区成员
发帖
与我相关
我的任务
分享
using System;
using System.Collections.Generic;
using System.Text;
using ProcessMemoryReaderLib;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.ComponentModel;
namespace ProcessMemoryReaderLib
{
// 进程内存读取器
class ProcessMemoryReader:IDisposable
{
// 进程句柄
IntPtr m_hProcess;
// 读出指定内存区域
public byte[] ReadProcessMemory(IntPtr MemoryAddress, uint bytesToRead, out int bytesReaded)
{
byte[] buffer = new byte[bytesToRead];
IntPtr ptrBytesReaded;
API.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, bytesToRead, out ptrBytesReaded);
bytesReaded = ptrBytesReaded.ToInt32();
return buffer;
}
// 初始化进程句柄
public ProcessMemoryReader(string processName, string fileName)
{
Process myProcess=null;
Process[] myProcesses = Process.GetProcessesByName(processName);
if (myProcesses.Length == 1)
myProcess = myProcesses[0];
else if (myProcesses.Length == 0)
{
myProcess = new Process();
myProcess.StartInfo.FileName = fileName;
try
{
myProcess.Start();
myProcess.WaitForInputIdle();
}
catch (Win32Exception e)
{
if (e.NativeErrorCode == 2)
Console.WriteLine(@"找不到文件{0},请重新安装{1}程序。", fileName,processName);
throw e;
}
}
else
do
{
for (int i = 0; i < myProcesses.Length; i++)
{
Console.Write("程序{0,2}/{1,-2}:\"{2,20}\".\n您想要这个吗?(Y/N):", i + 1, myProcesses.Length, myProcesses[i].MainWindowTitle);
string answer = Console.ReadLine();
if (answer.ToUpper() == "Y")
{
myProcess = myProcesses[i];
break;
}
}
} while (myProcess == null);
m_hProcess = API.OpenProcess(0x10U, 1, (uint)myProcess.Id);
}
// 释放句柄
public void Dispose()
{
int iRetValue;
iRetValue = API.CloseHandle(m_hProcess);
if (iRetValue == 0)
throw new Exception("CloseHandle failed");
}
// 嵌套类,包装进程内存读取器ProcessMemoryReader所需的API
static class API
{
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
}
}
}
namespace FreecellHelper
{
// 封装牌局数据和相关方法的类
class FreeCell
{
const int MAXPOS = 21;
const int MAXCOL = 9; // includes top row as column 0
const int EMPTY = -1;
int gameNumber;
int[,] card = new int[MAXCOL, MAXPOS]; // current layout of cards, CARDs are ints
public FreeCell(int gameNumber)
{
if (gameNumber >= 1 && gameNumber <= 1000000)
Shuffle(gameNumber);
else
ReadMemory();
}
// 洗牌
void Shuffle(int gameNumber)
{
int wLeft = 52; // cards left to be chosen in shuffle
int[] deck = new int[52]; // deck of 52 unique cards
for (int col = 0; col < MAXCOL; col++) // clear the deck
for (int pos = 0; pos < MAXPOS; pos++)
card[col, pos] = EMPTY;
/* shuffle cards */
for (int i = 0; i < 52; i++) // put unique card in each deck loc.
deck[i] = i;
long holdrand = gameNumber; // gamenumber is seed for rand()
for (int i = 0; i < 52; i++)
{
// 实际上这句大部分是MFC的rand()源码,在.net中的Random和rand()不一样。
int j = (int)(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff) % wLeft;
card[(i % 8) + 1, i / 8] = deck[j];
deck[j] = deck[--wLeft];
}
this.gameNumber = gameNumber;
}
// 读内存
void ReadMemory()
{
string processName = "FreeCell";
string fileName = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\freecell.exe";
int bytesReaded;
byte[] memory;
using (ProcessMemoryReader pReader = new ProcessMemoryReader(processName, fileName))
{
memory = pReader.ReadProcessMemory((IntPtr)0x1000000, 0xE000U, out bytesReaded);
int startIndex = 0x7500;
for (int col = 0; col < MAXCOL; col++)
for (int pos = 0; pos < MAXPOS; pos++, startIndex += 4)
card[col, pos] = BitConverter.ToInt32(memory, startIndex);
this.gameNumber = BitConverter.ToInt32(memory, 0x834C);
}
}
// 用字符串表达当前牌局
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(string.Format("\t\t\t 空当接龙游戏 #{0}\n Free Cell->", gameNumber == 0 ? "尚未开局" : gameNumber.ToString()));
for (int pos = 0; pos < 8; pos++)
sb.Append(GetPatternString(card[0, pos]));
sb.Append(" <-Fixed Card\n\n");
for (int pos = 0; pos < MAXPOS; pos++) // display the card
{
sb.Append("\t ");
bool stop = true;
for (int col = 1; col < MAXCOL; col++)
{
int theCard = card[col, pos];
if (stop && theCard != EMPTY) stop = false;
sb.Append(GetPatternString(card[col, pos]));
}
if (stop) break;
sb.Append('\n');
}
sb.Append("\r\t ---------------------------------------------\n");
return sb.ToString();
}
// 根据牌的数值返回字符串形式的样子,ToString()的辅助方法
string GetPatternString(int theCard)
{
string[] value = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
string suit = "";
return theCard == EMPTY ? " " : string.Format("{0,4}{1,2}", suit[theCard % 4], value[theCard / 4]);
}
}
class Program
{
static void Main()
{
Console.WriteLine(@"
说明:
输入 0 等微软没有的牌局号可以读内存中的现有牌局。
如果没开空当接龙,会尝试自动打开空当接龙。
如果同时开着多个空当接龙程序,会提示选择。
输入 1 到 1000000 可以按照微软的算法生成牌局。
直接按回车或输入非 Int32 的值可以退出。");
while (true)
{
Console.Write("请输入您的选择:");
int result;
bool stop = !int.TryParse(Console.ReadLine(), out result);
if (stop) break;
Console.WriteLine(new FreeCell(result));
}
}
}
}
void Crack(Stack<int[,]> Cards)
{
// 空盘代表胜利
// 判断右上是否四个K就知道是否胜利
// 检验是否重复牌局
// 即和牌局堆栈一一比较
// 检验通过后
// 寻找当前牌局可以挪的牌(只剩一张的列、左上、每排最前一张)挪动
// 检验没通过
// 证明上一步是导致重复的禁步,应当撤销。
// 重复牌局、无可挪牌、可挪牌都试过,就会执行到这。
// 清除牌局堆栈最顶上一层,返回
}