Showing posts with label English. Show all posts
Showing posts with label English. Show all posts

Thursday, January 8, 2026

Meteor Defence: An Android game developed with Unity







Download Link:


The story that began with SnakeCraft continues with Meteor Defence. So what happened after SnakeCraft? First, we sent the application, which had moved from "Draft" status, to "Closed Testing," and then 14 days later, we sent it for "Production" approval. If it's accepted, your application is listed on the Google Play Store. We succeeded twice, and both SnakeCraft and Meteor Defence were listed on the Store. It hasn't even been a week yet, but how much did we earn from the first game? Excluding the money from testers testing, we've earned a pittance. Anyway, this is a bit of a dystopian piece. Let's talk a little about our new game. The game's description is as follows:

"Judgment Day has arrived. The rich have boarded spaceships and left the planet. The poor are left to face their fate. Now those who remain must make a magnificent finale. But the end is inevitable. Defend your planet against deadly meteors."

Of course, we're talking about a dystopian universe here! In this universe, the planet has reached its end, and meteors have begun to rain down from the sky. Those who remain believe that while there's no escape from the end, they can make it brighter. This belief eventually turns into resistance against nature, but of course, there's no escape from the end.

I tried to visualize this scene in the game. You have air defense systems and you try to destroy as many meteors as possible. The meteors speed up and multiply over time. As you destroy meteors, you build fortifications with the resources you obtain, and your health constantly increases. I wanted to give you a little hope here because even though your health reaches high values, it will eventually be 0! Of course, if you close the game before it's finished, that's another story.

The game offers about 10 minutes of gameplay with normal gameplay. You might see a one-time ad when you start the game, but you won't encounter any ads in the rest of the gameplay. Whether this will change later is another matter; it won't be like the government reducing the state contribution to the private pension scheme from 30% to 20%. I think I prefer slightly stricter policies regarding reliability. At the start of the game, you can choose your weapon power. This power allows you to fire more shots per second. You can also upgrade it to defend yourself until your arms and legs ache – the choice is yours. The most important part is that you fire by tapping the touchscreen.

So what happens next? Finally, I'll release another puzzle game. I'll see what happens after that depending on the situation.

Wednesday, December 31, 2025

Making Dashed Line in Unity!

There's probably no web developer who doesn't know the famous dashed line. Especially when you select "dashed" as a style on the border of a web element, voila, there you have it, the dashed line! Let's show an example below:
 

Easy peacy! But wait I need dashed line in Unity. So let's start!

First of all, we need to know exactly what we're going to do. We need a line, this line should be multiple and have gaps between them, and it would be good if it could move!

Lets start with line texture:


You can save this to your computer if you want. We copy this into the Unity project and select its properties as follows:


The key point here is that "Wrap Mode" must be set to "repeat". So the texture is ready. In the next step, we will create a dashed line using this texture. For this purpose, we will use a Shader. Right-click on the folder where we will create the Shader and select Create > Shader Graph > URP > Sprite Unlit Shader Graph. Let's work deductively, and when the graph is finished, it will look like this:


Let's explain the steps in order. First, we create an input of type Texture2D. To include this input in the shader graph, we add a "Sample Texture 2D" node and connect the texture input to the texture input of this node. To multiply and move our lines according to our purpose, we add a "Tiling and Offset" node. The value we give to the "x" value of the Tiling input corresponds to the number of breaks. If we want to move, we split the output of the "Tiling and Offset" node using the "Split" node. The R output will correspond to the "x" value and the G output will correspond to the "y" value. Since we will be moving along the x-axis, we preferably add a "Subtract" node before the x value. Since the x value will decrease over time, we add a "Time" node and, preferably to control the movement speed, we add a "Multiply" node, connecting the "Time" output and the x output to the "Subtract" node. Finally, we connect the output of a "Vector2" node to the UV input of the "Sample Texture 2D" node. We also make sure to connect the RGBA output of this node to the BaseColor input of the "Fragment" node and the A output to the Alpha input. And there you have it!

After creating the graph, right-click on it and select Create > Material to create a "Material". Now all you have to do is create a "Line Renderer" and select the newly created object as the Material.

Once you've completed all the steps, you'll have a moving dashed line!




Sunday, December 14, 2025

SnakeCraft - Making Android game with unity





aa



Download Link:


You can install the game on your Android phone by clicking the link above, selecting the package manager, and completing the security verification. 

In this article, we delved into a completely different topic: game development with Unity. This playground has developed surprisingly much compared to the past, so much so that you can find countless tutorial videos on YouTube. So I thought, why not make one myself? But how does asset creation work? I had AI draw it. I drew it, but of course, I couldn't do much fine-tuning. But still, a game came out of it. Now we need to make some money. For that, there's AdMob. This was great; I was able to finish the process quickly. Quick, but get your driver's license and passport ready. Since I didn't have a passport, I sent my residence permit, and they accepted it, thankfully. So how do we publish this game? We signed up for the Google Play console. Google has made such a mind-boggling console; you need to be a Google engineer to understand what's where and how. Anyway, I researched and found out that we needed to complete a closed test. You informed within the console. For the closed test, you need 12 users, and these users need to test the game for 14 days. Okay, we understand you're implementing this to prevent quality from dropping or to improve declining quality, but am I a company that's going to find 12 people to test it for 14 days? Let's say we distribute it to friends and family. According to my research, Mr. Google might not like that either and extend the process for another 14 days until they're satisfied. Also, I couldn't create an email link to send to the testers. It's impossible to understand by searching at the interface. For example, the status shows "under review," and the game is in draft. What is a draft? Who is reviewing it? What will happen after it's reviewed? Maybe that's why the link isn't visible. I asked the AI, and it couldn't figure it out either. Anyway, people who do this kind of work can copy the link from YouTube videos; hopefully, I'll be able to copy it someday. Additionally, you need to fill out many surveys and create a privacy policy. Finally, you need to pay $25 to use the Google Play console. I wrote this article to share my experiences in case anyone is interested. However, they withdraw the money incredibly quickly; I've never seen a system that does that. Despite everything, YouTube is free, so let's not deny them their due.

Update: To begin closed testing, you need to wait up to 14 days for review process. After process application, status will change from draft and link become usable. So closed tests could be continued.


Saturday, May 14, 2022

Generating GUID in excel using macro

For some reason, you may need to generate GUID in an excel document. For me, because of using GUID as primary keys in database, I have needed to generate insert scripts and GUIDs as primary keys. First of all you need to activate developer options of excel. After that, you are able to write macros. Finally, create a module and create function given below:

Function createguid()
Dim guid As String
guid = CreateObject("WScript.Shell").Exec("powershell -command [guid]::newGuid().ToString()").StdOut.ReadAll
createguid = Application.WorksheetFunction.Clean(guid)
End Function
In this approach, powershell is used for GUID generation. You can use this function in formulas after creation. Only drawback of this method is powershell console is opened and closed as many as generated GUIDs. 

Saturday, December 25, 2021

Dynamically rendering HTML to image with javascript and SVG without using any external library

In this article, we render CSS styled HTML to image. With this method, HTML can be exported to png, jpeg or bmp without using any external js library. SVG 2 is a new recommendation that is exposed by w3 consortium. SVG 2 has a new feature, foreign object, that enables us to use different rendering engines in a SVG representation. So, we use HTML rendering engine to render image representation of HTML. Example codes are at below:

<div id="export_html_to_svg_container" style="display: flex;flex-direction: row;width: 300px; height: 100px;flex-grow: 1">
    <div style="width: 100%; background-color: #ff7070;"></div>
    <div style="display: flex;justify-content: center;text-align: center;align-items: center;width: 100%;background: #a624a8;font-weight: 500;color: white;">OUTPUT</div>
    <div style="width: 100%; background-color: #7070ff;"></div>
</div>

<div style="margin-top:10px">
    <button onclick="exportToImage('png')">PNG</button>
    <button onclick="exportToImage('jpeg')">JPEG</button>
    <button onclick="exportToImage('bmp')">BMP</button>
</div>

<script>

    function exportToImage(imageType) {

        let content = document.getElementById("export_html_to_svg_container");
        let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        let foreignObject = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");      

        svg.appendChild(foreignObject);
        foreignObject.innerHTML = content.outerHTML;
        svg.setAttribute("width", "300px");
        svg.setAttribute("height", "100px");
        foreignObject.setAttribute("width", "100%");
        foreignObject.setAttribute("height", "100%");

        let serializer = new XMLSerializer();
        let serializedContent = serializer.serializeToString(svg);
        let base64Content = btoa(serializedContent);
        let imageUrl = "data:image/svg+xml;base64," + base64Content;
        let img = document.createElement("img");
        
        img.onerror = function (a, b) {
            alert("error");
        }

        img.onload = function () {

            let canvas = document.createElement("canvas");
            let context = canvas.getContext("2d");
            context.drawImage(img, 0, 0);
            let dataUrl = canvas.toDataURL("image/" + imageType);
            simulateDownload("output." + imageType, dataUrl);
        }

        img.src = imageUrl;
    }

    function simulateDownload(download, href) {
        const a = document.createElement('a');
        a.download = download;
        a.href = href;
        a.click();
        a.remove();
    }

</script>
In example, we render div (export_html_to_svg_container) object with its content to image.  First of all, we create an SVG object. We need a foreign object to place the HTML in, so we create one. We put the HTML in the foreign object and the foreign object in the SVG object. Before rendering, we must set the SVG object's width and height attributes. Finally, we serialize the SVG object to string with XMLSerializer and generate an image url using that string. With this url, we render the output image with the help of the image(img) object and canvas.

This method is compatible with many modern browsers like Chrome, Firefox and Edge.

Working Example:

OUTPUT

Monday, February 22, 2021

k Nearest Neighbours Classifier (kNN) with Javascript Implementation for Beginners

k Nearest Neighbours Classifier (kNN) is a powerful but computational costly nonlinear classifier. Basically, kNN works based on distance calculation and finding of closest neighbour vectors according to a distance function. Distance function can be l1 (Manhattan distance), l2 (Euclidean distance) or a different available appropriate distance function. kNN uses a hyper parameter (k) that implies count of closest neighbours. 

Algorithm find closest k vector to current vector, and returns classification result as class label of the largest matched number of class between these k closest vectors.




In this example; classes 1,2,3 corresponds to red, green and purple respectively. Algorithm takes k, x and y as input and return class label as color and draw last input point as a orange point. 


->k
->X
->Y
Javascript Codes:
document.addEventListener('DOMContentLoaded', (e) => {

            drawPoints();
        });

        var point = { x: 0, y: 0 };
        var k = 3;

        var datas = [

            { c: 1, x: 10, y: 100 },
            { c: 1, x: -10, y: 50 },
            { c: 1, x: 50, y: 150 },
            { c: 2, x: 100, y: 80 },
            { c: 1, x: 30, y: 200 },
            { c: 2, x: 200, y: 50 },
            { c: 2, x: 120, y: 30 },
            { c: 2, x: 100, y: 150 },
            { c: 3, x: 300, y: 50 },
            { c: 1, x: -150, y: 200 },
            { c: 3, x: -300, y: 400 },
            { c: 3, x: 233, y: 333 },
            { c: 2, x: 127, y: 190 },
            { c: 3, x: 100, y: -32 },
            { c: 1, x: -50, y: -12 },
            { c: 1, x: -101, y: -50 },
            { c: 1, x: -301, y: -19 },
            { c: 2, x: 127, y: -22 },
            { c: 3, x: 120, y: -100 },
            { c: 2, x: -50, y: -200 },
            { c: 3, x: 800, y: 100 },
            { c: 3, x: 150, y: -150 },
            { c: 3, x: 70, y: -80 },
            { c: 3, x: 70, y: -500 },
            { c: 3, x: 200, y: -300 },
            { c: 2, x: -50, y: -150 },
            { c: 3, x: 111, y: -200 },
            { c: 3, x: 301, y: -310 },
            { c: 3, x: 200, y: -151 },
            { c: 1, x: -122, y: -99 },
            { c: 1, x: -301, y: -499 },
            { c: 1, x: 401, y: -1 },
        ];

        function start() {

            let classColor = "";

            setValues();

            drawCurrentPoint();

            let c = knnClassify();

            if (c == 1)
                classColor = "red";
            else if (c == 2)
                classColor = "green";
            else
                classColor = "purple";

            alert(classColor);
        }

        function knnClassify() {

            var classificationResults = [

                { c: 1, count: 0 },
                { c: 2, count: 0 },
                { c: 3, count: 0 }
            ];

            let distances = [];

            for (let i = 0; i < datas.length; i++) {

                let distance = l2Distance(datas[i], point);
                let distanceToClass = { c: datas[i].c, d: distance };

                distances.push(distanceToClass);
            }

            distances.sort(function (a, b) {

                return a.d - b.d;
            });

            for (let i = 0; i < k; i++) {

                for (let k = 0; k < classificationResults.length; k++) {

                    if (classificationResults[k].c == distances[i].c) {

                        classificationResults[k].count++;
                    }
                }
            }

            classificationResults.sort(function (a, b) {

                return b.count - a.count;
            });

            return classificationResults[0].c;
        }

        function l2Distance(point1, point2) {

            return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
        }

        function drawPoints() {

            var canvas = document.getElementById("g");

            for (let i = 0; i < datas.length; i++) {

                let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');;
                circle.setAttributeNS(null, "cx", datas[i].x);
                circle.setAttributeNS(null, "cy", datas[i].y);
                circle.setAttributeNS(null, "r", 3);

                if (datas[i].c == 1)
                    circle.setAttributeNS(null, "fill", "red");
                else if (datas[i].c == 2)
                    circle.setAttributeNS(null, "fill", "green");
                else
                    circle.setAttributeNS(null, "fill", "purple");

                canvas.appendChild(circle);
            }
        }

        function drawCurrentPoint() {

            var canvas = document.getElementById("g");

            let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
            circle.setAttributeNS(null, "cx", point.x);
            circle.setAttributeNS(null, "cy", point.y);
            circle.setAttributeNS(null, "r", 3);

            circle.setAttributeNS(null, "fill", "orange");

            canvas.appendChild(circle);
        }
                   
        function setValues() {

            k = parseFloat(document.getElementById("pk").value);
            point.x = parseFloat(document.getElementById("pX").value);
            point.y = parseFloat(document.getElementById("pY").value);
        }
HTML Codes:
    <div>
        <input id="pk" type="text" value="3" />->k
    </div>
    <div>
        <input id="pX" type="text" value="0" />->X
    </div>
    <div>
        <input id="pY" type="text" value="0" />->Y
    </div>

    <div id="resultDiv" style="margin-top: 20px;"></div>
    <div style="margin-top: 20px;">
        <button onclick="start()" type="button">CLASSIFY</button>
    </div>

    <div style="margin-top: 50px;">
        <svg height="500" id="canvas" width="500">
            <g id="g" transform="translate(250 250) scale(1,-1)">
                <line style="stroke-width: 1; stroke: rgb(0, 0, 255);" x1="-1000" x2="1000" y1="0" y2="0"></line>
                <line style="stroke-width: 1; stroke: rgb(0, 0, 255);" x1="0" x2="0" y1="-1000" y2="1000"></line>

            </g>
        </svg>
    </div>

Friday, February 12, 2021

Devextreme Toast Wrapper for Global Widget Configuration

While using Devextreme toast widget, you may need to configure it. By default, toast widget placed bottom middle of window. In this article, I write a wrapper javascript code to configure widget globally, and I provide to show widged at bottom right of window and widget will be continuing to display content while mouse hover on it. This wrapper code is also compatible with older browsers. 

Wrapper code is dependent to Jquery.

dx-toast-wrapper.js:
var toastDefault = {

            width: "500px",
            displayTime: 4000,
            cancelHiding: false,

            contentTemplate: null,

            position: {

                at: "right bottom",
                collision: "fit",
                boundaryOffset: "20 20",

            },

            onContentReady: function (e) {

                $(e.element).on("mouseenter", function () {

                    this.cancelHiding = true;

                }.bind(this));

                $(e.element).on("mouseleave", function () {

                    this.cancelHiding = false;
                    e.component.hide();

                }.bind(this));
            }.bind(this),

            onHiding: function (e) {

                e.cancel = this.cancelHiding;

            }.bind(this)
        };

        var toast = {

            success: function (message) {

                toastDefault.contentTemplate = function () {

                    return $("</p>").html(message);
                };

                toastDefault.type = "success";

                DevExpress.ui.notify(toastDefault);
            },
            error: function (message) {

                toastDefault.contentTemplate = function () {

                    return $("</p>").html(message);
                };

                toastDefault.type = "error";

                DevExpress.ui.notify(toastDefault);
            },
            info: function (message) {

                toastDefault.contentTemplate = function () {

                    return $("</p>").html(message);
                };

                toastDefault.type = "info";

                DevExpress.ui.notify(toastDefault);
            },
            warning: function (message) {

                toastDefault.contentTemplate = function () {

                    return $("</p>").html(message);
                };

                toastDefault.type = "warning";

                DevExpress.ui.notify(toastDefault);
            }
        }
You can use Devextreme toast like that:

index.html:
<script>
toast.success("Success message");
toast.error("Error message");
toast.info("Info message");
toast.warning("Warning message");
</script>

Sunday, February 7, 2021

Using ProjectBaseCore without Dependency Injection

We can use ProjectBaseCore(PBC) without dependency injection(DI) by instantiating DatabaseFactory class with new keyword. We can give to factory class's constructor function a object that is implemented IConfiguration interface, or we can create database object by simply giving connection string and provider parameters to GetDbObject function. I give a console application example of how to use PBC without DI.

Program.cs:
class Program
{
   static void Main(string[] args)
   {
        DatabaseFactory databaseFactory = new DatabaseFactory(GetConfiguration());
        IDatabase2 db = databaseFactory.GetDbObject();
        var dt = db.ExecuteQueryDataTable("select * from product");
   }

   static IConfigurationRoot GetConfiguration()
   {
         var builder = new ConfigurationBuilder()
           .SetBasePath(System.AppContext.BaseDirectory)
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

         return builder.Build();
   }
}
appsettings.json:
{
  "DefaultDb": "Context",
  "ContextProviderName": "MySql.Data.MySqlClient",
  "ConnectionStrings": {
    "Context": "Server=localhost;Database=db;Uid=root;Pwd=1234;"
  }
}

Saturday, February 6, 2021

Injecting ProjectBaseCore in .Net Core Project

ProjectBaseCore (PBC) has to be injected to use in .net core project with version 2.x and later. After version 2.x, DatabaseFactory and QueryGeneratorFactory classes are no longer static classes. As a result, PBC version 2.x is not compatible with older versions, because you must inject DatabaseFactory and QueryGeneratorFactory classes or instantiate them with using new keyword.

First of all, in startup.js file or in a dependency injection container, injection must be defined:

services.AddSingleton<IDatabaseFactory, DatabaseFactory>();
services.AddSingleton<IQueryGeneratorFactory, QueryGeneratorFactory>();
In startup file, we write these codes in "ConfigureServices" function. After these declarations, we can use these services in controllers or middleware classes.

public class HomeController : Controller
{
     private readonly IDatabaseFactory _databaseFactory;
     private readonly IQueryGeneratorFactory _queryGeneratorFactory;

     public HomeController(IDatabaseFactory databaseFactory, IQueryGeneratorFactory queryGeneratorFactory)
     {
         _databaseFactory = databaseFactory;
         _queryGeneratorFactory = queryGeneratorFactory;
     }

     public IActionResult Index()
     {
         var db = _databaseFactory.GetDbObject();
         var qg = _queryGeneratorFactory.GetDbObject();
         qg.SelectText = "select * from product";

         var dt = db.ExecuteQueryDataTable(qg.GetSelectCommandBasic());
         return View();
     }
}

Saturday, January 23, 2021

Support Vector Machines (SVM) with Javascript Implementation for Beginners

I give an example of javascript implementation of support vector machines (SVM) and I explain SVM algorithm with hinge loss function in this article.

SVM algorithm aims to find a hyperplane that separates dataset in two classes:



For SVM, classes take values {1,-1}. Algorithm tries to find a hyperplane by maximizing margin between support vectors and hyperplane. We can describe support vectors as closest vectors to hyperplane. In 2 dimensional space, a hyperplane corresponds to a line.

So, to calculate a hyperplane, we must define hyperplane function:

f(x) = wx + b;

In this example, our space is 2 dimensional, so we have a coordinate point (x,y) and a class label (c).

As a result, we have a dataset that consists of javascript objects that includes {c,x,y} properties. Before going to optimization step, we must define SVM loss function. In this loss function, yi corresponds to c and xi corresponds to x,y for our case.


SVM algorithm uses hinge loss function. This loss function penalizes incorrect classifications. Max function is a convex function, so we can use gradient descent algorithm (GDA) as optimization algorithm. In 2 dimension, we have w1, w2 and b as optimization parameters. So we calculate partial derivatives:

d/dw1 Loss(w1,w2,c,x,y,b) = -1 * c * x

d/dw2 Loss(w1,w2,c,x,y,b) = -1 * c * y

d/b Loss(w1,w2,c,x,y,b) = -1 * c

While calculating loss, we calculate all losses for all points and take their mean value. As a result, we can calculate w1,w2 and b by using GDA. In our example, 1 labeled class and -1 labeled class are drawn red and blue respectively.


->alfa (learning parameter)

->maxIteration
Javascript codes:
<script>

        var alfa = 0.001;
        var maxIteration = 300000;

        var w1 = 1;
        var w2 = 1;
        var b = 1;
        var dw1 = 0;
        var dw2 = 0;
        var db = 0;

        var datas = [

            { c: 1, x:10, y: 100 },
            { c: 1, x:-10, y: 50 },
            { c: 1, x:50, y: 150 },
            { c: 1, x:100, y: 80 }, 
            { c: 1, x:30, y: 200 },
            { c: 1, x:200, y: 50 },
            { c: 1, x: 120, y: 30 },
            { c: 1, x: 100, y: 150 },
            { c: 1, x: 300, y: 50 },
            { c: 1, x: -150, y: 200 },
            { c: 1, x: -300, y: 400 },
            { c: 1, x: 233, y: 333 },
            { c: 1, x: 127, y: 190 },
            { c: 1, x: 100, y: -32},
            { c: 1, x: -50, y: -12 },
            { c: 1, x: -101, y: -50 },
            { c: 1, x: -301, y: -19 },
            { c: 1, x: 127, y: -22 },
            { c: -1, x:120, y: -100 },
            { c: -1, x:-50, y: -200 },
            { c: -1, x:800, y: 100 },
            { c: -1, x:150, y: -150 },
            { c: -1, x:70, y: -80 },
            { c: -1, x: 70, y: -500 },
            { c: -1, x: 200, y: -300 },
            { c: -1, x: -50, y: -150 },
            { c: -1, x: 111, y: -200 },
            { c: -1, x: 301, y: -310 },
            { c: -1, x: 200, y: -151 },
            { c: -1, x: -122, y: -99 },
            { c: -1, x: -301, y: -499 },
            { c: -1, x: 401, y: -1 },
        ]

        function getHingeLoss(data) {

            let loss = 1 - (w1 * data.x + w2 * data.y + b) * data.c;

            if (loss > 0)
                return loss;
            else
                return 0;
        }

        function setGradients() {

            let cost = 0;

            for (let i = 0; i < datas.length; i++) {

                let loss = getHingeLoss(datas[i]);
                cost += loss;

                if (loss > 0) {

                    dw1 += (-1 * datas[i].x * datas[i].c);
                    dw2 += (-1 * datas[i].y * datas[i].c);
                    db += (-1 * datas[i].c);
                }
            }

            cost /= datas.length;
            dw1 /= datas.length;
            dw2 /= datas.length;
            db /= datas.length;

            return cost;
        }

        function train() {

            setValues();
            drawPoints();

            for (var i = 0; i < maxIteration; i++) {

                setGradients();

                w1 -= alfa * dw1;
                w2 -= alfa * dw2;
                b -= alfa * db;             
            }

            drawLine();

            let resultDiv = document.getElementById("resultDiv");
            resultDiv.innerHTML = "w1:" + w1 + ", w2:" + w2 + ",b:" + b;
        }

        function drawPoints() {

            var canvas = document.getElementById("g");

            for (let i = 0; i < datas.length; i++) {

                let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');;
                circle.setAttributeNS(null, "cx", datas[i].x);
                circle.setAttributeNS(null, "cy", datas[i].y);
                circle.setAttributeNS(null, "r", 1);

                if (datas[i].c == 1)
                    circle.setAttributeNS(null, "fill", "red");
                else
                    circle.setAttributeNS(null, "fill", "blue");

                canvas.appendChild(circle);
            }
        }

        function drawLine() {

            var canvas = document.getElementById("g");

            let point1x = 1000;
            let point1y = (w1 * point1x + b) / (-1 * w2);
            let point2x = -1000;
            let point2y = (w1 * point2x + b) / (-1 * w2);

            let line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttributeNS(null, "x1", point1x);
            line.setAttributeNS(null, "y1", point1y);
            line.setAttributeNS(null, "x2", point2x);
            line.setAttributeNS(null, "y2", point2y);
            line.setAttributeNS(null, "style", "stroke: rgb(0, 255, 0); stroke-width:1");
            canvas.appendChild(line);
        }

        function setValues() {

            alfa = parseFloat(document.getElementById("alfa").value);
            maxIteration = parseFloat(document.getElementById("maxIteration").value);
        }

    </script>
HTML codes:
<div>
        <input id="alfa" type="text" value="0.001" />->alfa
    </div>
    <div>
        <input id="maxIteration" type="text" value="300000" />->maxIteration
    </div>

    <div id="resultDiv" style="margin-top: 20px;"></div>
    <div style="margin-top: 20px;">
        <button onclick="train()" type="button">START</button>
    </div>

    <div style="margin-top: 50px;">
        <svg height="500" id="canvas" width="500">
            <g id="g" transform="translate(250 250) scale(1,-1)">
                <line style="stroke-width: 1; stroke: rgb(0, 0, 255);" x1="-1000" x2="1000" y1="0" y2="0"></line>
                <line style="stroke-width: 1; stroke: rgb(0, 0, 255);" x1="0" x2="0" y1="-1000" y2="1000"></line>

            </g>
        </svg>
    </div>

Sunday, January 17, 2021

Gradient Descent Algorithm for Beginners (Quadratic Function Example)

In this article, I explain how gradient descent algorithm (GDA) works. I use a quadratic function for explanation:

f(x) = ax^2+bx+c

As you know, gradient of a function is first derivative of function (f'(x)). First derivative of f(x):

f'(x) = 2ax + b;

GDA is a iterative algorithm that calculates gradient of function f(x) for x in each iteration, and calculates next point by substracting gradient from x. GDA uses a learning parameter (alfa) that regularizes changings of x. So in each iteration, GDA calculates next x value:

x(t+1) = x(t) - alfa*f'(x(t))

So, why does GDA use gradient of function?

Think yourself on a hill and you want to get down. If slope is steep, you take a big step, otherwise a small step. Because while coming to end of hill, slope will be smaller until it is zero.

If you think of gradient as a vector, gradient's direction always guide you to end of hill or top of hill.

Note that, we can use GDA to find minimum point of a convex function, and gradient ascent algorithm to find maximum point of a concave function.

I prepared a working javascript example. You can calculate minimum point of quadratic function and visualize calculated point and function with this code.

In each iteration, calculated point (x,y) is displayed as a red dot.


->x (starting value of x)
->alfa (learning parameter)
->maxIteration (maximum iteration count)
->a
->b
->c

Javascript Codes:

<script>

        var x = 200;
        var alfa = 0.01;
        var maxIteration = 5000;

        var a = 1;
        var b = -5;
        var c = 6;

        var fx = (x) => a * x * x + b * x + c;

        var dxfx = (x) => 2 * a * x + b;

        function start() {

            setValues();
            drawCurve();

            var canvas = document.getElementById("g");
            let y = 0;

            for (var i = 0; i < maxIteration; i++) {

                x = x - alfa * dxfx(x);
                y = fx(x);

                let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');;
                circle.setAttributeNS(null, "cx", x);
                circle.setAttributeNS(null, "cy", y);
                circle.setAttributeNS(null, "r", 1);
                circle.setAttributeNS(null, "fill", "red");

                canvas.appendChild(circle);
            }

            let resultDiv = document.getElementById("resultDiv");
            resultDiv.innerHTML = "x:" + x + ", y:" + y;
        }

        function setValues() {

            x = parseFloat(document.getElementById("x").value);
            alfa = parseFloat(document.getElementById("alfa").value);
            maxIteration = parseFloat(document.getElementById("maxIteration").value);
            a = parseFloat(document.getElementById("a").value);
            b = parseFloat(document.getElementById("b").value);
            c = parseFloat(document.getElementById("c").value);
        }

        function drawCurve() {

            var canvas = document.getElementById("g");

            for (var i = 5000; i >= -5000; i -= 1) {

                let line = document.createElementNS('http://www.w3.org/2000/svg', 'line');     
                line.setAttributeNS(null, "x1", i);
                line.setAttributeNS(null, "y1", fx(i));
                line.setAttributeNS(null, "x2", i - 1);
                line.setAttributeNS(null, "y2", fx(i - 1));
                line.setAttributeNS(null, "style", "stroke: rgb(0, 255, 0); stroke-width:1");
                canvas.appendChild(line);
            }
        }

    </script>
HTML Codes:
<div>
        <input id="x" type="text" value="200" />->x
    </div>
    <div>
        <input id="alfa" type="text" value="0.01" />->alfa
    </div>
    <div>
        <input id="maxIteration" type="text" value="5000" />->maxIteration
    </div>
    <div>
        <input id="a" type="text" value="1" />->a
    </div>
    <div>
        <input id="b" type="text" value="-5" />->b
    </div>
    <div>
        <input id="c" type="text" value="6" />->c
    </div>

    <div style="margin-top:20px" id="resultDiv"></div>
    <div style="margin-top:20px">
        <button type="button" onclick="start()">START</button>
    </div>

    <div style="margin-top:50px">
        <svg id="canvas" width="500" height="500">
            <g id="g" transform="translate(250 250) scale(1,-1)">
                <line x1="-1000" y1="0" x2="1000" y2="0" style="stroke: rgb(0, 0, 255); stroke-width:1"></line>
                <line x1="0" y1="-1000" x2="0" y2="1000" style="stroke: rgb(0, 0, 255); stroke-width:1"></line>

            </g>
        </svg>
    </div>

Sunday, January 3, 2021

x-comment jquery plugin: Jquery plugin for commenting or discussion

With x-comment, users' comments can be displayed hierarchically and users can respond to each other. There is no level limit while answering. x-comment allows adding new comments, reply to comments, and runs entirely on json and javascript objects.

Github:

https://github.com/vyigity/x-comment

Dependency

  • Jquery
  • Bootstrap
  • Fontawesome
  • Globalize

Configuration- Plugin

  • mode: Can be set as "array" or "remote". With "array" value, data is processed locally by using the javascript array given to the plugin. This method can be used for batch input and output operations. The data is accessed by running the function that returns Jquery Deferred in the dataSource field with "remote" value. (required)
  • items: In "array" mode, data is given to the plugin here. Also, after the data is loaded in "remote" mode, it can be read as a javascript array.(required in array mode)
  • dataSource: Can be set as a function that returns a jquery Deferred object. Data is obtained by running this function by the plugin. Data must be sent as parameter to promise resolve function.(required in remote mode)
  • authorName: The name written here is used by the plugin when responding. (required)
  • width: It allows the size of the plugin to be set to px. (optional)
  • allowInsert: Can be set as "true/false". It allows to show the form that enables inserting. (optional - Default:true)
  • allowReply: Can be set as "true/false". Ensures that comments can be answered or not. (optional - Default:true)
  • allowDelete: Can be set as "true/false". Ensures that comments can be deleted or not. (optional - Default:true)
  • onInserting: Can be set as a function that returns a jquery Deferred object. Is triggered when adding a new record. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • value: Value that is typed by user.
  • onReplied: Can be set as a function that returns a jquery Deferred object. Is triggered when replying to a comment. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • value: Value that is typed by user. 
      • item: Comment that is answered to.
  • onDeleting: Can be set as a function that returns a jquery Deferred object. Is triggered when deleting a comment. 
    • Parameters: 
      • instance: Instance of plugin. For example, it can be used to access the items or the plugin can be refreshed. 
      • item: Comment about to be deleted.
  • onError: Is triggered on error that occurs in functions that return a jquery Deferred object. Deferred object must be used with reject function. 
    • Parameters: 
      • data: The value sent through the reject function of the Deferred object.
  • texts: Can be configured text in plugin. A javascript object. (optional)

Configuration - texts (optional)

  • sendButtonText: Determines the text on the button in the new comment creation section.
  • inputTextAreaPlaceHolder: Allows editing of placeholder that appears in comment text area.
  • sendReplyButtonText: Determines the text on the reply send button.
  • cancelButtonText: Determines the text on the button that enables the cancellation of the response..
  • replyButtonText: Determines the text on the button that enables the answering process.
  • deleteButtonText: Determines the text on the button that allows the comments to be deleted.

Configuration - items

  • id: A unique value of a comment item.
  • parent: Parent value of a comment item.
  • deletable: Can be set as "true/false". The value that indicates the comment that can be deleted or not.
  • content: Content of a comment item.
  • created: Creation date time of a comment item. Value must be formatted as JSON. For example, "2020-12-31T20:52:00Z"
  • fullName: User name of owner of comment item.




Example (data.js):
var comments = [
    {
        id: 1,
        parent: null,
        deletable: true,
        content: "1. yorum",
        created: "2020-12-31T20:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 2,
        parent: null,
        deletable: true,
        content: "2. yorum",
        created: "2020-12-31T21:52:00Z",
        fullName: "Veli Yigit Yolcu"
    },
    {
        id: 3,
        parent: 2,
        deletable: true,
        content: "2. yoruma cevap",
        created: "2020-12-31T22:52:00Z",
        fullName: "Veli Yigit Yolcu"
    }
];
Example (index.html):
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/comment.css" rel="stylesheet" />
    <link href="css/fontawesome.min.css" rel="stylesheet" />
    <link href="css/brands.css" rel="stylesheet" />
    <link href="css/solid.css" rel="stylesheet" />

    <script src="js/jquery-3.5.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/x-comment.js"></script>

    <script src="cldr/cldr.js"></script>
    <script src="cldr/event.js"></script>
    <script src="cldr/supplemental.js"></script>

    <script src="globalize/globalize.js"></script>
    <script src="globalize/message.js"></script>
    <script src="globalize/number.js"></script>
    <script src="globalize/currency.js"></script>
    <script src="globalize/date.js"></script>

    <script src="cldr-data/supplemental.js"></script>
    <script src="cldr-data/tr.js"></script>

    <script src="data/data.js"></script>
</head>
<body>

    <script>

        Globalize.locale("tr");

        var currentId = 100;

        $(document).ready(function () {

            $("#xcomment").xcomment({

                mode: "array",
                items: comments,
                allowInsert: true,
                authorName: "Veli Yigit Yolcu",
                width: 600,
                onInserting: function (instance, value) {

                    let def = $.Deferred();

                    instance.items.splice(0, 0,
                        {
                            id: currentId,
                            parent: null,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        });

                    currentId++;

                    def.resolve();

                    return def;
                },
                onReplied: function (instance, item, value) {

                    let def = $.Deferred();

                    instance.items.push(
                        {
                            id: currentId,
                            parent: item.id,
                            deletable: true,
                            content: value,
                            created: new Date().toJSON(),
                            fullName: "Veli Yigit Yolcu"
                        }
                    );

                    currentId++;

                    def.resolve();

                    return def;
                },
                onDeleting: function (instance, item) {

                    let def = $.Deferred();

                    for (var i = 0; i < instance.items.length; i++) {

                        if (instance.items[i].id === item.id) {

                            instance.items.splice(i, 1);
                        }
                    }

                    def.resolve();

                    return def;
                }
            });
        });

    </script>

    <div id="xcomment" ></div>

</body>
</html>