1

Тема: AHK: игра «Жизнь» [Life]

Игра Life. Набросал на досуге. Т.к. нет опыта работы в Gdip, сделал на контролах.
Суть игры заключается в изменении клетки в зависимости от соседних.
Если соседей меньше 2-х или больше 3-х, клетка умирает
Если соседей 2 или 3, клетка не изменяется
Если соседей 3 и клетка пустая, клетка рождается

; ---------------------------------------------------- Переменные
Title = Life
w := 20, x := 5, y := 5
Col = 10 ; количество столбцов
Str = 10 ; количество строк
Fishka = O ; знак на кнопке
; ---------------------------------------------------- Gui, Show
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
    }
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, x5 y%y% gПуск, Пуск
Gui, Add, Button, x+5 gОчистить, Очистить
Gui, Add, Button, x+5 gСтоп, Стоп
Gui, Show, x500 y300 , %Title%
Return ; ---------------------------------------------------- Пуск
Пуск:
Loop { ; бесконечный цикл
n1 := 0, Butt := 0, _Butt = 0 ; очистка переменных
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        Butt += 1 ; счетчик для контролов
        ControlGetText, TextB, Button%Butt%, %Title% ; получаем текст контрола
        If TextB = %Fishka% ; если метка присутствует
            {            
            Gosub ПроверкаСоседей
            _%A%_%B% := n = 2 OR n = 3 ; присваиваем в массив 1 если условие выполняется и 0 если нет
            If _%A%_%B% = 0 ; если изменения есть, присваиваем метку
                n1 = 1
            }
        Else ; если организм отсутствует
            {
            Gosub ПроверкаСоседей
            _%A%_%B% := n = 3 ; присваиваем в массив 1 если условие выполняется и 0 если нет
            If _%A%_%B% = 1 ; если изменения есть, присваиваем метку 
                n1 = 1    
            }
        n = 0 ; очистка счетчика количества соседей        
    } }
If     (n1 = 0 or n2 = 0)  ; если изменений нет или нажата клавиша "Стоп", завершаем работу
    {
    MsgBox % "Поколений:" A_index - 1 ; %
    n2 = 1 ; восстанавливаем счетчик
    Break    
    }
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        var := _%A%_%A_Index% = 1 ? Fishka : ; если метка изменения есть, присваиваем метку
        GuiControl,, %A%_%A_Index%, %var% ; изменяем контрол
        } } 
    }
Return ; ---------------------------------------------------- ПроверкаСоседей
ПроверкаСоседей:    
_Butt := Butt - Str - 1 ; получаем верхний слева номер контрола
V := mod(Butt,Col) ; возвращает остаток от деления
Loop 3 { ; проверка верхнего ряда
        If NOT (A = 1 or _Butt <= 0) ; если строка не первая
            If NOT (V = 0 and A_Index = 3) ; если столбец не последний и цикл не 3
                If NOT (V = 1 and A_Index = 1) ; если столбец не первый и цикл не 1
                    Gosub ControlGet
        _Butt += 1 ; увеличиваем номер контрола
    }
_Butt := Butt - 1 ; получаем слева номер контрола
If V <> 1 ; если столбец не крайний слева...
    Gosub ControlGet
_Butt := Butt + 1 ; получаем справа номер контрола
If V <> 0 ; если столбец не крайний справа...
    Gosub ControlGet
_Butt := Butt + Str - 1 ; получаем нижний слева номер контрола
Loop 3 { ; проверка нижнего ряда
    If NOT (A = Str OR V = 0 and A_Index = 3 OR V = 1 and A_Index = 1) ; если столбец не последний или остаток не 0 (столбец не правый) и цикл не 3 или столбец не левый и индекс не 1
        Gosub ControlGet    
    _Butt += 1 ; увеличиваем номер контрола    
    }    
Return ; ---------------------------------------------------- ControlGet
ControlGet:
ControlGetText, Text_B, Button%_Butt%, %Title% ; получаем текст контрола
If Text_B = %Fishka%
    n += 1 ; счетчик соседей    
Return ; ---------------------------------------------------- Button
Button:
StringSplit, D, A_GuiControl, _ ; парсим
A := D1, B := D2 ; получаем номер столбца
MouseGetPos, , , , VarControl ; получаем имя контрола
ControlGetText, TextB, %VarControl%, %Title% ; получаем текст контрола
If TextB = %Fishka% ; если метка уже есть
    GuiControl,, %A%_%B%, ; изменяем контрол
Else ; если метки нет
    GuiControl,, %A%_%B%, %Fishka% ; изменяем контрол
Return ; ---------------------------------------------------- Стоп
Стоп:
n2 = 0
Return ; ---------------------------------------------------- Очистить
Очистить:
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControl,, %A%_%B% ; изменяем контрол
    } }
Return

2

Re: AHK: игра «Жизнь» [Life]

Раз уж это игра, поясните: как в ней можно выиграть или проиграть?

3

Re: AHK: игра «Жизнь» [Life]

ypppu, в неё можно играть.

4

Re: AHK: игра «Жизнь» [Life]

alexii пишет:

ypppu, в неё можно играть.

КАК? Это похоже на опыт или моделирование, но не стоит задача достигнуть какой-либо цели:

Суть игры заключается в изменении клетки в зависимости от соседних.

Если было бы сказано "Найти комбинацию, при которой число поколений было бы максимальным" или ещё что-нибудь... Лично мне попалась комбинация, при которой жизнь оказалась бесконечной.

5

Re: AHK: игра «Жизнь» [Life]

Неужто не разу не слыхали: Жизнь (игра) — Википедия? Помнится, даже тут её как-то обсуждали.

6

Re: AHK: игра «Жизнь» [Life]

Да, не слыхал.

wikipedia пишет:

Конвей первоначально предположил, что никакая начальная комбинация не может привести к неограниченному размножению и предложил премию в 50 долларов тому, кто докажет или опровергнет эту гипотезу.

Теперь вроде понятно.
Вношу предложение считать Zohann разработчиком!

7

Re: AHK: игра «Жизнь» [Life]

Интересная разработка:) Согласен.

8

Re: AHK: игра «Жизнь» [Life]

ypppu пишет:

Вношу предложение считать Zohann разработчиком!

Есть небольшие замечания. При закрытии окна скрипт должен завершаться. Кроме того, попробуйте увеличить размер поля до, скажем, 15х15 — игра сразу начнёт тормозить. Возможно, алгоритм неидеален. Во всяком случае, в начало скрипта стоит добавить

SetBatchLines, -1

для ускорения. Нехватает также возможности проходить поколения пошагово.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: игра «Жизнь» [Life]

Ещё косяк обнаружил. Попробуйте задать разные значения для строк и столбцов. Да, алгоритм точно неидеален!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

10

Re: AHK: игра «Жизнь» [Life]

Хорошо, достану скрипт из закромов) и поправлю насколько это возможно. Вообще хотел научиться работать с библиотекой Gdip, да туториал уж шибко сложный, на русском бы осилил еще. Поэтому и возникла мысля использовать Button как клетки поля).

11

Re: AHK: игра «Жизнь» [Life]

Меня заинтересовала тема! Напишу через GDI+, поделюсь!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: игра «Жизнь» [Life]

Zohann пишет:

Хорошо, достану скрипт из закромов) и поправлю насколько это возможно. Вообще хотел научиться работать с библиотекой Gdip, да туториал уж шибко сложный, на русском бы осилил еще. Поэтому и возникла мысля использовать Button как клетки поля).

Тут проблема не в технологии, а в алгоритме. Позже конкретизирую.

13

Re: AHK: игра «Жизнь» [Life]

Рациональный алгоритм по ссылке в Википедии описан, мне, вроде, удалось уже реализовать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14 (изменено: Zohann, 2011-11-17 10:25:53)

Re: AHK: игра «Жизнь» [Life]

Цикл изменен на таймер
+Ползунок скорости
+Счетчик поколений
+Возможность изменять кол-во строк и столбцов
+Запись переменных в ini-файл
+Кнопка "Выход"

SetKeyDelay, 20
SetTitleMatchMode, 2
SetBatchLines, -1
; ---------------------------------------------------- Переменные
Title = Life
ini = %Title%.ini
Generation = 0
w := 20, x := 5, y := 65
Fishka = O ; знак на кнопке
; ---------------------------------------------------- Чтение ini
IniRead, Str, %ini%, Set, Str, 11
Col := Str
IniRead, Speed, %ini%, Set, Speed, 300
; ---------------------------------------------------- Gui, Show
Gui, Add, Text, x5 Section, Скорость
Gui, Add, Slider, ToolTip Range100-1000 Page100 x+5 y5 vSpeed gChange, %Speed%
Gui, Font, Arial cBlue s18
Gui, Add, Text, Center x+5 w30 h30, 0
Gui, Font
Gui, Add, Text, xs y+5, Строк
Gui, Add, Edit, Number x+5 w30 vStr, %Str%
Gui, Add, Text, x+5 gПрименить, Применить
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
    }
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, xs y%y% w60 gПуск, Пуск
Gui, Add, Button, x+5 wp gОчистить, Очистить
Gui, Add, Button, x+5 wp gСтоп, Стоп
Gui, Add, Button, x+5 wp gВыход, Выход
Gui, Show, x500 y300, %Title%
Return ; ---------------------------------------------------- Change
Change:
Gui, Submit, NoHide
If S = 1 ; если программа работает, меняем скорость
    SetTimer, Start, %Speed%
IniWrite, %Speed%, %ini%, Set, Speed    
Return ; ---------------------------------------------------- Применить    
Применить:
Gui, Submit, NoHide
IniWrite, %Str%, %ini%, Set, Str
Reload
Return ; ---------------------------------------------------- Пуск
Пуск:
S = 1 ; метка работы
Gui, Submit, NoHide
SetTimer, Start, %Speed%
Return ; ---------------------------------------------------- Стоп
Стоп:
S = 0 ; метка остановки
SetTimer, Start, off  ; ------------------------------------- Очистить
Return
Очистить:
If S = 1 ; если программа в работе, то выход
    Return
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControl,, %A%_%B% ; изменяем контрол
    } }
GuiControl,, static2, 0 ; очистка счетчика    
Return ; ---------------------------------------------------- Start
Start:
n1 := 0, Butt := 0, _Butt := 0 ; очистка переменных
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        Butt += 1 ; счетчик для контролов
        ControlGetText, TextB, Button%Butt%, %Title% ; получаем текст контрола
        If TextB = %Fishka% ; если метка присутствует
            {            
            Gosub ПроверкаСоседей
            _%A%_%B% := n = 2 OR n = 3 ; присваиваем в массив 1 если условие выполняется и 0 если нет
            If _%A%_%B% = 0 ; если изменения есть, присваиваем метку
                n1 = 1
            }
        Else ; если организм отсутствует
            {
            Gosub ПроверкаСоседей
            _%A%_%B% := n = 3 ; присваиваем в массив 1 если условие выполняется и 0 если нет
            If _%A%_%B% = 1 ; если изменения есть, присваиваем метку 
                n1 = 1    
            }
        n = 0 ; очистка счетчика количества соседей        
        }  }
If     n1 = 0  ; если изменений нет то завершаем работу
    {
    S = 0 ; метка остановки работы программы
    SetTimer, Start, off
    Generation = 0
    }
Else
    GuiControl,, static2, % Generation += 1 ; подсчет поколений
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        var := _%A%_%A_Index% = 1 ? Fishka : ; если метка изменения есть, присваиваем метку
        GuiControl,, %A%_%A_Index%, %var% ; изменяем контрол
        } } 
Return ; ---------------------------------------------------- ПроверкаСоседей
ПроверкаСоседей:    
_Butt := Butt - Str - 1 ; получаем верхний слева номер контрола
V := mod(Butt,Col) ; возвращает остаток от деления
Loop 3 { ; проверка верхнего ряда
        If NOT (A = 1 or _Butt <= 0) ; если строка не первая
            If NOT (V = 0 and A_Index = 3) ; если столбец не последний и цикл не 3
                If NOT (V = 1 and A_Index = 1) ; если столбец не первый и цикл не 1
                    Gosub ControlGet
        _Butt += 1 ; увеличиваем номер контрола
    }
_Butt := Butt - 1 ; получаем слева номер контрола
If V <> 1 ; если столбец не крайний слева...
    Gosub ControlGet
_Butt := Butt + 1 ; получаем справа номер контрола
If V <> 0 ; если столбец не крайний справа...
    Gosub ControlGet
_Butt := Butt + Str - 1 ; получаем нижний слева номер контрола
Loop 3 { ; проверка нижнего ряда
    If NOT (A = Str OR V = 0 and A_Index = 3 OR V = 1 and A_Index = 1) ; если столбец не последний или остаток не 0 (столбец не правый) и цикл не 3 или столбец не левый и индекс не 1
        Gosub ControlGet    
    _Butt += 1 ; увеличиваем номер контрола    
    }    
Return ; ---------------------------------------------------- ControlGet
ControlGet:
ControlGetText, Text_B, Button%_Butt%, %Title% ; получаем текст контрола
If Text_B = %Fishka%
    n += 1 ; счетчик соседей    
Return ; ---------------------------------------------------- Button
Button:
StringSplit, D, A_GuiControl, _ ; парсим
A := D1, B := D2 ; получаем номер столбца
MouseGetPos, , , , VarControl ; получаем имя контрола
ControlGetText, TextB, %VarControl%, %Title% ; получаем текст контрола
If TextB = %Fishka% ; если метка уже есть
    GuiControl,, %A%_%B%, ; изменяем контрол
Else ; если метки нет
    GuiControl,, %A%_%B%, %Fishka% ; изменяем контрол
Return ; ---------------------------------------------------- 
GuiClose:
Выход:
    ExitApp

Число строк должно быть равно числу столбцов, дабы алгоритм правильно работал, иначе, да, он будет работать не правильно. Сделал как попроще, хотя тоже интересно другие алгоритмы попробовать).

15 (изменено: stir, 2011-11-17 11:05:09)

Re: AHK: игра «Жизнь» [Life]

заметил, что игра входит в некое зацикливание по кругу и не останавливается.. хотя уже давно пора.. виной всему алгоритм, недающий закончиться цикличности. Геометрические фигуры постоянно повторяются, , на глаз примерно кратно 4 ,5 тактам.

Любители построили Ковчег, а профессионалы - Титаник.

16

Re: AHK: игра «Жизнь» [Life]

Так и должно быть, это "Периодические фигуры": т.е. фигуры, у которых состояние повторяется через некоторое число поколений, или же "Устойчивые фигуры" т.е. фигуры, которые остаются неизменными.

17

Re: AHK: игра «Жизнь» [Life]

Zohann, работает, но медленно очень. Попробуй открыть 30х30, нарисовать что-нибудь и запустить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: игра «Жизнь» [Life]

OFF: Вот тебе для вдохновения. Работать должно примерно так же.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

19

Re: AHK: игра «Жизнь» [Life]

Переделал алгоритм поиска  на двух массивах, стало понятней, но медленней , зато работает теперь на неквадратных полях!
Буду конечно подумать как увеличить быстродействие (например в сравнении текущего и будущего состояний пометить последнее неравенство и в следующем цикле уже не продолжать проверку соседей после него), но ведь это Buttons! GuiControlget это вам не GDip! )))

SetKeyDelay, 0
SetBatchLines, -1
; --------------------------------------- Переменные
Title = Life v.2
ini = %Title%.ini
Generation = 0
w := 20, x := 5, y := 65
Fishka = O ; знак на кнопке
Generation = 0 ; кол-во поколений
; --------------------------------------- Чтение ini
IniRead, Str, %ini%, Set, Str, 11
IniRead, Col, %ini%, Set, Col, 11
IniRead, Speed, %ini%, Set, Speed, 300
; --------------------------------------- Gui, Show
Gui, Add, Text, x5 Section, Скорость
Gui, Add, Slider, ToolTip Range100-1000 Page100 x+5 y5 vSpeed gChange, %Speed%
Gui, Font, Arial cBlue s18
Gui, Add, Text, Center x+5 w30 h30, 0
Gui, Font
Gui, Add, Text, xs y+5, Строк
Gui, Add, Edit, Number x+5 w30 vStr, %Str%
Gui, Add, Text, x+5, Столбцов
Gui, Add, Edit, Number x+5 w30 vCol, %Col%
Gui, Add, Text, x+5 gПрименить, Применить
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
    }
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, xs y%y% w60 gПуск, Пуск
Gui, Add, Button, x+5 wp gОчистить, Очистить
Gui, Add, Button, x+5 wp gСтоп, Стоп
Gui, Add, Button, x+5 wp gВыход, Выход
Gui, Show, x500 y300, %Title%
Return ; --------------------------------------- Change
Change:
Gui, Submit, NoHide
If S = 1 ; если программа работает, меняем скорость
    SetTimer, Start, %Speed%
IniWrite, %Speed%, %ini%, Set, Speed    
Return ; --------------------------------------- Применить    
Применить:
Gui, Submit, NoHide
IniWrite, %Str%, %ini%, Set, Str
IniWrite, %Col%, %ini%, Set, Col
Reload
Return ; --------------------------------------- Пуск
Пуск:
S = 1 ; метка работы
SetTimer, Start, %Speed%
Return ; --------------------------------------- Стоп
Стоп:
S = 0 ; метка остановки
SetTimer, Start, off
Return ; --------------------------------------- Очистить
Очистить:
If S = 1 ; если программа в работе, то выход
    Return
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControl,, %A%_%B% ; изменяем контрол
        _%A%_%B% = ; очистка массива
    } }
GuiControl,, static2, 0 ; очистка счетчика   
Generation = 0 ; кол-во поколений
Return ; --------------------------------------- Start
Start:
m = 0 ; очистка состояния полей
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        GuiControlget, TextB,, %A%_%B% ; считать состояние текущей клетки
        Around = 0    ; очистка кол-ва окружений
        A -= 1, B -= 1        ; обход вокруг текущей клетки
        Gosub ПроверкаСоседей
        B += 1
        Gosub ПроверкаСоседей
        B += 1
        Gosub ПроверкаСоседей
        A += 1
        Gosub ПроверкаСоседей
        A += 1
        Gosub ПроверкаСоседей
        B -= 1
        Gosub ПроверкаСоседей
        B -= 1
        Gosub ПроверкаСоседей
        A -= 1
        Gosub ПроверкаСоседей
        B += 1                 ; возврат на текущюю клетку         
        _%A%_%B% := (Around = "2" OR Around = "3") ? TextB : "" ; Если соседей 2 или 3, клетка не изменяется
        If (Around = "3" AND TextB = "") ; Если соседей 3 и клетка пустая, клетка рождается
            _%A%_%B% := Fishka        
        If TextB <> % _%A%_%B% ; сравнение текущего и будущего состояний
            m = 1    
    }    }
If m = 0 
    {
    SetTimer, Start, off
    S = 0 ; метка остановки работы программы
    }
Else
    GuiControl,, static2, % Generation += 1 ; подсчет поколений    
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        GuiControl,, %A%_%B%, % _%A%_%B% ; изменяем контрол
        } }
Return ; ---------------------------------------------------- ПроверкаСоседей
ПроверкаСоседей: 
    GuiControlget, TextBA,,%A%_%B% ; считать значок соседней клетки
    Birn := TextBA = Fishka ; присвоить 1 или 0
    Around += Birn ; подсчет соседей    
Return ; ---------------------------------------------------- Button
Button:
StringSplit, D, A_GuiControl, _ ; парсим
A := D1, B := D2 ; получаем номер столбца
MouseGetPos, , , , VarControl ; получаем имя контрола
ControlGetText, TextB, %VarControl%, %Title% ; получаем текст контрола
If TextB = %Fishka% ; если метка уже есть
    GuiControl,, %A%_%B%, ; изменяем контрол
Else ; если метки нет
    GuiControl,, %A%_%B%, %Fishka% ; изменяем контрол
Return
GuiClose:
Выход:
    ExitApp

20

Re: AHK: игра «Жизнь» [Life]

Смысл рационального алгоритма — проверять только изменившиеся в предыдущей итерации клетки и их соседей.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

21

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:

OFF: Вот тебе для вдохновения. Работать должно примерно так же.

Можно далеко зайти.

22

Re: AHK: игра «Жизнь» [Life]

После прогулки на свежем воздухе возникла мысль: т.к. после первого цикла новое состояние поля уже находится в массиве _%A%_%B%, то почему бы в следующем цикле не проверять этот массив вместо GuiControlget каждой кнопки! А?)

teadrinker пишет:

OFF: Вот тебе для вдохновения. Работать должно примерно так же.

Вечером погляжу дома.

23

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:

Смысл рационального алгоритма — проверять только изменившиеся в предыдущей итерации клетки и их соседей.

Это не так просто, как кажется. Вообще AHK не лучший инструмент в данном случае. Тут нужно как можно меньше взаимодействовать с GUI. А желательно алгоритм вообще на асме написать(пример), задача как раз для него.

24

Re: AHK: игра «Жизнь» [Life]

Александр_ пишет:

Это не так просто, как кажется.

Я ж говорю, уже сделал. Со сложностями не столкнулся, использовал массивы. Работает довольно шустренько, даже в больших колониях. Ну, не в таких больших, как на роликах.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25

Re: AHK: игра «Жизнь» [Life]

ypppu пишет:
teadrinker пишет:

OFF: Вот тебе для вдохновения. Работать должно примерно так же.

Можно далеко зайти.

Видел тоже этот ролик, в нём, кстати, хорошо фигуры видны, можно снимать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

26

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:
Александр_ пишет:

Это не так просто, как кажется.

Я ж говорю, уже сделал. Со сложностями не столкнулся, использовал массивы. Работает довольно шустренько, даже в больших колониях. Ну, не в таких больших, как на роликах.

Нужно контрольные тесты придумать, например поле 20х20, а фигура- простой крест.
http://s017.radikal.ru/i422/1111/22/a7f16ee3eebat.jpg
И сравнить скорость работы с другими скриптами

27

Re: AHK: игра «Жизнь» [Life]

У меня поле — 600х400 (GDI+), границы за пределами окна, в окне только центр, поле можно сдвигать мышкой по мере необходимости. Быстро обсчитывает колонию в несколько сотен жителей (точное число пока не знаю). Добавлю всяких рюшечек и выложу.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

28 (изменено: Zohann, 2011-11-17 23:55:14)

Re: AHK: игра «Жизнь» [Life]

Вот, выкинул много лишнего, изменил немного алгоритм и интерфейс. Скорость существенно выше, чем предыдущие версии.

SetKeyDelay, 0
SetBatchLines, -1
; --------------------------------------- Переменные
Title = Life v.3
ini = %Title%.ini
Generation := 0, w := 20, x := 5, y := 65
Fishka = O ; знак на кнопке
Generation = 0 ; кол-во поколений
; --------------------------------------- Чтение ini
IniRead, Str, %ini%, Set, Str, 25
IniRead, Col, %ini%, Set, Col, 25
IniRead, Speed, %ini%, Set, Speed, 200
; --------------------------------------- Gui, Show
Gui, Add, GroupBox, Center x5 w140 h46 Section, Скорость
Gui, Add, GroupBox, Center x+5 w60 hp, Счет
Gui, Add, GroupBox, Center x+5 w104 hp, Размер поля
Gui, Add, Slider, NoTicks Center ToolTip Range10-1000 xs+7 ys+15 w126 vSpeed gChange, %Speed%
Gui, Font, cBlue s16
Gui, Add, Text, Arial Center x+15 w50 h30 vСчет, 0
Gui, Font
Gui, Add, Text, x+20, x
Gui, Add, Edit, Number x+5 w30 vCol, %Col%
Gui, Add, Text, x+5, y
Gui, Add, Edit, Number x+8 w30 vStr, %Str%
Gui, Add, Button, x+16 gПрименить, Применить
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
    }
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, xs y%y% w60 gПуск, Пуск
Gui, Add, Button, x+5 wp gОчистить, Очистить
Gui, Add, Button, x+5 wp gСтоп, Стоп
x := x > 210 ? x - 60 : "+5"
Gui, Add, Button, x%x% yp wp gВыход, Выход
Gui, Show, x100 , %Title%
Return ; --------------------------------------- Change
Change:
Gui, Submit, NoHide
If S = 1 ; если программа работает, меняем скорость
    SetTimer, Start, %Speed%
IniWrite, %Speed%, %ini%, Set, Speed    
Return ; --------------------------------------- Применить    
Применить:
Gui, Submit, NoHide
IniWrite, %Str%, %ini%, Set, Str
IniWrite, %Col%, %ini%, Set, Col
Reload
Return ; --------------------------------------- Пуск
Пуск:
S = 1 ; метка работы
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        GuiControlget, %A%_%B%,, %A%_%B% ; считать состояние 
        } }
SetTimer, Start, %Speed%
Return ; --------------------------------------- Стоп
Стоп:
S = 0 ; метка остановки
SetTimer, Start, off
Return ; --------------------------------------- Очистить
Очистить:
If S = 1 ; если программа в работе, то выход
    Return
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControlget, %A%_%B%,, %A%_%B% ; считать значок
        GuiControl,, %A%_%B% ; изменяем контрол
        _%A%_%B% = ; очистка массива
    } }
GuiControl,, Счет, 0 ; очистка счетчика   
Generation = 0 ; кол-во поколений
Return ; --------------------------------------- Start
Start:
m = 0 ; очистка состояния полей
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        Around = 0    ; очистка кол-ва окружений
        A -= 1, B -= 1        ; обход вокруг текущей клетки
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1                 ; возврат на текущюю клетку         
        _%A%_%B% := (Around = "2" OR Around = "3") ? %A%_%B% : "" ; Если соседей 2 или 3, клетка не изменяется
        If (Around = "3" AND %A%_%B% = "") ; Если соседей 3 и клетка пустая, клетка рождается
            _%A%_%B% := Fishka        
        If %A%_%B% <> % _%A%_%B% ; сравнение текущего и будущего состояний
            m = 1    
    } }
If m = 0 ; если изменений не было, останов
    {
    S := 0 ; метка останова
    SetTimer, Start, off
    }
Else
    GuiControl,, Счет, % Generation += 1 ; подсчет поколений    
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        GuiControl,, %A%_%B%, % _%A%_%B% ; изменяем контрол
        %A%_%B% = % _%A%_%B% ; присвоить массив
        } }
Return ; ---------------------------------------------------- Button
Button:
GuiControlget, TextB,, %A_GuiControl% ; считать состояние 
GuiControl,, %A_GuiControl%, % TextB = Fishka ? "" : Fishka ; изменяем контрол    
Return
GuiClose:
Выход:
    ExitApp
Александр_ пишет:

Нужно контрольные тесты придумать, например поле 20х20, а фигура- простой крест.
И сравнить скорость работы с другими скриптами

Моментально 20х20 обработало, 30х30 тоже весьма быстро, только долго крест рисовать пришлось. Надо сохранение придумать для фигур.
http://img408.imageshack.us/img408/3581/15620913.th.jpg

29

Re: AHK: игра «Жизнь» [Life]

В 19 строке ошибка: название шрифта в опциях контрола Text не пишется. И ещё скорость 10 — самая высокая, 1000 — самая маленькая, нелогично как-то!
За исключением этого уже большой прогресс!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

30

Re: AHK: игра «Жизнь» [Life]

И ещё знак на кнопке плохо виден, можно как-нибудь так:

SetKeyDelay, 0
SetBatchLines, -1
; --------------------------------------- Переменные
Title = Life v.3
ini = %Title%.ini
Generation := 0, w := 20, x := 5, y := 65
Fishka = • ; знак на кнопке
Generation = 0 ; кол-во поколений
; --------------------------------------- Чтение ini
IniRead, Str, %ini%, Set, Str, 25
IniRead, Col, %ini%, Set, Col, 25
IniRead, Speed, %ini%, Set, Speed, 200
; --------------------------------------- Gui, Show
Gui, Add, GroupBox, Center x5 w140 h46 Section, Скорость
Gui, Add, GroupBox, Center x+5 w60 hp, Счет
Gui, Add, GroupBox, Center x+5 w104 hp, Размер поля
Gui, Add, Slider, NoTicks Center ToolTip Range10-1000 xs+7 ys+15 w126 vSpeed gChange, %Speed%
Gui, Font, cBlue s16
Gui, Add, Text, Center x+15 w50 h30 vСчет, 0
Gui, Font
Gui, Add, Text, x+20, x
Gui, Add, Edit, Number x+5 w30 vCol, %Col%
Gui, Add, Text, x+5, y
Gui, Add, Edit, Number x+8 w30 vStr, %Str%
Gui, Add, Button, x+16 gПрименить, Применить
Gui, Font, s30
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
   }
Gui, Font
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, xs y%y% w60 gПуск, Пуск
Gui, Add, Button, x+5 wp gОчистить, Очистить
Gui, Add, Button, x+5 wp gСтоп, Стоп
x := x > 210 ? x - 60 : "+5"
Gui, Add, Button, x%x% yp wp gВыход, Выход
Gui, Show, x100 , %Title%
Return ; --------------------------------------- Change
Change:
Gui, Submit, NoHide
If S = 1 ; если программа работает, меняем скорость
    SetTimer, Start, %Speed%
IniWrite, %Speed%, %ini%, Set, Speed    
Return ; --------------------------------------- Применить    
Применить:
Gui, Submit, NoHide
IniWrite, %Str%, %ini%, Set, Str
IniWrite, %Col%, %ini%, Set, Col
Reload
Return ; --------------------------------------- Пуск
Пуск:
S = 1 ; метка работы
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        GuiControlget, %A%_%B%,, %A%_%B% ; считать состояние 
        } }
SetTimer, Start, %Speed%
Return ; --------------------------------------- Стоп
Стоп:
S = 0 ; метка остановки
SetTimer, Start, off
Return ; --------------------------------------- Очистить
Очистить:
If S = 1 ; если программа в работе, то выход
    Return
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControlget, %A%_%B%,, %A%_%B% ; считать значок
        GuiControl,, %A%_%B% ; изменяем контрол
        _%A%_%B% = ; очистка массива
    } }
GuiControl,, Счет, 0 ; очистка счетчика   
Generation = 0 ; кол-во поколений
Return ; --------------------------------------- Start
Start:
m = 0 ; очистка состояния полей
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        Around = 0    ; очистка кол-ва окружений
        A -= 1, B -= 1        ; обход вокруг текущей клетки
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1                 ; возврат на текущюю клетку         
        _%A%_%B% := (Around = "2" OR Around = "3") ? %A%_%B% : "" ; Если соседей 2 или 3, клетка не изменяется
        If (Around = "3" AND %A%_%B% = "") ; Если соседей 3 и клетка пустая, клетка рождается
            _%A%_%B% := Fishka        
        If %A%_%B% <> % _%A%_%B% ; сравнение текущего и будущего состояний
            m = 1    
    } }
If m = 0 ; если изменений не было, останов
    {
    S := 0 ; метка останова
    SetTimer, Start, off
    }
Else
    GuiControl,, Счет, % Generation += 1 ; подсчет поколений    
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        GuiControl,, %A%_%B%, % _%A%_%B% ; изменяем контрол
        %A%_%B% = % _%A%_%B% ; присвоить массив
        } }
Return ; ---------------------------------------------------- Button
Button:
GuiControlget, TextB,, %A_GuiControl% ; считать состояние 
GuiControl,, %A_GuiControl%, % TextB = Fishka ? "" : Fishka ; изменяем контрол    
Return
GuiClose:
Выход:
    ExitApp
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

31

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:

В 19 строке ошибка: название шрифта в опциях контрола Text не пишется. И ещё скорость 10 — самая высокая, 1000 — самая маленькая, нелогично как-то! smile
За исключением этого уже большой прогресс!

Ага, с текстом игрался, забыл вернуть на место.
Скорость поправил через Speed := MaxSpeed - Speed.
Прогресс невооруженным взгядом видно))

teadrinker пишет:

И ещё знак на кнопке плохо виден, можно как-нибудь так:

О как здорово получилось!
Допишу сохранение фигур и выложу.

32 (изменено: Александр_, 2011-11-18 14:06:25)

Re: AHK: игра «Жизнь» [Life]

Результат хороший, не стоит смотреть на программы в видео, конкурировать с ними скриптом в принципе не реально(кстати, их исходники открыты и неплохо документированы). Теперь уже нужно думать о изменении алгоритма или механизма вывода на экран. Проверил на "сях"- для того, чтобы 100 раз полностью отобразить поле 30х30 нужно 7 секунд, а для того, чтобы миллион раз рассчитать всё поле 30х30 требуется 16 секунд. Т.е. для отображения одной клетки требуется больше времени, чем для одиннадцати расчётов пола 30х30. На ahk, конечно, разница будет меньше, но всё же...
Сохранения реализуются очень просто, вы явно упустили тот факт, что для хранения одной клетки требуется ровно 1бит информации. Т.е. для хранения поля 32х32 и меньше хватит массива из 32 чисел. Отсюда вытекает и способ быстрой генерации случайного поля. Возможно имеет смысл использовать эту особенность и в алгоритме, но нужно учесть тормознутость NumGet.

33 (изменено: Zohann, 2011-11-25 12:39:58)

Re: AHK: игра «Жизнь» [Life]

Изменения:
Ползунок скорости (сдвиг вправо - увеличение скорости).
+Меню
-Цикл чтения ячеек при запуске, т.к. массив изменяется уже при нажатии на клетку.
+Сохранение/Загрузка/Удаление фигур в ini-файл
+Помощь/О программе

SetKeyDelay, 0
SetBatchLines, -1
; --------------------------------------- Переменные
Title = Life v.4
ini = %Title%.ini
Generation := 0, w := 20, x := 5, y := 65, MaxSpeed := 1000
Fishka = • ; знак на кнопке
Generation = 0 ; кол-во поколений
; --------------------------------------- Чтение ini
IniRead, Str, %ini%, Set, Str, 25
IniRead, Col, %ini%, Set, Col, 25
IniRead, Speed, %ini%, Set, Speed, 200
; --------------------------------------- Меню
Menu, FileMenu, Add, Новая игра, Очистить
Menu, FileMenu, Add
Menu, FileMenu, Add, Сохранить фигуру..., Сохранить
IniRead, FigureAll, %ini%, Figure, FigureAll, 0 ; считать список фигур
If (FigureAll <> 0 AND FigureAll <> "") ; если сохраненные фигуры есть...
	{
	StringSplit, fName, FigureAll, | ; сплит строки
	Loop, %fName0%
		if % fName%A_Index% ; если имя не пусто...
			{
			Menu, Load, Add, % fName%A_Index%, Загрузить ; запись в меню
			Menu, Del, Add, % fName%A_Index%, Удалить ; запись в меню
			}
	}
Else
	{
	Menu, Load, Add
	Menu, Del, Add
	}
Menu, FileMenu, Add, Загрузить фигуру, :Load
Menu, FileMenu, Add, Удалить фигуру, :Del
Menu, FileMenu, Add
Menu, FileMenu, Add, Выход, Выход
Menu, HelpMenu, Add, Помощь, Помощь
Menu, HelpMenu, Add, О программе..., О
Menu, MyMenuBar, Add, Файл, :FileMenu
Menu, MyMenuBar, Add, Справка, :HelpMenu
Gui, Menu, MyMenuBar
; --------------------------------------- Gui, Show
Gui, Add, GroupBox, Center x5 w140 h46 Section, Скорость
Gui, Add, GroupBox, Center x+5 w60 hp, Счет
Gui, Add, GroupBox, Center x+5 w104 hp, Размер поля
Gui, Add, Slider, NoTicks Center ToolTip Range10-%MaxSpeed% xs+7 ys+15 w126 vSpeed gChange, %Speed%
Gui, Font, cBlue s16
Gui, Add, Text, Center x+15 w50 h30 vСчет, 0
Gui, Font
Gui, Add, Text, x+20, x
Gui, Add, Edit, Number x+5 w30 vCol, %Col%
Gui, Add, Text, x+5, y
Gui, Add, Edit, Number x+8 w30 vStr, %Str%
Gui, Add, Button, x+16 gПрименить, Применить
Gui, Font, s30
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    x = 5 ; начальная позиция по х для новой строки
    Loop %Col% { ; цикл по количеству столбцов
        B := A_Index ; присваиваем номер столбца
        Gui, Add, Button,  x%x% y%y% w%w% h%w% gButton v%A%_%B%
        x += 20 ; позиция для следующего контрола
        }
    y +=20 ; позиция по у для следующей строки
   }
Gui, Font
y += 5  ; позиция по у для кнопок управления
Gui, Add, Button, xs y%y% w60 gПуск, Пуск
Gui, Add, Button, x+5 wp gОчистить, Очистить
Gui, Add, Button, x+5 wp gСтоп, Стоп
x := x > 210 ? x - 60 : "+5"
Gui, Add, Button, x%x% yp wp gВыход, Выход
Gui, Show, x100 , %Title%
Return ; --------------------------------------- Change
Change:
Gui, Submit, NoHide
Speed := MaxSpeed - Speed
If S = 1 ; если программа работает, меняем скорость
    SetTimer, Start, %Speed%
IniWrite, %Speed%, %ini%, Set, Speed
Return ; --------------------------------------- Применить    
Применить:
Gui, Submit, NoHide
IniWrite, %Str%, %ini%, Set, Str
IniWrite, %Col%, %ini%, Set, Col
Reload
Return ; --------------------------------------- Пуск
Пуск:
S = 1 ; метка работы
SetTimer, Start, %Speed%
Return ; --------------------------------------- Стоп
Стоп:
S = 0 ; метка остановки
SetTimer, Start, off
Return ; --------------------------------------- Очистить
Очистить:
If S = 1 ; если программа в работе, то выход
    Return
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
        GuiControlget, %A%_%B%,, %A%_%B% ; считать значок
        GuiControl,, %A%_%B% ; изменяем контрол
		%A%_%B% = ; очистка массива
        _%A%_%B% = ; очистка массива
    } }
GuiControl,, Счет, 0 ; очистка счетчика   
Generation = 0 ; кол-во поколений
Return ; --------------------------------------- Start
Start:
m = 0 ; очистка состояния полей
Loop %Str% { ; цикл по количеству строк
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов  
        B := A_Index ; присваиваем номер столбца
        Around = 0    ; очистка кол-ва окружений
        A -= 1, B -= 1        ; обход вокруг текущей клетки
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A += 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        A -= 1
        Around += % %A%_%B% = Fishka ; присвоить 1 или 0
        B += 1                 ; возврат на текущюю клетку         
        _%A%_%B% := (Around = "2" OR Around = "3") ? %A%_%B% : "" ; Если соседей 2 или 3, клетка не изменяется
        If (Around = "3" AND %A%_%B% = "") ; Если соседей 3 и клетка пустая, клетка рождается
            _%A%_%B% := Fishka        
        If %A%_%B% <> % _%A%_%B% ; сравнение текущего и будущего состояний
            m = 1    
    } }
If m = 0 ; если изменений не было, останов
    {
    S := 0 ; метка останова
    SetTimer, Start, off
    }
Else
    GuiControl,, Счет, % Generation += 1 ; подсчет поколений    
Loop %Str% { ; обновляем игровое поле
    A := A_Index ; присваиваем номер строки
    Loop %Col% { ; цикл по количеству столбцов    
        B := A_Index ; присваиваем номер столбца
        GuiControl,, %A%_%B%, % _%A%_%B% ; изменяем контрол
        %A%_%B% = % _%A%_%B% ; присвоить массив
        } }
Return ; ---------------------------------------------------- Button
Button:
GuiControlget, TextB,, %A_GuiControl% ; считать состояние 
GuiControl,, %A_GuiControl%, % TextB = Fishka ? "" : Fishka ; % изменяем контрол
GuiControlget, %A_GuiControl%,, %A_GuiControl% ; считать состояние 
Return ; ---------------------------------------------------- Сохранить
Сохранить: 
fSave = |
Loop %Str% {
    A := A_Index
    Loop %Col% {
        B := A_Index
		If %A%_%B% = %Fishka% ; если клетка живая
			fSave .= A "_" B "|" ; добавить в список
	} 	}
	If fSave <> |
		{
		InputBox, Name, Сохранение, Введите название фигуры, , 260, 120
		if (ErrorLevel <> 0 OR Name = "")
			Return
		IniRead, FigureAll, %ini%, Figure, FigureAll, 0 ; считать список фигур
		FigureAll := FigureAll = 0 ? "|" : FigureAll ; если 0, то присвоить "пусто"
		If InStr(FigureAll, "|" Name "|") = 0 ; если имя не повторяется...
			{
			FigureAll .= Name "|" ; добавить имя к списку
			IniWrite, %FigureAll%, %ini%, Figure, FigureAll ; запись списка в ini
			Menu, Load, Add, %Name%, Загрузить ; добавить пункт в меню
			Menu, Del, Add, %Name%, Удалить ; добавить пункт в меню	
			}
		Else
			{	
			Gui +OwnDialogs			
			MsgBox, 36, Внимание!, Фигура с таким именем уже сохранена!`nЗаменить на новую?
			IfMsgBox, No
				Return
			}
		IniWrite, %fSave%, %ini%, Figure, %Name%
		}
Return ; ---------------------------------------------------- Загрузить
Загрузить:
IniRead, Figure, %ini%, Figure, %A_ThisMenuItem%, 0
If FigureAll = 0
	Return
Loop %Str% {
	A := A_Index ; присваиваем номер строки
	Loop %Col% { ; цикл по количеству столбцов    
		B := A_Index ; присваиваем номер столбца
		If InStr(Figure, "|" A "_" B "|") >= 1 ; если поиск удачный...
			{
			GuiControl,, %A%_%B%, %Fishka% ; изменяем контрол
			%A%_%B% = %Fishka% ; изменить элемент массива
			}
	} 	}
Return ; ---------------------------------------------------- Удалить		
Удалить: ; удалить пункт в меню
StringReplace, FigureAll, FigureAll, |%A_ThisMenuItem%|, |
IniWrite, %FigureAll%, %ini%, Figure, FigureAll
IniDelete, %ini%, Figure, %A_ThisMenuItem%
Menu, Load, Delete, %A_ThisMenuItem%
Menu, Del, Delete, %A_ThisMenuItem%	
Return ; ---------------------------------------------------- Помощь
Помощь:
Gui +OwnDialogs
MsgBox, 8256, Помощь, 
(
Игра «Жизнь» (Game of Life) — клеточный автомат, 
придуманный английским математиком Джоном Конвеем в 1970 году.
Игрок не принимает прямого участия в игре, а лишь расставляет начальную конфигурацию «живых» клеток,
которые затем взаимодействуют согласно правилам уже без его участия.
Правила:
Пустая (мёртвая) клетка, рядом с которой ровно три живые клетки, оживает;
Если у живой клетки есть две или три живые соседки, то эта клетка продолжает жить;
Если соседей меньше двух или больше трёх клетка умирает (от «одиночества» или от «перенаселённости»).
)
Return ; ---------------------------------------------------- О программе
О:
Gui +OwnDialogs
MsgBox, 8256, Игра «Жизнь» (Game of Life) from John Horton,
(
Разработато Zohann совместно с обществом forum.script-coding.com
Отдельная благодарность участникам форума:
teadrinker, ypppu, alexii Александр_.

© 2011 Zohann
)
Return
GuiClose:
Выход:
    ExitApp

34

Re: AHK: игра «Жизнь» [Life]

В благодарностях Александр_'а не упомянул!

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

35

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:

В благодарностях Александр_'а не упомянул!

Ну если это только единственная причина не присвоить мне статус разработчика, то уже исправил!

36

Re: AHK: игра «Жизнь» [Life]

Zohann, не надо жертв!

37

Re: AHK: игра «Жизнь» [Life]

Zohann пишет:

...присвоить мне статус разработчика...

OFF: Цель форума не в получении статуса.

38

Re: AHK: игра «Жизнь» [Life]

teadrinker пишет:

Я ж говорю, уже сделал. Со сложностями не столкнулся, использовал массивы. Работает довольно шустренько, даже в больших колониях. Ну, не в таких больших, как на роликах.

И шож, где игруля?

39

Re: AHK: игра «Жизнь» [Life]

Будет, будет! Просто ещё до ума довести нужно, а времени не очень много.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

40

Re: AHK: игра «Жизнь» [Life]

Добил, наконец, если ещё кому-то интересно!

Требует AHK_L; файла Gdip.ahk, находящегося в любой из перечисленных ниже папок:

%A_ScriptDir%\Lib\  ; Local library - requires AHK_L 42+.
%A_MyDocuments%\AutoHotkey\Lib\  ; User library.
path-to-the-currently-running-AutoHotkey.exe\Lib\  ; Standard library.

Рисовать фигуры можно, кликая по полю (отдельные точки), и проводкой (линии и прямоугольники), удерживая левую кнопку мыши; удерживая Alt можно рисовать диагонали. Всё то же самое плюс Ctrl — стирание нарисованного. Для полной очистки поля воспользуйтесь Clear во время, когда движение фигур полностью остановлено (кнопка Stop, она же Start)

Нарисованные фигуры можно сохранять и в дальнейшем загружать. Сохранённая фигура загружается в видимый центр игрового поля, до нажатия кнопки OK её можно сдвигать в нужное место клавишами стрелок. Само поле можно двигать правой кнопкой мыши. Чтобы отцентровать поле, нажмите Center.

   #NoEnv
   SetBatchLines, -1
   SetWinDelay, 0

   IniName := A_ScriptDir "\" RegExReplace(A_ScriptName, "(.*\.).*", "$1ini")
   Columns = 500
   Rows := Round(Columns*A_ScreenHeight/A_ScreenWidth)

   IniRead, Cell, % IniName, Settings, Cell, 8   ; размер клетки
   FieldWidth := Columns*Cell - 1   ; полная ширина игрового поля
   FieldHeight := Rows*Cell - 1     ; полная высота игрового поля
   ButtonField = 55   ; область с элементами управления
   AliveBrush1 := 0xFF2A5EA9   ; цвет живых клеток в монохромном режиме

   Gosub, CreateWindow

   CellArray := []  ; в этом двумерном массиве будут все клетки поля, их координаты и состояние
   Loop % Columns
      CellArray[A_Index] := []

   Loop % Rows
   {
      r := A_Index
      Loop % Columns
         CellArray[r][A_Index] := {x: Cell*(A_Index - 1), y: Cell*(r - 1), alive: 0}
   }

   NextArray := {}  ; здесь будут клетки, изменённые в предыдущей итерации и их соседи
                    ; в цикле будем рассматривать только их
   OnMessage(0x201, "WM_LBUTTONDOWN")
   OnMessage(0x200, "WM_MOUSEMOVE")
   OnMessage(0x202, "WM_LBUTTONUP")
   OnMessage(0x111, "WM_COMMAND")
   OnMessage(0x00F, "WM_PAINT")
   OnExit, Exit
   Return

CreateWindow:
   pToken := Gdip_Startup()

   SysGet, GuiW, % SM_CXFULLSCREEN := 16
   SysGet, GuiH, % SM_CYFULLSCREEN := 17
   SysGet, WBorder, % SM_CXSIZEFRAME := 32
   SysGet, HBorder, % SM_CYSIZEFRAME := 33
   IniRead, FieldW, % IniName, Size, FieldW, % GuiW - 2*WBorder
   IniRead, FieldH, % IniName, Size, FieldH, % GuiH - 2*HBorder - ButtonField
   IniRead, GuiX, % IniName, Size, GuiX, 0
   IniRead, GuiY, % IniName, Size, GuiY, 0
   IniRead, Pause, % IniName, Settings, Pause, 10
   IniRead, Multicolor, % IniName, Settings, Multicolor, 0

   Gui, Parent: +hwndhParent +Resize  ; родительское окно с элементами управления
   Gui, Parent:Default
   Gui, Color, D4D0C8
   Gui, Font, s8, Verdana
   Gui, Add, Pic, % "vPic x0 y0 w" FieldW " h" FieldH " hwndhPic"   ; будет родительским окном для игрового поля
   Gui, Add, Button, % "vStartStop x10 y" FieldH+(ButtonField//2 - 23//2) " w57 h23 gStart", Start
   Gui, Add, Button, vNext xp+61 yp wp hp gCycle, Next
   Gui, Add, Button, vClear xp+61 yp wp hp gClear, Clear
   Gui, Add, Button, vCenter xp+61 yp wp hp gCenter, Center
   Gui, Add, Button, vSave xp+77 yp wp hp gSave hwndhSaveButton, Save
   Gui, Add, Button, vLoad xp+61 yp wp hp gLoad hwndhLoadButton, Load
   Gui, Add, Text, % "vTextSpeed xp+75 yp+" TextD := 5, Speed:

   Options := "xp+40 w100 yp-3 h20 Range1-50 ToolTip AltSubmit"
   Gui, Add, Slider, vSlider gSpeedSet %Options%, % Speed := Round(51 - Pause/10)
   Gui, Add, Text, vSpeed xp+100 yp+3, % Speed
   Gui, Add, Text, vTextSize xp+30 yp, Cell size:
   Gui, Add, DDL, vDDLSize gDDLSize xp+58 yp-4 h20 w35 r8
      , % RegExReplace("4|5|6|7|8|9|10|11", "(" Cell ")", Cell = 11 ? "$1||" : "$1|")
   Gui, Add, Checkbox, % "vMulticolor gMulticolor xp+58 yp+5" (Multicolor ? " Checked" : ""), Multicolor
   trn := FieldW < 898
   Gui, Add, Text, % "vTextGen gClearGen x" (trn ? 788 : FieldW - 110) " yp", Generation
   Gui, Font, s9
   Gui, Add, Text, % "vGen gClearGen x" (trn ? 858 : FieldW - 40) " yp-1 w35", 0

   Gui, Child: -Caption +hwndhField +Parent%hPic%  ; окно с игровым полем

   hFieldDC := GetDC(hField)
   hbm := CreateDIBSection(FieldWidth, FieldHeight)
   hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm)
   G := Gdip_GraphicsFromHDC(hdc)

   pAliveBrush1 := Gdip_BrushCreateSolid(Multicolor ? 0xFF30B29E : AliveBrush1)
   pAliveBrush2 := Gdip_BrushCreateSolid(0xFFFFC400)
   pAliveBrush3 := Gdip_BrushCreateSolid(0xFFC930B8)
   pBackBrush := Gdip_BrushCreateSolid(0xFFFFFFFF)
   Gosub, FillBackground

   Gui, Show, % "x" GuiX " y" GuiY " w" FieldW " h" FieldH + ButtonField
   GuiControlGet, Pic, Pos, Pic
   x_val := PicW//2 - FieldWidth//2
   y_val := PicH//2 - FieldHeight//2
   Gui, Child:Show, % "x" x_val " y" y_val " w" FieldWidth " h" FieldHeight
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Controls = Next|Clear|DDLSize|Save|Load
   Return

FillBackground:
   Gdip_FillRectangle(G, pBackBrush, -1, -1, FieldWidth+2, FieldHeight+2)   ; заливаем бэкграунд

   TransparentCell := (0x45 + (Cell - 5)*7)<<24
   TransparentGrid := (0x75 + (Cell - 5)*7)<<24
   pCellPen := Gdip_CreatePen(TransparentCell|0x7C7A77, 1)
   pGridPen := Gdip_CreatePen(TransparentGrid|0x7C7A77, 1)
   Loop % Rows - 1
      Gdip_DrawLine(G,  mod(A_Index, 10) ? pCellPen : pGridPen
         , 0, A_Index * Cell - 1, FieldWidth, A_Index * Cell - 1)   ; рисуем горизонтали

   Loop % Columns - 1
      Gdip_DrawLine(G, mod(A_Index, 10) ? pCellPen : pGridPen
         , A_Index * Cell - 1, 0, A_Index * Cell - 1, FieldHeight)   ; рисуем вертикали
   Gdip_DeletePen(pCellPen), Gdip_DeletePen(pGridPen)
   Return

#If WinActive("ahk_id " hParent)
Enter::
Start:
   if WinExist("ahk_id" hLoad)
      Return

   GuiControl, Parent:, StartStop, % (StartStop := !StartStop) ? "Stop" : "Start"
   Loop, parse, Controls, |
      GuiControl, % "Parent:" (StartStop ? "Disable" : "Enable"), %A_LoopField%
   if !StartStop
      Return

   GuiControl, Parent:, Gen, % Gen := 0
   SetTimer, Cycle, -1
   Return

Cycle:
   Loop
   {
      color := Multicolor ? Mod(Ceil(A_Index/20), 3) : 1
      CurrentBrush := color = 1 ? pAliveBrush1 : color = 2 ? pAliveBrush2 : pAliveBrush3
      GuiControl, Parent:, Gen, % ++Gen

      CurrentArray := {}  ; здесь будут клетки, которые изменятся в этой итерации
      for k, v in NextArray
      {
         i := 0, r := v.r, c := v.c
         Loop 3   ; проверяем количество живых и мёртвых соседей у претендентов на смену статуса
         {
            n := c + (p := A_Index) - 2
            Loop 3
            {
               if (p = 2 && A_Index = 2)
                  Continue

               m := r + A_Index - 2
               if (CellArray[m][n].alive && ++i = 4)  ; достаточно досчитать до четырёх
                  Break 2
            }
         }
         o := CellArray[r][c], x := o.x, y := o.y
         if o.alive
         {
            if (i < 2 || i = 4) ; если живых соседей меньше двух или больше трёх — живая умирает
               CurrentArray[A_Index] := {r: r, c: c, alive: 0}
               , Gdip_FillRectangle(G, pBackBrush, x, y, Cell - 1, Cell - 1)
         }
         Else if i = 3   ; если соседей трое — мёртвая оживает
            CurrentArray[A_Index] := {r: r, c: c, alive: 1}
            , Gdip_FillRectangle(G, CurrentBrush, x, y, Cell - 1, Cell - 1)
      }
      NextArray := {}   ; опустошаем массив

      if !CurrentArray.GetCapacity()  ; если ничего не изменилось, значит цикл закончен
      {
         GuiControl, Parent:, StartStop, Start
         Loop, parse, Controls, |
            GuiControl, Parent:Enable, %A_LoopField%
         Break
      }

      for k, v in CurrentArray   ; заносим в массив NextArray изменившиеся клетки и
      {                           ; соседние с ними для проверки в следующей итерации
         c := v.c, r := v.r, UpdateNextArray(r, c)
         , CellArray[r][c].alive := v.alive   ; вносим изменения в основной массив
      }
      BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
      Sleep, Pause
   } Until !StartStop
   StartStop := 0
   Return

Del::
Clear:
   if StartStop
      Return
   GuiControl, Parent:, Gen, % Gen := 0
   for k, v in CellArray
      for n, m in v
         if m.alive
            Update_hDC(m)
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Return

Center:
   GuiControlGet, Pic, Parent:Pos, Pic
   x_val := PicW//2 - FieldWidth//2
   y_val := PicH//2 - FieldHeight//2
   Gui, Child:Show, % "x" x_val " y" y_val " w" FieldWidth " h" FieldHeight
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Return

Save:
   Critical

   if !FileExist(A_ScriptDir "\Figures")
      FileCreateDir, %A_ScriptDir%\Figures

   Gui, Parent: +OwnDialogs
   WinGetPos,, Y_Pic,,, ahk_id %hPic%
   WinGetPos, XButt,,,, ahk_id %hSaveButton%

   GuiControlGet, Field, Parent:Pos, Pic

   Loop
   {
      InputBox, FigureName, Save, Type a Name:,, 200, 120, XButt, Y_Pic + FieldH - 120
      if ErrorLevel
         Return

      BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
      FigureName = %FigureName%
      if (FigureName = "")
         MsgBox, Введите название фигуры!
      else if found := FileExist(A_ScriptDir "\Figures\" FigureName ".life")
      {
         MsgBox, 0x34, Название существует, Название фигуры "%FigureName%" уже существует!`nЗаменить?
         IfMsgBox, Yes
            Break
         else
            FigureName =
      }
   } Until FigureName

   for r, v in CellArray
   {
      for c, m in v
      {
         if m.alive
         {
            if !once
               r_min := r, once := 1
            Figure .= r "," c "|"
         }
      }
   }

   Figure := SubStr(Figure, 1, -1)
   c_min := 1000000000
   Loop, parse, Figure, |
   {
      r_new := RegExReplace(A_LoopField, "(.*),.*", "$1") - r_min
      NewFigure .= RegExReplace(A_LoopField, ".*(,.*)", r_new "$1") . "|"
      if ((n := RegExReplace(A_LoopField, ".*,(.*)", "$1")) < c_min)
         c_min := n
   }
   NewFigure := SubStr(NewFigure, 1, -1), Figure := ""

   Loop, parse, NewFigure, |
   {
      c_new := RegExReplace(A_LoopField, ".*,(.*)", "$1") - c_min
      Figure .= RegExReplace(A_LoopField, "(.*,).*", "$1" c_new) . "|"
   }
   Figure := SubStr(Figure, 1, -1)

   FileDelete, % A_ScriptDir "\Figures\" FigureName ".life"
   FileAppend, % Figure, % A_ScriptDir "\Figures\" FigureName ".life"
   Figure := NewFigure := once := ""
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Notify("Фигура сохранена в файл`n" A_ScriptDir "\Figures\" FigureName ".life"
      , 0xFF0055BB, "Arial", "s15 x15 y12 cFFFFFFFF Italic", 1500)
   Return

Load:
   Gui, Load: New, +OwnerParent +hwndhLoad
   Gui, Load: Default
   Gui, Margin, 15, 10
   Gui, Font, s10 q5, Verdana
   Gui, Add, DDL, vDDLNames gDDLNames hwndhDDLNames w150 h23 r15, Select a Name:||
   Gui, Font, s8, Verdana
   Gui, Add, Button, % "x" (150+30-125)//2 " w60 h23", OK
   Gui, Add, Button, xp+65 w60 h23", Cancel
   GuiControl, Focus, OK
   WinGetPos,, Y_Pic,,, ahk_id %hPic%
   WinGetPos, XButt,,,, ahk_id %hLoadButton%
   GuiControlGet, Field, Parent:Pos, Pic
   Gui, Show, Hide, Load
   DetectHiddenWindows, On
   WinGetPos,,,, LoadH, ahk_id %hLoad%
   Gui, Show, % "x" XButt " y" Y_Pic + FieldH - LoadH, Load
   Return

DDLNames:
   Critical

   GuiControlGet, DDLNames, Load:, DDLNames
   if DDLNames = No Files
      Return

   if CurrentFigure
      Loop, parse, CurrentFigure, |
      {
         r := RegExReplace(A_LoopField, "(.*),.*", "$1") + CurrentRow
         c := RegExReplace(A_LoopField, ".*,(.*)", "$1") + CurrentColumn
         CellArray[r][c].alive := 1, UpdateNextArray(r, c)
      }

   if !hMemoryBm
   {
      hMemoryBm := CreateDIBSection(FieldWidth, FieldHeight)
      hMemoryDC := CreateCompatibleDC()
      oMemoryBm := SelectObject(hMemoryDC, hMemoryBm)
      GMemory := Gdip_GraphicsFromHDC(hMemoryDC)
   }
   BitBlt(hMemoryDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)

   FileRead, CurrentFigure, % A_ScriptDir "\Figures\" DDLNames ".life"
   max_r := max_c := 0
   Loop, parse, CurrentFigure, |
   {
      max_r := (r := RegExReplace(A_LoopField, "(.*),.*", "$1")) > max_r ? r : max_r
      max_c := (c := RegExReplace(A_LoopField, ".*,(.*)", "$1")) > max_c ? c : max_c
   }

   WinGetPos, X_Field, Y_Field,,, ahk_id %hField%
   WinGetPos, X_Pic, Y_Pic, W_Pic, H_Pic, ahk_id %hPic%

   XPosField := X_Pic - X_Field
   YPosField := Y_Pic - Y_Field

   FirstVisibleRow := Ceil(YPosField/Cell) + 1
   LastVisibleRow := Ceil((YPosField + H_Pic)/Cell)

   FirstVisibleColumn := Ceil(XPosField/Cell) + 1
   LastVisibleColumn := Ceil((XPosField + W_Pic)/Cell)

   CurrentRow := StartRow := (LastVisibleRow + FirstVisibleRow - max_r)//2
   CurrentColumn := StartColumn := (LastVisibleColumn + FirstVisibleColumn - max_c)//2

   Loop, parse, CurrentFigure, |
   {
      r := RegExReplace(A_LoopField, "(.*),.*", "$1") + StartRow
      c := RegExReplace(A_LoopField, ".*,(.*)", "$1") + StartColumn
      x := CellArray[r][c].x, y := CellArray[r][c].y
      Gdip_FillRectangle(G, pAliveBrush1, x, y, Cell - 1, Cell - 1)
   }
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)

   Hotkey, IfWinExist, ahk_id %hLoad%
   Hotkey, Left, MoveFigure, On
   Hotkey, Right, MoveFigure, On
   Hotkey, Up, MoveFigure, On
   Hotkey, Down, MoveFigure, On
   Return

MoveFigure:
   While GetKeyState(A_ThisHotkey, "P") || GetKeyState(A_PriorHotkey, "P")
   {
      GetKeyState("UP", "P") ? (--CurrentRow = 0 ? ++CurrentRow : CurrentRow)
      GetKeyState("Down", "P") ? (++CurrentRow = Rows + 1 ? --CurrentRow : CurrentRow)
      GetKeyState("Left", "P") ? (--CurrentColumn = 0 ? ++CurrentColumn : CurrentColumn)
      GetKeyState("Right", "P") ? (++CurrentColumn = Columns + 1 ? --CurrentColumn : CurrentColumn)

      BitBlt(hdc, 0, 0, FieldWidth, FieldHeight, hMemoryDC, 0, 0)
      Loop, parse, CurrentFigure, |
      {
         r := RegExReplace(A_LoopField, "(.*),.*", "$1") + CurrentRow
         c := RegExReplace(A_LoopField, ".*,(.*)", "$1") + CurrentColumn
         x := CellArray[r][c].x, y := CellArray[r][c].y
         Gdip_FillRectangle(G, pAliveBrush1, x, y, Cell - 1, Cell - 1)
      }
      BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
      Sleep, 50
   }
   Return

#If WinExist("ahk_id" hLoad)
Enter::
LoadButtonOK:
   if !CurrentFigure
   {
      Gui, Load:Destroy
      Return
   }

   Loop, parse, CurrentFigure, |
   {
      r := RegExReplace(A_LoopField, "(.*),.*", "$1") + CurrentRow
      c := RegExReplace(A_LoopField, ".*,(.*)", "$1") + CurrentColumn
      CellArray[r][c].alive := 1, UpdateNextArray(r, c)
   }

Esc::
LoadGuiClose:
LoadButtonCancel:
   Gui, Load:Destroy
   if !CurrentFigure
      Return

   if (A_ThisLabel ~= "Load(ButtonCancel|GuiClose)" || A_ThisHotkey = "Esc")
      BitBlt(hdc, 0, 0, FieldWidth, FieldHeight, hMemoryDC, 0, 0)
      , BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Hotkey, Left, Off
   Hotkey, Right, Off
   Hotkey, Up, Off
   Hotkey, Down, Off
   SelectObject(hMemoryDC, oMemoryBm), DeleteObject(hMemoryBm)
   DeleteDC(hMemoryDC), Gdip_DeleteGraphics(GMemory)
   hMemoryBm := CurrentFigure := ""
   Return

SpeedSet:
   GuiControl, Parent:, Speed, % Slider
   Pause := (51 - Slider)*10
   Return

DDLSize:
   Gui, Child:Show, Hide
   GuiControlGet, Cell, Parent:, DDLSize

   FieldWidth := Columns*Cell - 1
   FieldHeight := Rows*Cell - 1

   hPrevbm := hbm
   hbm := CreateDIBSection(FieldWidth, FieldHeight)
   SelectObject(hdc, hbm), DeleteObject(hPrevbm), Gdip_DeleteGraphics(G)
   G := Gdip_GraphicsFromHDC(hdc)

   Gosub, FillBackground
   Loop % Rows
   {
      r := A_Index
      Loop % Columns
      {
         oCell := CellArray[r][A_Index]
         oCell.x := Cell*(A_Index - 1), oCell.y := Cell*(r - 1)
         if oCell.alive
            Gdip_FillRectangle(G, pAliveBrush1, oCell.x, oCell.y, Cell - 1, Cell - 1)
      }
   }

   GuiControlGet, Pic, Pos, Pic
   x_val := PicW//2 - FieldWidth//2
   y_val := PicH//2 - FieldHeight//2
   Gui, Child:Show, % "x" x_val " y" y_val " w" FieldWidth " h" FieldHeight
   SetTimer, Paint1, -10
   Return

Multicolor:
   GuiControlGet, Multicolor, Parent:, Multicolor
   Gdip_DeleteBrush(pAliveBrush1)
   pAliveBrush1 := Gdip_BrushCreateSolid(Multicolor ? 0xFF30B29E : AliveBrush1)
   Return

ClearGen:
   GuiControl, Parent:, Gen, % Gen := 0
   Return

ParentGuiSize:
   Gui, Parent:Default
   GuiControl, Move, Pic, % "w" A_GuiWidth " h" A_GuiHeight - ButtonField
   d := A_GuiHeight - ButtonField//2 - 23//2
   Controls2 := Controls . "|StartStop|Center"
   Loop, parse, Controls2, |
      GuiControl, Move, %A_LoopField%, % "y" d
   GuiControl, Move, TextSpeed, % "y" d + TextD
   GuiControl, Move, Slider, % "y" d + 2
   GuiControl, Move, Speed, % "y" d + TextD
   GuiControl, Move, TextSize, % "y" d + TextD
   GuiControl, Move, Multicolor, % "y" d + TextD
   trn := A_GuiWidth < 898
   GuiControl, MoveDraw, TextGen, % "x" (trn ? 788 : A_GuiWidth - 110) " y" d + 5
   GuiControl, MoveDraw, Gen, % "x" (trn ? 858 : A_GuiWidth - 40) " y" d + 4
   Return

#If !WinExist("ahk_id" hLoad) && WinActive("ahk_id" hParent)
Esc::
ParentGuiClose:
   ExitApp

Exit:
   WinGetPos, X, Y,,, ahk_id %hParent%
   WinGet, MinMax, MinMax, ahk_id %hParent%
   GuiControlGet, Pic, Parent:Pos, Pic
   Gui, Parent:Destroy

   Gdip_DeleteBrush(pBackBrush), Gdip_DeleteBrush(pAliveBrush1)
   Gdip_DeleteBrush(pAliveBrush2), Gdip_DeleteBrush(pAliveBrush3)
   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc), Gdip_DeleteGraphics(G)
   ReleaseDC(hFieldDC, hField), Gdip_Shutdown(pToken)

   IniWrite, % MinMax = -1 ? 0 : X, % IniName, Size, GuiX
   IniWrite, % MinMax = -1 ? 0 : Y, % IniName, Size, GuiY
   IniWrite, % MinMax = -1 ? 800 : PicW, % IniName, Size, FieldW
   IniWrite, % MinMax = -1 ? 500 : PicH, % IniName, Size, FieldH
   IniWrite, % Pause, % IniName, Settings, Pause
   IniWrite, % Cell, % IniName, Settings, Cell
   IniWrite, % Multicolor, % IniName, Settings, Multicolor
   ExitApp

#If WinActive("ahk_id" hParent)
RButton:: SendInput, {LButton Down}
RButton Up::
   SendInput, {LButton Up}
   SetTimer, Move, -20
   Return

Move:
   WinGetPos, X_Field, Y_Field,,, ahk_id %hField%
   WinGetPos, X_Pic, Y_Pic, W_Pic, H_Pic, ahk_id %hPic%

   if (X_Field - X_Pic > 0 && Y_Field - Y_Pic > 0)
      WinMove, ahk_id %hField%,, 0, 0

   else if (X_Field + FieldWidth < X_Pic + W_Pic && Y_Field + FieldHeight < Y_Pic + H_Pic)
      WinMove, ahk_id %hField%,, W_Pic - FieldWidth, H_Pic - FieldHeight

   else if (X_Field - X_Pic > 0 && !(Y_Field + FieldHeight < Y_Pic + H_Pic))
      WinMove, ahk_id %hField%,, 0, Y_Field - Y_Pic

   else if (X_Field - X_Pic > 0 && Y_Field + FieldHeight < Y_Pic + H_Pic)
      WinMove, ahk_id %hField%,, 0, H_Pic - FieldHeight

   else if (Y_Field - Y_Pic > 0 && !(X_Field + FieldWidth < X_Pic + W_Pic))
      WinMove, ahk_id %hField%,, X_Field - X_Pic, 0

   else if (Y_Field - Y_Pic > 0 && X_Field + FieldWidth < X_Pic + W_Pic)
      WinMove, ahk_id %hField%,, W_Pic - FieldWidth, 0

   else if (X_Field + FieldWidth < X_Pic + W_Pic)
      WinMove, ahk_id %hField%,, W_Pic - FieldWidth, Y_Field - Y_Pic

   else if (Y_Field + FieldHeight < Y_Pic + H_Pic)
      WinMove, ahk_id %hField%,, X_Field - X_Pic, H_Pic - FieldHeight

   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Return

WM_PAINT()   ; поддержка изображения при перерисовке окна
{
   global
   SetTimer, Paint1, -10
   Return

Paint1:
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   SetTimer, Paint2, -50
   Return

Paint2:
   BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   Return
}

Update_hDC(oCell)
{
   global
   if oCell.alive := !oCell.alive
      Gdip_FillRectangle(G, pAliveBrush1, oCell.x, oCell.y, Cell - 1, Cell - 1)
   Else
      Gdip_FillRectangle(G, pBackBrush, oCell.x, oCell.y, Cell - 1, Cell - 1)
}

WM_LBUTTONDOWN(wp, lp, msg, hwnd)
{
   local x, y, c, r, n, m, Time, Figures
   static PrevTime = 0
   Critical

   if A_GuiControl = DDLNames
   {
      Loop, %A_ScriptDir%\Figures\*.life
         Figures .= (A_Index = 1 ? "" : "|") . RegExReplace(A_LoopFileName, "(.*)\..*", "$1")
      Sort, Figures, D|
      GuiControl,, DDLNames, % Figures ? "|" Figures : "|No Files"
      Return
   }
   else if A_GuiControl = Pic
   {
      if GetKeyState("RButton", "P")
      {
         PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2,, AutoHotkeyGUI1
         Return
      }
   }
   Else if A_GuiControl =
   {
      PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
      Return
   }

   Time := A_TickCount

   if (StartStop || hwnd != hField || Time - PrevTime < 100)
      Return

   PrevTime := Time
   x := lp & 0xFFFF, y := lp >> 16
   c := Ceil(x/Cell), r := Ceil(y/Cell)

   UpdateNextArray(r, c), Update_hDC(CellArray[r][c])
   , BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)
   , StartX := CellArray[r][c].x, StartY := CellArray[r][c].y, StartC := c, StartR := r

   if !hPaintDC
   {
      hPaintDC := GetDC(hPic)
      GuiControlGet, Pic, Parent:Pos, Pic
      hPaintBm := CreateDIBSection(PicW, PicH)
      , hPaintMDC := CreateCompatibleDC()
      , oPaintBm := SelectObject(hPaintMDC, hPaintBm)
      , GPaint := Gdip_GraphicsFromHDC(hPaintMDC)
      WinGetPos, X_Field, Y_Field,,, ahk_id %hField%
      WinGetPos, X_Pic, Y_Pic,,, ahk_id %hPic%
      XPosField := X_Pic - X_Field, YPosField := Y_Pic - Y_Field
   }
}

WM_MOUSEMOVE(wp, lp, msg, hwnd)
{
   local x, y, c, r, p, m, n, k
   static c_prev, r_prev
   if (hwnd != hField || StartStop || !GetKeyState("LButton", "P") || !StartR || !StartX)
      Return

   x := lp & 0xFFFF, y := lp >> 16
   last_c := c := Ceil(x/Cell), last_r := r := Ceil(y/Cell)

   if ((c = c_prev && r = r_prev) || !hPaintMDC)
      Return

   c_prev := c, r_prev := r

   BitBlt(hPaintMDC, 0, 0, PicW, PicH, hdc, XPosField, YPosField)

   Brush := (CtrlState := GetKeyState("Ctrl", "P")) ? pBackBrush : pAliveBrush1

   m := Abs(r - StartR) + 1, n := Abs(c - StartC) + 1

   if GetKeyState("Alt", "P") && Var := 1
      Loop % ToolTipShow((k := m > n ? m : n) . " diagonal", k)
         Gdip_FillRectangle(GPaint, Brush
            , StartX + (c > StartC ? 1 : -1)*Cell*(A_Index - 1) - XPosField
            , StartY + (r > StartR ? 1 : -1)*Cell*(A_Index - 1) - YPosField
            , Cell - 1, Cell - 1)

   Else if !GetKeyState("Alt", "P") && Var := 2
   {
      Loop % m
      {
         p := A_Index
         Loop % ToolTipShow(p . " row`n" . n . " column", n)
            Gdip_FillRectangle(GPaint, Brush
               , StartX + (c > StartC ? 1 : -1)*Cell*(A_Index - 1) - XPosField
               , StartY + (r > StartR ? 1 : -1)*Cell*(p - 1) - YPosField
               , Cell - 1, Cell - 1)
      }
   }
   BitBlt(hFieldDC, XPosField, YPosField, PicW, PicH, hPaintMDC, 0, 0)
}

WM_LBUTTONUP(wp, lp, msg, hwnd)
{
   local n, m, p
   if (hwnd != hField || StartStop)
      Return

   ToolTip
   Critical

   m := Abs(last_r - StartR) + 1, n := Abs(last_c - StartC) + 1
   if Var = 1
      Loop % m > n ? m : n
         CurrentR := StartR + (last_r > StartR ? 1 : -1)*(A_Index - 1)
         , CurrentC := StartC + (last_c > StartC ? 1 : -1)*(A_Index - 1)
         , CellArray[CurrentR][CurrentC].alive := !CtrlState
         , UpdateNextArray(CurrentR, CurrentC)

   else if Var = 2
   {
      Loop % m
      {
         p := A_Index
         Loop % n
            CurrentR := StartR + (last_r > StartR ? 1 : -1)*(p - 1)
            , CurrentC := StartC + (last_c > StartC ? 1 : -1)*(A_Index - 1)
            , CellArray[CurrentR][CurrentC].alive := !CtrlState
            , UpdateNextArray(CurrentR, CurrentC)
      }
   }

   if !(Var && hPaintDC)
      Return

   BitBlt(hdc, XPosField, YPosField, PicW, PicH, hPaintMDC, 0, 0)
   , SelectObject(hPaintMDC, oPaintBm), DeleteObject(hPaintBm), DeleteDC(hPaintMDC)
   , Gdip_DeleteGraphics(GPaint), ReleaseDC(hPaintDC, hPic)
   , hPaintDC := Var := StartR := StartX := CtrlState := ""
}

UpdateNextArray(r, c)
{
   global NextArray
   Loop 3
   {
      n := c + A_Index - 2
      Loop 3
      {
         m := r + A_Index - 2
         if !NextArray.HasKey(m "|" n)
            NextArray[m "|" n] := {r: m, c: n}
      }
   }
}

ToolTipShow(Text, Value)
{
   ToolTip % Text
   Return Value
}

Notify(Text, ColorWin, FontName, Options, timeout, Alpha = 255, Token = 1)
{
   Options .= " q4"
   If !Token && !pToken := Gdip_Startup()
   {
      MsgBox, 48, Ошибка GDI+, Убедитесь в наличии gdiplus.dll в вашей системе!
      ExitApp
   }

   AllStyles = Italic|Bold|Underline|Strikeout
   Loop, parse, AllStyles, |
      if InStr(Options, A_LoopField)
         Styles .= A_LoopField

   if !RegExMatch(Options, "i).*s(\d+).*", Found)
   {
      MsgBox, 0x1010, Notify Error, Не задан размер шрифта!
      ExitApp
   }
   s := Found1

   x := RegExMatch(Options, "i).*x(\d+).*", Found) ? Found1 : (10, Options .= " x10")
   y := RegExMatch(Options, "i).*y(\d+).*", Found) ? Found1 : (10, Options .= " y10")
   c := RegExMatch(Options, "i).*c([0-9A-Fa-f]+)( |$)", Found) ? Found1 : ("FF000000", Options .= " cFF000000")

   ; WS_EX_LAYERED := 0x80000, WS_EX_TRANSPARENT := 0x20
   Gui, Notyfy:New, -Caption +E0x80020 +AlwaysOnTop +ToolWindow +Owner +HwndID
   Gui, Notyfy:Show, NA

   hbm := CreateDIBSection(1, 1), hdc := CreateCompatibleDC()
   obm := SelectObject(hdc, hbm), G := Gdip_GraphicsFromHDC(hdc)

   MeasureString(G, Text, FontName, Styles, s, WText, HText)
   Width := WText + 2*x, Height := HText + 2*y
   SelectObject(hdc, obm), DeleteObject(hbm), Gdip_DeleteGraphics(G)

   hbm := CreateDIBSection(Width, Height)
   obm := SelectObject(hdc, hbm), G := Gdip_GraphicsFromHDC(hdc), Gdip_SetSmoothingMode(G, 4)

   pBrush := Gdip_BrushCreateSolid(ColorWin)

   Gdip_FillRoundedRectangle(G, pBrush, 0, 0, Width-1, Height-1, Height//2 > 20 ? 20 : Height//2)
   Gdip_DeleteBrush(pBrush)

   Gdip_TextToGraphics(G, Text, Options, FontName, Width, Height)

   Alpha_ := -10
   Loop
   {
      Alpha_+=10
      UpdateLayeredWindow(ID, hdc
         , (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height, Alpha_)
      Sleep, 10
   } Until Alpha_ + 10 > Alpha

   UpdateLayeredWindow(ID, hdc
      , (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height, Alpha)

   Sleep, timeout

   Alpha_ := Alpha
   Loop
   {
      Alpha_-=10
      UpdateLayeredWindow(ID, hdc
         , (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height, Alpha_)
      Sleep, 10
   } Until Alpha_ - 10 < 0

   UpdateLayeredWindow(ID, hdc
      , (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height, 0)

   Gui, Notify:Destroy

   SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc), Gdip_DeleteGraphics(G)
   if !Token
      Gdip_Shutdown(pToken)
}

MeasureString(G, Text, FontName, Styles, Size, ByRef WText, ByRef HText)
{
   Style = 0
   StyleArray := [["Bold", 1], ["Italic", 2], ["Underline", 4], ["Strikeout", 8]]
   for key, value in StyleArray
      if InStr(Styles, value.1)
         Style += value.2

   if !hFamily := Gdip_FontFamilyCreate(FontName)
   {
      MsgBox, Указанный шрифт не поддерживается системой!
      ExitApp
   }
   hFont := Gdip_FontCreate(hFamily, Size, Style)
   FormatStyle := NoWrap ? 0x4000 | 0x1000 : 0x4000
   hFormat := Gdip_StringFormatCreate(FormatStyle)
   VarSetCapacity(RectF, 16)
   Result := Gdip_MeasureString(G, Text, hFont, hFormat, RectF)

   Gdip_DeleteStringFormat(hFormat)
   Gdip_DeleteFont(hFont)
   Gdip_DeleteFontFamily(hFamily)

   WText := RegExReplace(Result, "(.*?\|){2}(.*?)\|.*", "$2")
   HText := RegExReplace(Result, "(.*?\|){3}(.*?)\|.*", "$2")
}

WM_COMMAND(wp, lp)
{
   global hDDLNames
   CBN_CLOSEUP := 8
   if ((wp >> 16 = CBN_CLOSEUP) && lp = hDDLNames)
   {
      Gui, Load:Default
      GuiControl, Focus, OK
      GuiControlGet, Choose,, DDLNames
      if !Choose
         GuiControl,, DDLNames, Select a Name:||
   }
}

Здесь я использовал второй, рациональный алгоритм из Википедии. В коде он реализуется по метке Cycle:, насколько возможно, откомментирован. Если у кого-то возникнут мысли по оптимизации, поделитесь!
Фигура для загрузки на пробу. Папка Figures должна быть помещена в директорию скрипта.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

41

Re: AHK: игра «Жизнь» [Life]

Не запускается почему-то. AutoHotkey_L установил, в Lib Gdip положил, запускаю из той же папки.

Error:  Missing "{"

    Line#
    168: GuiControl,Parent:,StartStop,Start
    169: Loop,parse,Controls,|
    170: GuiControl,Parent:Enable,%A_LoopField%
    171: Break
    172: }
    174: For k,v in CurrentArray
    175: c := v.c, r := v.r, UpdateNextArray(r, c), CellArray[r][c].alive := v.alive  
--->    177: }
    178: BitBlt(hFieldDC, 0, 0, FieldWidth, FieldHeight, hdc, 0, 0)  
    179: Sleep,Pause
    180: }
    180: Until,!StartStop
    181: StartStop := 0
    182: Return
    186: if StartStop  

The program will exit.

42 (изменено: Zohann, 2011-12-10 15:14:43)

Re: AHK: игра «Жизнь» [Life]

А, оказывается ANSI x86 надо было установить.
Ну ваще крутяк! Чотко! Могете!
Одно замечание: Старт-Стоп-Старт и счетчик генерации опять с нуля.
Чую, сила в Gdip, да туториала на русском нет...

43

Re: AHK: игра «Жизнь» [Life]

Zohann пишет:

А, оказывается ANSI x86 надо было установить.

ANSI версия - скрипт запускается в любой кодировке, Unicode версия - скрипт запускается только в UTF-8.

Zohann пишет:

...туториала на русском нет...

Нет, но разобраться можно:

#NoEnv
SetBatchLines, -1
CoordMode, Pixel
CoordMode, Mouse
; установка единого курсора
SetDefinedCursor(32515) ; IDC_CROSS
; создание прозрачного окна
Gui, +AlwaysOnTop -Caption +E0x80000 +HwndGUIhWnd +Owner
Gui, Show, w150 h150, 10xZoom
WinMove, % "ahk_id"GUIhWnd,, A_ScreenWidth/2-76, A_ScreenHeight/2-76
; обработка клика по не клиентской области окна
OnMessage(0x201, "WM_NCLBUTTONDOWN")
; загрузка нужной библиотеки
hModule:=DllCall("LoadLibrary", "Str", "gdiplus.dll")
; выделение памяти под структуру
VarSetCapacity(GdiplusStartupInput, 16, 0)
; инициализация структуры, вернее необходимого поля, остальные можно не декларировать
NumPut(1, GdiplusStartupInput, 0, "Char") ; GdiplusVersion
; инициализация Windows GDI+ с получением указателя нужного, чтобы потом закрыть
DllCall("gdiplus\GdiplusStartup", "UInt*", pToken, "UInt", &GdiplusStartupInput)
; выделение памяти под структуру
VarSetCapacity(BITMAPINFO, 40, 0)
; инициализация структуры
NumPut(40, BITMAPINFO, 0) ; biSize
NumPut(150, BITMAPINFO, 4) ; biWidth
NumPut(150,BITMAPINFO, 8) ; biHeight
NumPut(1, BITMAPINFO, 12, "UShort") ; biPlanes
NumPut(32, BITMAPINFO, 14, "UShort") ; biBitCount
NumPut(0, BITMAPINFO, 16) ; biCompression
; получение дескриптора созданого аппаратно-независимого растра (Device Independent Bitmap)
hBitmap:=DllCall("CreateDIBSection", "UInt", hDC
                                   , "UInt", &BITMAPINFO
                                   , "UInt", 0
                                   , "UInt*", 0
                                   , "UInt", 0
                                   , "UInt", 0)
; высвобождение контекста устройства для других приложений
DllCall("ReleaseDC", "UInt", 0, "UInt", hDC)
; получение дескриптора памяти контекста устройства
hMemDC:=DllCall("CreateCompatibleDC", "UInt", 0) ; current screen
; выбор объекта в заданный контекст устройства
DllCall("SelectObject", "UInt", hMemDC, "UInt", hBitmap)
; получение указателя объекта Graphics из дескриптора контекста устройства
DllCall("gdiplus\GdipCreateFromHDC", "UInt", hMemDC, "UInt*", pGraphics)
; создание двух переменных содержащих шестнадцатиричное число (степень прозрачности и цвет)
Color1:=0xFF000000, Color2:=0xFFFFFFFF ; argb
; создание объектов класса Pen
GdipCreatePen(Color1, pPen1) ; black line
GdipCreatePen(Color2, pPen2) ; white line
GdipCreatePen(Color1, pPen3) ; black dot rect
GdipCreatePen(Color1, pPen4) ; black rect
; назначение своего стиля объекту
DllCall("gdiplus\GdipSetPenDashStyle", "UInt", pPen1
                                     , "Char", 5) ; DashStyleCustom
; выделение памяти под структуру массива
VarSetCapacity(Array, 8, 0)
; инициализация структуры массива
NumPut(4, Array, 0, "Float") ; dash lenght
NumPut(3, Array, 4, "Float") ; space lenght
; присвоение массива объекту
DllCall("gdiplus\GdipSetPenDashArray", "UInt", pPen1
                                     , "Int", &Array
                                     , "Int", 2) ; count
; назначение стиля объекту
DllCall("gdiplus\GdipSetPenDashStyle", "UInt", pPen3
                                     , "Char", 2) ; DashStyleDot
; создание объекта класса Brush
DllCall("gdiplus\GdipCreateSolidFill", "Int", Color1, "UInt*", pBrush)
SetTimer, ChaseCursor, 10
OnExit, ExitScript
Return

ChaseCursor:
   MouseGetPos, XPos, YPos
; присвоение цвета и заливка объектов Brush
   Loop, 15
      GdipDrawLine(A_Index-1)
; отрисовка линий объектами Pen
   GdipDrawObject("Line", pPen2, 0, 75, 70, 75) ; white line
   GdipDrawObject("Line", pPen2, 80, 75, 150, 75)
   GdipDrawObject("Line", pPen2, 75, 0, 75, 70)
   GdipDrawObject("Line", pPen2, 75, 80, 75, 150)
   GdipDrawObject("Line", pPen1, 69, 75, 1, 75) ; black dash line
   GdipDrawObject("Line", pPen1, 81, 75, 147, 75)
   GdipDrawObject("Line", pPen1, 75, 69, 75, 1)
   GdipDrawObject("Line", pPen1, 75, 81, 75, 147)
; отрисовка прямоугольников объектами Pen
   GdipDrawObject("Rectangle", pPen2, 70, 70, 10, 10) ; white center rect
   GdipDrawObject("Rectangle", pPen3, 70, 70, 10, 10) ; black dot center rect
   GdipDrawObject("Rectangle", pPen4, 0, 0, 149, 149) ; black outside rect
; обновление многослойного окна
   DllCall("UpdateLayeredWindow", "UInt", GUIhWnd
                                , "UInt", 0
                                , "UInt", 0
                                , "Int64*", 0x09600000096 ; 150x150
                                , "UInt", hMemDC
                                , "Int64*", 0
                                , "UInt", 0
                                , "UInt*", 0x01FF0000 ; BLENDFUNCTION
                                , "UInt", 2)
   Return

ExitScript:
; высвобождение ресурсов
   DllCall("gdiplus\GdiplusShutdown", "UInt", pToken)
   DllCall("FreeLibrary", "UInt", hModule)
; восстановление системных курсоров
   DllCall("SystemParametersInfo", "UInt", 0x57 ; SPI_SETCURSORS
                                 , "UInt", 0
                                 , "UInt", 0
                                 , "UInt", 0)
   ExitApp

WM_NCLBUTTONDOWN()
{
   global
   PostMessage, 0xA1, 2,,, % "ahk_id"GUIhWnd ; WM_NCLBUTTONDOWN, HTCAPTION
}

GdipDrawLine(Y)
{
   global
   Loop, 15
   {
      PixelGetColor, CurrentColor, XPos-7+A_Index-1, YPos-7+Y, RGB
      DllCall("gdiplus\GdipSetSolidFillColor", "UInt", pBrush
                                             , "UInt", CurrentColor|0xFF000000)
      DllCall("gdiplus\GdipFillRectangle", "UInt", pGraphics
                                         , "UInt", pBrush
                                         , "Float", (A_Index-1)*10
                                         , "Float", Y*10
                                         , "Float", 10 ; w
                                         , "Float", 10) ; h
   }
}

GdipCreatePen(PenColor, ByRef pPenN)
{
   global
   DllCall("gdiplus\GdipCreatePen1", "Int", PenColor
                                   , "Float", 1 ; width
                                   , "Char", 2 ; unit - pixel
                                   , "UInt*", pPenN)
}

GdipDrawObject(Kind, pPenN, FromX, FromY, IntoX, IntoY)
{
   global
   DllCall("gdiplus\GdipDraw" . Kind, "UInt", pGraphics
                                    , "UInt", pPenN
                                    , "Float", FromX
                                    , "Float", FromY
                                    , "Float", IntoX
                                    , "Float", IntoY)
}

SetDefinedCursor(Cursor)
{
   SystemCursors:="
   ,32512,32513,32514,32515,32516,32640,32641,32642
   ,32643,32644,32645,32646,32648,32649,32650,32651"
   Loop, Parse, SystemCursors, `,
   {
      If % A_Loopfield=Cursor
      {
         Loop, Parse, SystemCursors, `,
         {
            hCursor:=DllCall("LoadCursor", "UInt", 0, "Int", Cursor)
            hCursor:=DllCall("CopyImage", "UInt", hCursor
                                        , "UInt", 0x2 ; IMAGE_CURSOR
                                        , "Int", 28 ; w
                                        , "Int", 28 ; h
                                        , "UInt", 0)
            DllCall("SetSystemCursor", "UInt", hCursor
                                     , "Int", A_Loopfield)
         }
      }
   }
}

Это кусок кода для примера, плюс добавил комментарии.

44

Re: AHK: игра «Жизнь» [Life]

Увидев "получение дескриптора созданого аппаратно-независимого растра" стало не по себе малость). Спасибо, буду разбираться.

45

Re: AHK: игра «Жизнь» [Life]

Grey пишет:
Zohann пишет:

...туториала на русском нет...

Нет, но разобраться можно:

Удобнее пользоваться уже написанной библиотекой.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

46 (изменено: Grey, 2011-12-11 21:17:01)

Re: AHK: игра «Жизнь» [Life]

Честно говоря к библиотеке не обращался, на оффоруме попался скрипт с названием Analog Clock, вот там посмотрел пример использования, ну и + MSDN. Кстати конкретно по пунктирам в Gdip.ahk ни слова. Стоит ещё отметить, что в Win7 при активной теме со степенью прозрачности окантовки окон (Aero), наблюдаются тормоза, у программ Color Spy, InqSoft Window Scanner (использующих эту же подсистему для аналогичных целей) такого нет.

47

Re: AHK: игра «Жизнь» [Life]

Grey пишет:

Стоит ещё отметить, что в Win7 при активной теме со степенью прозрачности окантовки окон (Aero), наблюдаются тормоза, у программ Color Spy, InqSoft Window Scanner (использующих эту же подсистему для аналогичных целей) такого нет.

А какие именно тормоза?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

48

Re: AHK: игра «Жизнь» [Life]

Окно и туллтип обновляются раза в 3-4 медленнее.

49

Re: AHK: игра «Жизнь» [Life]

Ясно, спасибо.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder