Sain jostakin päähän alkaa tekemään ohjelmaa, joka ennustaisi miinaharavan avattujen luukkujen avulla, että missä ruudussa todennäköisimmin on miina. Tällä hetkellä ohjelmaan täytyy olla kokoajan käsin syöttämässä tietoja sisään (mikä on varsin työlästä), joten olisiko mahdollista jollain tavalla lukea Microsoftin miinaharavan eri vaiheiden tietoja suoraan ohjelmaan?
Tuosta Windowsin minesweeperistä en tiedä, mutta alla olevista linkeistä saattaa olla apua itse ongelman ratkaisemiseen.
Varsinainen ongelma todennäköisyyksien laskemiseen on jo ratkaistu. Halusin vain jollain tavalla saada tiedot reaaliaikaisesti miinaharavasta tuohon ohjelmaani.
Yksinkertaisin tapa tähän lienee ottaa screenshot kyseisestä ikkunasta ja lukea siitä eri kohtien värejä ja värin perusteella päätellä mikä numero kyseisessä kohdassa on. Miinaharavassa ruudukko on tasakokoinen ja sen numerot ovat erivärisiä, joten lukeminen on toteutettavissa hyvinkin helposti.
for i = 0 to 20 ' kentän koon lukeminen on sitten toinen pulma.... for j = 0 to 20 ' Oletetaan että esimmäinen luettava kohta on kohdassa 20, 100 ' tavallisen miinaharavan ruudut ovat 16 x 16 kokoisia väri = GetColor(22 + 16 * i, 100 + 16 * j) if väri = sininen then taulu[i][j] = 1 else if väri = Vihreä then taulu[i][j] = 2 else .... next next
Eipähän todellakaan olisi tullut tuollaista mieleen. Täytyypähän kokeilla. Kiitos vinkistä :D
Edit. vielä kun keksisi, että miten screenshotteja saa kätevimmin otettua muutosten tapahtuessa...
Mitä kieltä käytät?
Tää alkuperäinen analysoija on tehty PHP:llä, mutta ajattelin koodata tämän uudelleen Pythonilla tai Javalla...
PHP:llä tuskin voi screenshottia ottaa, mutta Javalla ei ainakaan tarvitse edes ottaa sitä. Voit lukea vain tietyistä koordinaateista (?).
Moikka Triton!
tässä VB.NET-pohjalta ideoitua sälää...
' [k]väännelty SharpDevelop 3.2'lla[/k] Imports Accessibility Imports [linkki "http://www.kotisivutila.fi/neansivut/downloads/AccLayer.zip"]AccLayer[/linkki] Imports Microsoft.Win32 Imports System.Threading Imports System.Windows.Forms Public Partial Class MainForm Private Structure ClientStruct Dim [Object] As Object Dim Left As Integer Dim Top As Integer Dim Width As Integer Dim Location As Point Dim [Size] As Size Dim Height As Integer Dim Mines As Integer Dim Level As Integer End Structure 'Private Structure CellMapStruct '*** 'Dim X As Integer 'Dim y As Integer 'Dim x2 As Integer 'Dim y2 As Integer ' jne... 'End Structure Private WMINE As ClientStruct 'Private CellMap() As CellMapStruct '*** Private sKey As String = "Software\Microsoft\Winmine" Dim AccProp As Object = Nothing Public Sub New() Me.InitializeComponent() End Sub Sub MainFormLoad(sender As Object, e As EventArgs) Me.Top = 550 Me.Left = _ (Screen.PrimaryScreen.WorkingArea.Width / 2) _ - (Me.Width / 2) Dim procName As String = "winmine" Dim NotAccessible As Boolean = False Dim appFolder As String = "" If appFolder <> String.Empty Then appFolder += "\" End If KillProcess(procName) Dim fullPath As String = appFolder + procName + ".exe" StartProcess(fullPath) Thread.Sleep(200) Dim MyObject As IAccessible = _ AccLayer.Acc.GetAccessibleObjectFromHandle _ (GetProcessHandle(procName)) Try MyObject.accHitTest(1, 1) Catch ex As Exception NotAccessible = True End Try If NotAccessible Then MsgBox("SHIT! It doesn't Work") Exit Sub End If Dim Children As Object = _ AccLayer.Acc.GetAccessibleChildren(MyObject) Dim MyChild As Object = Nothing For i As Integer = 0 To Children.GetUpperBound(0) If Children(i).accName = MyObject.accName Then MyChild = Children(i): Exit For End If Next If Not MyChild Is Nothing Then AccProp = New AccPropertySet(MyChild) WMINE.[Object] = MyChild AccProp = Nothing: MyChild = Nothing timer1.Interval = 250 timer1.Start End If MyObject = Nothing End Sub Sub StartProcess(ByVal fullPath As String) Dim sInfo As New ProcessStartInfo With sInfo .FileName = fullPath .WindowStyle = ProcessWindowStyle.Normal End With Dim proc As New Process With proc .StartInfo = sInfo .Start End With End Sub Sub KillProcess(ByVal AppName As String) Dim procs() As Process = Process.GetProcesses() For Each proc As Process In procs With proc If .ProcessName.ToLower _ = AppName.ToLower Then .Kill End If End With Next procs = Nothing End Sub Function IsRunningProcess(ByVal AppName As String) As Boolean Dim procs() As Process = Process.GetProcesses() For Each proc As Process In procs With proc If .ProcessName.ToLower _ = AppName.ToLower Then Return True procs = Nothing Exit Function End If End With Next procs = Nothing Return False End Function Function GetProcessHandle(ByVal AppName As String) As Object Dim procs() As Process = Process.GetProcesses() For Each proc As Process In procs With proc If .ProcessName.ToLower _ = AppName.ToLower Then Return .MainWindowHandle procs = Nothing Exit Function End If End With Next procs = Nothing Return Nothing End Function Sub Timer1Tick(sender As Object, e As EventArgs) Timer1.Stop If Not IsRunningProcess("winmine") Then MsgBox("SHIT! MineSweeper is not running...") Me.Close End If Try AccProp = New AccPropertySet(WMINE.[Object]) WMINE.Left = AccProp.Location.Left WMINE.Top = AccProp.Location.Top WMINE.Width = AccProp.Location.Width _ - AccProp.Location.X WMINE.Height = AccProp.Location.Height _ - AccProp.Location.Y WMINE.[Size] = New Size(WMINE.Width,WMINE.Height) WMINE.Location = New Point( _ AccProp.Location.X, AccProp.Location.Y) WMINE.Mines = GetRegistryValue("Mines") WMINE.Level = GetRegistryValue("Difficulty") Catch ex As Exception MsgBox("SHIT! Can't connect to object...") Me.Close End Try Try Using bmp As New Bitmap(WMINE.Width, WMINE.Height) Using g As Graphics = Graphics.FromImage(bmp) g.CopyFromScreen(New Point(WMINE.Left, _ WMINE.Top), New Point(0, 0), WMINE.[Size]) ' tähän kohtaan voi sitten aivan itse rakennella ' toiminnon, jolla kartoittaa solualueet kuvasta '(bmp) jotta pääsee vertailemaan kuvan solualueiden ' mahdollisia värityksen muutoksia, tyyliin ... ' Dim LevelTag As Integer ' If LevelTag <> WMINE.Level Then ' Select Case WMINE.Level ' Case 1 ' Redim Preserve CellMap( _ ' tämän_tason_solujen_määrä) '*** ' Case 2 'jne.. ' Case 3 'jne.. ' End Select 'For i As Integer = 0 To CellMap.GetUpperBound(0) 'CellMap(i).x = x.piste kuvasta bmp ' jne... 'Next 'LevelTag = WMINE.Level 'End If 'For i As Integer = 0 To CellMap.GetUpprBound(0) 'If bmp.GetPixel(CellMap(i).x, _ 'CellMap(i).y).ToArgb <> Color.Gray.ToArgb Then 'esim. ' Do something... 'End If 'Next End Using End Using Catch ex As Exception MsgBox("SHIT! It doesn't work") End Try Timer1.Start End Sub Function GetRegistryValue( _ ByVal sKeyName As String) As Object Dim reg As RegistryKey Dim strTemp As String = String.Empty reg = Registry.CurrentUser.OpenSubKey(sKey) reg.OpenSubKey(sKeyName) If Not (reg Is Nothing) Then Return reg.GetValue(sKeyName) Else Return Nothing End If reg.Close() End Function Sub MainFormFormClosing(sender As Object, e As FormClosingEventArgs) KillProcess("winmine") WMINE = Nothing Me.Dispose End Sub Sub MainFormFormClosed(sender As Object, e As FormClosedEventArgs) End End Sub End Class
Kiitos, täytynee tutkia tätä mahd. pian.
Moikka taas Triton!
Halutessasi voit impata täältä edellistä hieman pidemmälle ideoidun viritelmän sorsat tutkittavaksesi
Nyt täytyy enää jostain repästä VB, niin homma lähtee skulaa ;D
Mikkisoftan sivuilta VB:net 2008 express edition.
Moikka taas Triton!
Kokeile VB:net 2008 express'n asemesta SharpDevelop 3.2'ta, on hieman kevyempi...
muille.kiinnostuneille@:
edellisessä viestissäni näkyvä linkki on nyt poissa pelistä, mutta täältä voi impata MineSweeperSpy.dll kirjaston asennusohjeineen + VB.NET testiprojektin, jolla selviää .dll'n käyttö
Itsekin innostuin koodailemaan tällasen, joka lukee pelikentän datan suoraan minesweeper.exe:n muistista. Miinuksena jo esitettyyn "kuvatapaan" on se, että tämä joudutaan päivittämään jokaista minesweeper-versiota varten. Plussana se, että saadaan suoraan selville missä ruudussa on miina ja missä ei. Moi.
edit. tuli kiire. Unohtui sorsa ja mainita, että toimii jossain vistoissa ja seiskoissa. Tästä voi vielä ladata itse pelin.
edit2. jotain hauskaa xp:n miinaharavasta: Minesweeper, Behind the scenes
Heippa taas!
tässä vielä VB.NET-sovitus tosta Deffi'n xp:n miinaharava linkin takaa löytyvästä viritelmästä
Deffi kirjoitti:
Plussana se, että saadaan suoraan selville missä ruudussa on miina ja missä ei.
Tuohan on suoranaista huijaamista :D
Triton kirjoitti:
Tuohan on suoranaista huijaamista :D
Minusta ei ole kiinnostavaa ratkaista algoritmisesti suhteellisen yksinkertaista ongelmaa, joka usein lopulta päättyy kuitenkin arvaamiseen. Deffin ratkaisu on siitä erinomainen, että se poistaa pelistä satunnaiskomponentin. :)
Se satunnaisuus tekee miinaharavasta jännittävän. :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.