open System
open System.Windows.Forms
open System.Drawing
open Microsoft.FSharp.Control.CommonExtensions
open System.Collections.Generic
open System.IO

let SS = DateTime.Now
     
let Sqr a = a*a

let Dist (a:(int*int)) (b:(int*int)) =
    Sqr ((fst a)-(fst b)) + Sqr ((snd a)-(snd b))

let Vect x1 y1 x2 y2 x3 y3 =
    let (dx1, dy1) = (x1-x2, y1-y2)
    let (dx2, dy2) = (x3-x2, y3-y2)
    match (dx1*dy2-dx2*dy1) with
        | p when p<0 -> -1
        | p when p>0 -> +1
        | _ -> 0

let isInter xx yy rr x1 y1 x2 y2 =
    let mutable d = 1000000000
    d <- min d (Dist (xx, yy) (x1, y1))
    d <- min d (Dist (xx, yy) (x2, y2))
    if ((Vect xx yy x1 y1 x2 y2) * (Vect xx yy x2 y2 x1 y1) > 0) then
        let a = y2-y1
        let b = x1-x2
        let c = -a*x1-b*y1
        Sqr (a*xx+b*yy+c) <= (Sqr rr)*(Sqr a + Sqr b)
    else
        d <= Sqr rr

let isIntersects xx yy rr x y w h =
    (isInter xx yy rr x y (x+w) y ||
     isInter xx yy rr (x+w) y (x+w) (y+h) ||
     isInter xx yy rr (x+w) (y+h) x (y+h) ||
     isInter xx yy rr x (y+h) x y)

let dCell = 20
let dCirc = 11
    
type IPaintObject =
    abstract Paint : Graphics -> unit
    abstract Recalc : float -> unit

type DelegateLoad = delegate of (string) -> (int[][]*ResizeArray<IPaintObject>*int)
    
let po = new ResizeArray<IPaintObject>()

type SmoothForm(dx:int, dy:int, _path:string) as x =
    inherit Form()
    do x.DoubleBuffered <- true

    let mutable left = 0
    let mutable down = 0
    let mutable right = 0
    let mutable up = 0
    let mutable need = 0
    let mutable path = _path
    let mutable currLevel = 0
    let mutable complete = 0
    let mutable (dd:DelegateLoad) = null
    let mutable death = 0
    let mutable loading = 0

    let mutable Map = null

    let d = new Dictionary<int, double*double>()

    member x.Load(_map:int[][], obj, _need) = 
        Map <- _map
        po.Clear()
        for o in obj do
            po.Add o
        need <- _need
        x.Init()

    member x.LoadNext() =
        currLevel <- currLevel + 1
        if (File.Exists(path+""+"L"+currLevel.ToString()+".txt") = false) then
            complete <- 1
        else
            x.Loading <- 2
            x.Load(dd.Invoke(path+""+"L"+currLevel.ToString()+".txt"))
            x.Loading <- 0
        x.Invalidate()


    member x.Init() =
        left <- 0
        down <- 0
        right <- 0
        up <- 0

        let mm = Map |> Array.map(fun x -> x |> Array.max) |> Array.max
        let xMin = Array.create (mm+1) 1000.0
        let xMax = Array.create (mm+1) 0.0
        let yMin = Array.create (mm+1) 1000.0
        let yMax = Array.create (mm+1) 0.0
        for i = 0 to x.rows-1 do
            for j = 0 to x.cols-1 do
                if (Map.[i].[j]>0) then
                    let p = Map.[i].[j]
                    xMin.[p] <- min (xMin.[p]) (float (j*dx))
                    xMax.[p] <- max (xMax.[p]) (float ((j+1)*dx))
                    yMin.[p] <- min (yMin.[p]) (float (i*dy))
                    yMax.[p] <- max (yMax.[p]) (float ((i+1)*dy))
        d.Clear()
        for i in [1..mm] do
            d.Add(i, ((xMin.[i]+xMax.[i])/2., (yMin.[i]+yMax.[i])/2.))

    member x.FuncLoad with get() = dd and set(v) = (dd <- v)

    member x.Complete = complete
    member x.Death with get() = death and set(v) = (death <- v)
    member x.Path with get() = path and set(v) = (path <- v)
    member x.map = Map
    member x.Saves = d
    member x.needGather = need
    member x.Loading with get() = loading and set(v) = (loading <- v)

    member x.Left with get() = left and set(v) = (left <- v)
    member x.Right with get() = right and set(v) = (right <- v)
    member x.Down with get() = down and set(v) = (down <- v)
    member x.Up with get() = up and set(v) = (up <- v)        

    member x.DX = dx
    member x.DY = dy
    member x.rows = (Map |> Array.length)
    member x.cols = (Map.[0] |> Array.length)

let form = new SmoothForm(Text="F# The world hardest game",  Visible=true, TopMost=true,
                            Width=22*dCell+8, Height=14*dCell+33,
                            dx=dCell, dy=dCell,
                            FormBorderStyle=FormBorderStyle.FixedSingle,
                            _path = @"C:Documents and SettingsslimМои документыVisual Studio 2010ProjectsTCFS_Console")

form.KeyDown
    |> Event.filter(fun args -> (args.KeyValue >= 37) && (args.KeyValue <= 40)) 
    |> Event.add (fun args ->
        match (args.KeyCode) with
            | Keys.Down -> form.Down <- 1
            | Keys.Left -> form.Left <- 1
            | Keys.Right -> form.Right <- 1
            | Keys.Up -> form.Up <- 1     
        )

form.KeyUp
    |> Event.filter(fun args -> (args.KeyValue >= 37) && (args.KeyValue <= 40))
    |> Event.add (fun args ->
        match (args.KeyCode) with
            | Keys.Down -> form.Down <- 0
            | Keys.Left -> form.Left <- 0
            | Keys.Right -> form.Right <- 0
            | Keys.Up -> form.Up <- 0
        )

form.Paint.Add(fun arg ->
    let g = arg.Graphics
    if (form.Complete = 0) then
        if (form.Loading = 0) then
            for i=0 to form.rows-1 do
                for j=0 to form.cols-1 do
                    match (form.map.[i].[j], (i+j)%2) with
                        | (-1, _) -> g.FillRectangle(Brushes.DarkViolet, j*form.DX, i*form.DY, form.DX, form.DY)
                        | ( 0, 0) -> g.FillRectangle(Brushes.White, j*form.DX, i*form.DY, form.DX, form.DY)
                        | ( 0, 1) -> g.FillRectangle(Brushes.LightGray, j*form.DX, i*form.DY, form.DX, form.DY)
                        | ( p, _) when p>0 -> g.FillRectangle(Brushes.LightGreen, j*form.DX, i*form.DY+1, form.DX, form.DY)
                    if (i>0 && (form.map.[i].[j]>=0 && form.map.[i-1].[j]<0
                            ||  form.map.[i].[j]<0 && form.map.[i-1].[j]>=0)) then
                        g.DrawLine(new Pen(Color.Black, float32 2), j*form.DX, i*form.DY, (j+1)*form.DX, i*form.DY)
                    if (j>0 && (form.map.[i].[j]>=0 && form.map.[i].[j-1]<0
                            ||  form.map.[i].[j]<0 && form.map.[i].[j-1]>=0)) then
                        g.DrawLine(new Pen(Color.Black, float32 2), j*form.DX, i*form.DY, j*form.DX, (i+1)*form.DY)
            for obj in po do
                obj.Recalc((DateTime.Now-SS).TotalSeconds)
                obj.Paint(g)
            async { do! Async.Sleep(10)
                    form.Invalidate() } |> Async.Start
        else
            if (form.Loading = 1) then
                form.LoadNext()
    else
        g.FillRectangle(Brushes.Magenta, 0, 0, form.Width, form.Height);
        g.DrawString("Deaths: " + form.Death.ToString(), new Font(FontFamily.GenericMonospace, float32 32.), Brushes.Black, float32 20., float32 100.)
)

type RedSquare(xx:int, yy:int, ww:int, hh:int, speed:int) =
    let mutable xCoord = float xx
    let mutable yCoord = float yy
    let mutable width = ww
    let mutable height = hh
    let mutable dying = 0
    let mutable gather = 0
    let mutable last = 0.0
    let mutable xSave = float xx
    let mutable ySave = float yy
    let mutable lastSave = 1

    member rs.X with get() = int xCoord and set(v) = (xCoord <- v)
    member rs.Y with get() = int yCoord and set(v) = (yCoord <- v)
    member rs.W with get() = width and set(v) = (width <- v)
    member rs.H with get() = height and set(v) = (height <- v)
    member rs.Got with get() = gather
    member rs.isDying with get() = (dying>0)

    member rs.Die() =
        if (dying = 0) then
            dying <- 1
            gather <- 0
            form.Death <- form.Death+1
    member rs.Add() =
        gather <- gather+1

    interface IPaintObject with
        member obj.Paint(g) =
            let rect = 
                match (dying) with
                    | 0 -> Rectangle(x=int xCoord-width/2, y=int yCoord-height/2, width=width, height=height)
                    | p when 2*p>=ww ->
                                        xCoord <- xSave
                                        yCoord <- ySave
                                        dying <- 0
                                        Rectangle(x=int xCoord-width/2, y=int yCoord-height/2, width=width, height=height)
                    | p ->
                            dying <- dying+1
                            Rectangle(x=int xCoord-width/2+p, y=int yCoord-height/2+p, width=width-p-p, height=height-p-p)
            g.FillRectangle(Brushes.Red, rect)
            g.DrawRectangle(new Pen(Color.Black, float32 2), rect)
        member obj.Recalc(T) =
            let t = T-last
            let mutable xOld = 0.0
            let mutable yOld = 0.0

            if (dying=0) then
                xOld <- xCoord
                yOld <- yCoord
                xCoord <- xCoord - ((float (form.Left))*(float speed)*t)
                if (form.map.[int (yCoord-float height/2.)/dCell].[int (xCoord-float width/2.)/dCell]<0 ||
                    form.map.[int (yCoord+float height/2.)/dCell].[int (xCoord-float width/2.)/dCell]<0) then
                    xCoord <- xOld
                    yCoord <- yOld

                xOld <- xCoord
                yOld <- yCoord
                xCoord <- xCoord + ((float (form.Right))*(float speed)*t)
                if (form.map.[int (yCoord-float height/2.)/dCell].[int (xCoord+float width/2.)/dCell]<0 ||
                    form.map.[int (yCoord+float height/2.)/dCell].[int (xCoord+float width/2.)/dCell]<0) then
                    xCoord <- xOld
                    yCoord <- yOld

                xOld <- xCoord
                yOld <- yCoord
                yCoord <- yCoord - ((float (form.Up))*(float speed)*t)
                if (form.map.[int (yCoord-float height/2.)/dCell].[int (xCoord-float width/2.)/dCell]<0 ||
                    form.map.[int (yCoord-float height/2.)/dCell].[int (xCoord+float width/2.)/dCell]<0) then
                    xCoord <- xOld
                    yCoord <- yOld

                xOld <- xCoord
                yOld <- yCoord
                yCoord <- yCoord + ((float (form.Down))*(float speed)*t)
                if (form.map.[int (yCoord+float height/2.)/dCell].[int (xCoord-float width/2.)/dCell]<0 ||
                    form.map.[int (yCoord+float height/2.)/dCell].[int (xCoord+float width/2.)/dCell]<0) then
                    xCoord <- xOld
                    yCoord <- yOld

                let rr = int yCoord/dCell
                let cc = int xCoord/dCell
                if (form.map.[rr].[cc] > lastSave && form.map.[rr].[cc] <> form.Saves.Count) then
                    lastSave <- form.map.[rr].[cc]
                    xSave <- fst form.Saves.[lastSave]
                    ySave <- snd form.Saves.[lastSave]

                if (form.map.[rr].[cc] = form.Saves.Count && gather = form.needGather) then
                    form.Loading <- 1
                    
            last <- T

type BlueCircle(xx:int, yy:int, rr:int, speed:int, segments:(int*int)[]) =
    let len = segments |> Array.length

    let mutable X = xx
    let mutable Y = yy
       
    member bc.Stable with get() = (bc.TotalDist < 1e-8)
    member bc.Speed with get() = float speed
    member bc.Dists = segments |> Array.map(fun (dx, dy) -> Math.Sqrt(float(dx*dx+dy*dy)))
    member bc.TotalDist = bc.Dists |> Array.sum
    member bc.TotalTime = bc.TotalDist/bc.Speed

    interface IPaintObject with
        member obj.Paint(g) =
            let rect = Rectangle(x=X-rr, y=Y-rr, width=rr+rr, height=rr+rr)
            g.FillEllipse(Brushes.Blue, rect)
            g.DrawEllipse(Pens.Black, rect)
        member bc.Recalc(tt) =
            if (bc.Stable=false) then
                let mutable t1 = tt�.TotalTime
                let mutable ind = 0
                X <- xx
                Y <- yy
                while (ind<len-1 && t1*bc.Speed>=bc.Dists.[ind]) do
                    X <- X + (fst segments.[ind])
                    Y <- Y + (snd segments.[ind])
                    t1 <- t1-bc.Dists.[ind]/bc.Speed
                    ind <- ind+1
            
                let (dx, dy) = (((float (fst segments.[ind]))/(bc.Dists.[ind])),
                                ((float (snd segments.[ind]))/(bc.Dists.[ind])))
                X <- X + int (dx*t1*bc.Speed)
                Y <- Y + int (dy*t1*bc.Speed)

                let rs = seq { for obj in po do
                                    match obj with
                                        | :? RedSquare as p ->
                                            yield p 
                                        | _ -> yield! Seq.empty
                                } |> Seq.head

                if (isIntersects X Y rr (rs.X-rs.W/2) (rs.Y-rs.H/2) (rs.W) (rs.H)) then
                    rs.Die()

type YellowCircle(xx:int, yy:int, rr:int, tr:float) =
    let mutable XX = 0
    let mutable Disable = false

    member yc.isDead with get() = Disable and set(v) = (Disable <- v)
    member yc.Take() =
        yc.isDead <- true

    interface IPaintObject with
        member obj.Paint(g) =
            if (not Disable) then
                let rect = Rectangle(x=xx-rr+XX, y=yy-rr, width=rr+rr-XX-XX, height=rr+rr)
                g.FillEllipse(Brushes.Yellow, rect)
                g.DrawEllipse(Pens.Black, rect)
        member yc.Recalc(tt:float) =
            let rs =  seq { for obj in po do
                                match obj with
                                    | :? RedSquare as p ->
                                        yield p 
                                    | _ -> yield! Seq.empty
                            } |> Seq.head
            if (not Disable && rs.isDying=false) then
                let mutable t = tt%tr
                if (t*2.>tr) then t <- tr-t
                XX <- int (((float rr)/(tr/2.))*t)

                if (isIntersects xx yy rr (rs.X-rs.W/2) (rs.Y-rs.H/2) (rs.W) (rs.H)) then
                    yc.Take()
                    rs.Add()
            else
                if (Disable && rs.isDying=true) then
                    Disable <- false

// Ф-ция парсит файл по заданому пути, выковыривая параметры уровня
let LoadLevel _path =
    let pp = new ResizeArray<IPaintObject>()

    let data = File.ReadAllLines(_path) |> Array.toSeq;
    let tmp = 0
    let tmpD = 0.0
    let nm = (data |> Seq.head).Split([|' '|])
    let (n, m) = (Int32.Parse(nm.[0]), Int32.Parse(nm.[1]))
    let L1 = data
             |> Seq.skip 1
             |> Seq.take n
             |> Seq.toArray
             |> Array.map(fun x -> x.Split([|' '|]) |> Array.filter(fun x -> Int32.TryParse(x, ref tmp)) |> Array.map(fun x -> Int32.Parse(x)))

    let lbc = Int32.Parse(data
             |> Seq.skip (1+n)
             |> Seq.head)

    let bc = data
             |> Seq.skip 1
             |> Seq.skip n
             |> Seq.skip 1
             |> Seq.take lbc
             |> Seq.toArray
             |> Array.map(fun x ->
                    let b = x.Replace('.', ',').Split([|' '|]) |> Array.filter(fun x -> Double.TryParse(x, ref tmpD)) |> Array.map(fun x -> Double.Parse(x))
                    let c = int (b.[4])
                    let move = 
                        [|
                            for i in [0..c-1] do
                                yield (int(b.[5+2*i]*(float)dCell), int(b.[5+2*i+1]*(float)dCell))
                        |]
                    new BlueCircle(int (b.[0]*(float)dCell), int (b.[1]*(float)dCell), int(b.[2]*(float)dCirc), int(b.[3]*(float)dCell), move)
                )

    let ly = Int32.Parse(data
             |> Seq.skip 1
             |> Seq.skip n
             |> Seq.skip 1
             |> Seq.skip lbc
             |> Seq.head)

    let y = data
             |> Seq.skip 1
             |> Seq.skip n
             |> Seq.skip 1
             |> Seq.skip lbc
             |> Seq.skip 1
             |> Seq.take ly
             |> Seq.toArray
             |> Array.map(fun x ->
                    let b = x.Replace('.', ',').Split([|' '|]) |> Array.filter(fun x -> Double.TryParse(x, ref tmpD)) |> Array.map(fun x -> Double.Parse(x))
                    new YellowCircle(int (b.[0]*(float)dCell), int (b.[1]*(float)dCell), int(b.[2]*(float)dCirc), (b.[3]))
                )

    let rs = data         
             |> Seq.skip 1
             |> Seq.skip n
             |> Seq.skip 1
             |> Seq.skip lbc
             |> Seq.skip 1
             |> Seq.skip ly
             |> Seq.take 1
             |> Seq.toArray
             |> Array.map(fun x ->
                    let b = x.Replace('.', ',').Split([|' '|]) |> Array.filter(fun x -> Double.TryParse(x, ref tmpD)) |> Array.map(fun x -> Double.Parse(x))
                    new RedSquare(int (b.[0]*(float)dCell), int (b.[1]*(float)dCell), int(b.[2]), int(b.[3]), int(b.[4]*(float dCell)))
             )
             |> Array.toSeq
             |> Seq.head
    for obj in bc do
        pp.Add obj

    for obj in y do
        pp.Add obj

    pp.Add rs
    (L1, pp, ly)

form.FuncLoad <- new DelegateLoad(LoadLevel)
form.LoadNext()

form.Show()

#if COMPILED
[<STAThread>]
do Application.Run(form)
#endif

Add a code snippet to your website: www.paste.org