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
nextEipä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 ClassKiitos, 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.