diff --git a/Example.jpg b/Example.jpg new file mode 100644 index 0000000..755201b Binary files /dev/null and b/Example.jpg differ diff --git a/Game1/Content/Example.png b/Game1/Content/Example.png new file mode 100644 index 0000000..e9f0756 Binary files /dev/null and b/Game1/Content/Example.png differ diff --git a/Game1/Sources/Crops/Crops.cs b/Game1/Sources/Crops/Crops.cs index 40973fc..9b33722 100644 --- a/Game1/Sources/Crops/Crops.cs +++ b/Game1/Sources/Crops/Crops.cs @@ -14,7 +14,7 @@ class Crops private int cropType = 0; private float Timer = 1; private int UpdateCrop; - private float fullTimer; + private float fullTimer = 1; private bool housePos = false; private Vector2 Size; private Random r = new Random(); @@ -24,6 +24,7 @@ class Crops private float tempRain; private float prevpred; private DayNightCycle Time = new DayNightCycle(); + private int previousDay = 0; @@ -244,13 +245,17 @@ class Crops public void setCropType(int Type, CropTypes nCropType) { - - DataSet = nCropType; - cropType = Type; - - if (Status == 3) + if (Timer == fullTimer) { - soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax); + CropTypes temp = DataSet; + DataSet = nCropType; + cropType = Type; + if (Status > 1) + { + soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax); + if (temp != nCropType) + updateMLModel(DataSet, 1.0f); + } } } @@ -275,6 +280,7 @@ class Crops public void setStatus(int newStatus) { Status = newStatus; + Timer = getCropTimer(); } public void setOriginalStatus() @@ -334,25 +340,9 @@ class Crops public float getProductionRate(CropTypes Sample) { float predProd = 1.0f; - if (Status > 1 && Time.nDay()) + if (Status > 1 && Time.getDays() != previousDay) { - bool correctSeason = false; - foreach (string i in Sample.Season) - { - if (i == Time.getTimeOfYear() || i == "Whole Year") - { - correctSeason = true; - break; - } - } - - if (correctSeason) - { - predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time); - predProd = (predProd / soilProperties.Area) / 2; - } - else - predProd = 0.20f; + predProd = updateMLModel(Sample, predProd); } prevpred = predProd; ProductionRate = 1; @@ -396,6 +386,30 @@ class Crops return ProductionRate * prevpred; } + public float updateMLModel(CropTypes Sample, float predProd) + { + previousDay = Time.getDays(); + bool correctSeason = false; + foreach (string i in Sample.Season) + { + if (i == Time.getTimeOfYear() || i == "Whole Year") + { + correctSeason = true; + break; + } + } + + if (correctSeason) + { + predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time); + predProd = (predProd / soilProperties.Area) / 2; + } + else + predProd = 0.20f; + + return predProd; + } + public float getProductionRate() { return ProductionRate; diff --git a/Game1/Sources/Crops/Farm.cs b/Game1/Sources/Crops/Farm.cs index 6e8f4d5..437c405 100644 --- a/Game1/Sources/Crops/Farm.cs +++ b/Game1/Sources/Crops/Farm.cs @@ -20,7 +20,7 @@ class Farm private float[][] whiteNoise; private float[][] perlinNoise; private DayNightCycle Time; - private float updatePerc = 0.10f; + private float updatePerc = 0.01f; private float updateProgress = 0; private float nextUpdate = 0; private int productionUpdate = 0; @@ -141,7 +141,7 @@ class Farm Update = 0; } updateRainMapPosition(Size); - if (productionUpdate == 60) + if (productionUpdate == 2) { nextUpdate = updateProgress + updatePerc; for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++) diff --git a/Game1/Sources/ML/MLModel.cs b/Game1/Sources/ML/MLModel.cs index 30e3510..c329bcf 100644 --- a/Game1/Sources/ML/MLModel.cs +++ b/Game1/Sources/ML/MLModel.cs @@ -11,7 +11,7 @@ using Microsoft.ML.Trainers.LightGbm; class MLModel { private static MLContext mlContext = new MLContext(seed: 1); - + /* private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Fertilizer_Prediction.csv"; private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel"; private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report"; @@ -19,15 +19,15 @@ class MLModel private static string pathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/BigFertPredict.csv"; private static string modelpathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodelBig"; private static string reportBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_BigModel"; - /* - private static string pathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/BigFertPredict.csv"; - private static string modelpathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodelBig"; - private static string reportBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_BigModel"; + */ + private static string pathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/BigFertPredict.csv"; + private static string modelpathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodelBig"; + private static string reportBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_BigModel"; + + private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Fertilizer_Prediction.csv"; + private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel"; + private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report"; - private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Fertilizer_Prediction.csv"; - private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel"; - private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report"; - */ // Loading data, creatin and saving ML model for smaller dataset (100) public static void CreateModel() { diff --git a/Game1/Sources/ML_Joel/Model.cs b/Game1/Sources/ML_Joel/Model.cs index 060f968..fae4e65 100644 --- a/Game1/Sources/ML_Joel/Model.cs +++ b/Game1/Sources/ML_Joel/Model.cs @@ -13,7 +13,7 @@ namespace Game1.Sources.ML_Joel class Model { private static MLContext mlContext = new MLContext(seed: 1); - + /* private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall.csv"; private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel"; private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel"; @@ -21,8 +21,8 @@ namespace Game1.Sources.ML_Joel private static string path_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall_area.csv"; private static string modelpath_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel_area"; private static string report_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel_area"; + */ - /* private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall.csv"; private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel"; private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel"; @@ -30,7 +30,7 @@ namespace Game1.Sources.ML_Joel private static string path_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall_area.csv"; private static string modelpath_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel_area"; private static string report_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel_area"; - */ + // Loading data, creatin and saving ML model for smaller dataset (100) public static void CreateModel() { diff --git a/Joels Individual Report.md b/Joels Individual Report.md new file mode 100644 index 0000000..b7c4ca5 --- /dev/null +++ b/Joels Individual Report.md @@ -0,0 +1,103 @@ +Machine Learning Implementation + + + + + + +Introduction + + +I have implemented a ML to add in season, daily rainfall and area which can be cultivated into the Productivity rate of each crop. This dataset contains over 65000 entries of which we only use around 20000 as those are the only crops that are plantable for our agen and the lowest amount of entries for a single crop is 600. The daily rainfall has been added to SoilProperties in our tileset. Implementation of the needed properties into SoilProperties: + + +public float Rainfall; +public float prevRainfall; +public int Area; + + +. +. +. + + + //Randomize the first days rainfall and the area, +prevRainfall = r.Next(247, 3617); +Area = r.Next(1, 270000); + + +The dataset is said to be based on real life data. But for our our program is not able to fit the data 1 to 1 because some Crops only had an daily rainfall from 247 to 2000 but the Rainfall of that tile could still be 3617. I haven’t done anything to mitigate this but it doesn’t result in any strange results when passing through our data into the ML Model. It would have been better for the dataset contained rainfall data from 247 to 3617. Then the yield could possibly be lower or higher as rainfall increases or decreases. We added dynamic rainfall in is therefore constricting the rain from going outside of the datasets parameters: + + + //Sets previous days rainfall to current days rainfall and constrict the total rainfall from going outside of the parameters + soilProperties.prevRainfall = soilProperties.Rainfall; + if (soilProperties.prevRainfall > 3616) + soilProperties.prevRainfall = 3616; + else if (soilProperties.prevRainfall < 236) + soilProperties.prevRainfall = 236; + soilProperties.Rainfall = 0; + + + + + + +Implementation + + + + +I have used gradient boosting decision tree algorithm due to the features. +I used Gradient Boosting Decision Tree Algorithm for this task due to many features it has. +First a csv file is loaded: + IDataView trainingDataView = mlContext.Data.LoadFromTextFile( + path: path, + hasHeader: true, + separatorChar: ',', + allowQuoting: true, + allowSparse: false); +Then it is passed to next function which will train, evaluate and build a model: +- maximizing number of leaves, +- limiting maximum tree depth, +- maximizing the amount of bins per feature, + + +maintaining high accuracy by: +- low learning rate combine with: +- high number of iterations. + + +Creating pipeline for the model: + var pipeline = mlContext.Transforms + .Text.FeaturizeText("SeasonF", "Season") + .Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop")) + .Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall")) + .AppendCacheCheckpoint(mLContext) + .Append(mLContext.Regression.Trainers.LightGbm(options)); + + + .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel")); + + +Integration + + +Our tileset now has a dynamically moving overlay of clouds moving at the speed of WindSpeed and if the clouds are above at a tile we add to the total rainfall of the day. The rainfall we pass into the ML Model is the previous days rainfall and the first days rainfall is randomized. + + +We achieved this rainsystem by running a bitmap over our tileset, the bitmap is continues with itself so it runs seamlessly. Depending on the ransparency of each pixel on this bitmap we determine how much it is currently raining on set tile: + + + if (Rain >= 0.45f) + { + soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4; + } + + +if the transparency is < 0.45 then there will be no cloud drawn and it will not be raining at all. And this is the result: + + +(https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Oskar-ML/Example.jpg) + + +To optimize the program we now update 10% of the columns every second or else it would freeze for seconds at a time and the ML Model is only being fed data once a day as the total rainfall is only updated once a day anyways. \ No newline at end of file