Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
48da4d4736 | ||
![]() |
8efb2d2d38 | ||
![]() |
5dd6cd0020 | ||
![]() |
df77db10af | ||
![]() |
c1ef96716f | ||
![]() |
7211266f90 | ||
![]() |
43001006b8 | ||
![]() |
48c90afe77 | ||
![]() |
412a0969f0 | ||
![]() |
72a7a8aab3 | ||
![]() |
9e07e0f6bd | ||
![]() |
ad92969137 | ||
![]() |
2e96d5a2d5 | ||
![]() |
cb5a4ea733 | ||
![]() |
b6078e14ac | ||
0d4c1a0276 | |||
3b733f9d20 | |||
ef1c8c4386 | |||
bf86c760b1 | |||
5a6d7ecb48 | |||
49c41e3594 | |||
1bbd343e74 | |||
d19c3cbc41 | |||
9f57f7b00c | |||
cdc23ff3ed | |||
3114994c8b | |||
daf7810dac | |||
670acee8f2 | |||
d8246cce37 | |||
![]() |
631ad7c12f | ||
![]() |
8b115ec1f5 | ||
![]() |
090a612660 | ||
![]() |
561287f99e | ||
![]() |
0b7ff8a949 | ||
![]() |
c89fee6b05 | ||
![]() |
8ab1d77d9c | ||
![]() |
94c2792ef3 | ||
![]() |
5e9c9f503d | ||
![]() |
e406823e47 | ||
![]() |
6bb5073048 | ||
![]() |
fe04a5cd07 | ||
![]() |
10e58f984f | ||
![]() |
14e0e92f9b | ||
![]() |
c858261c89 | ||
![]() |
cfbe80cb25 | ||
![]() |
5e907deca7 | ||
![]() |
0dfef73667 | ||
![]() |
585522b4df | ||
![]() |
50fd54ee3b | ||
![]() |
0a31c36c93 | ||
![]() |
f63bdcee77 | ||
![]() |
eb99fd3f02 | ||
![]() |
5a208e116f | ||
![]() |
8b84387c81 | ||
![]() |
64aaef69dd | ||
![]() |
2e48e49239 | ||
![]() |
46d27ab057 | ||
![]() |
38df90d9b5 | ||
![]() |
ec0819a337 | ||
![]() |
700979aded | ||
![]() |
9b99e0e710 | ||
![]() |
848cd6598a | ||
![]() |
444b5b0585 | ||
![]() |
ba557d98f6 | ||
![]() |
57a9076771 | ||
![]() |
4a786a166e | ||
![]() |
2a7c06fbd2 | ||
![]() |
32370470b5 | ||
![]() |
710cd8581e |
BIN
Evaluation_examples/Example_UI.PNG
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
Evaluation_examples/Example_clouds.PNG
Normal file
After Width: | Height: | Size: 210 KiB |
BIN
Example.jpg
Normal file
After Width: | Height: | Size: 872 KiB |
38
Final_evaluation.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Final Evaluation
|
||||
|
||||
## Introduction
|
||||
PotatoPlan is an Inteligent Tractor AI Project and is written in C# using Monogame framework.
|
||||
NuGet Packages used and requeired for the project to work ar as follows:
|
||||
C5
|
||||
Microsoft.ML
|
||||
Microsoft.ML.LightGBM
|
||||
System.Drawing.Common
|
||||
|
||||
In our project agent (tractor) moves on resizable grid, which starting size is dependant on primary screen resolution.
|
||||
The task of the agent is to go through all soil tiles and plant different types of crops, use proper fertilizer and collect crops when fully grown.
|
||||
|
||||
Window can be resized usind WASD. Tractor speed can be changed using UP and DOWN arrow keys, while simulation speed can be changed using LEFT and RIGHT arrow keys.
|
||||
Also house placement can be changed by left clicking on a tile, and get info about the tile by right clicking.
|
||||
|
||||
Apart from Machine Learning Algorithms used in project there are also many different features implemented like:
|
||||
- Using A* algorithm to find an optimal path to previously selected target.
|
||||
- Target is found by scoring system which assign score to a tile based on few factors like production rate or distance.
|
||||
- Dynamically allocated cargo space for each fertilizer based on how often each fertilizer is used.
|
||||
- Day and night cycle and season system.
|
||||
- Using noise map generated for rainfall calculations to draw moving clouds.
|
||||
- ... and few other.
|
||||
|
||||
## Machine Learning Algorithms
|
||||
Project in its current state uses Machine Learning Algorithms to solve 2 problems. Light Gradient-Boosted Trees are used for both problems:
|
||||
1. Choosing a proper fertilizer which should be applied to current tile, based on few variables like nutrients in soil.
|
||||
Applying proper fertilizer boosts production rate of a crop (rate of growth of a crop). This part was done by Oskar Nastały.
|
||||
2. Calculating production rate of a tile based on rainfall and few other variabels. Noise map is generated and used to simulate dynamically changing rainfall.
|
||||
Then once a day AI is used to calculate base production rate multiplier. This part was done by Joel Städe.
|
||||
|
||||
## Examples
|
||||
|
||||
### Clouds
|
||||
![Clouds](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_clouds.PNG)
|
||||
|
||||
### UI
|
||||
![UI](https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Joel-ML/Evaluation_examples/Example_UI.PNG)
|
BIN
Game1/Content/Cloud.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Game1/Content/Clouds
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
Game1/Content/Clouds.png
Normal file
After Width: | Height: | Size: 4.8 MiB |
@ -61,6 +61,30 @@
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:CarronIcon.png;CarrotIcon.png
|
||||
|
||||
#begin Cloud.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
/processorParam:ColorKeyColor=255,0,255,255
|
||||
/processorParam:ColorKeyEnabled=True
|
||||
/processorParam:GenerateMipmaps=False
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:ResizeToPowerOfTwo=False
|
||||
/processorParam:MakeSquare=False
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:Cloud.png
|
||||
|
||||
#begin Clouds.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
/processorParam:ColorKeyColor=255,0,255,255
|
||||
/processorParam:ColorKeyEnabled=True
|
||||
/processorParam:GenerateMipmaps=False
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:ResizeToPowerOfTwo=False
|
||||
/processorParam:MakeSquare=False
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:Clouds.png
|
||||
|
||||
#begin CottonIcon.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
@ -248,6 +272,18 @@
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:PulsesIcon.png
|
||||
|
||||
#begin rain.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
/processorParam:ColorKeyColor=255,0,255,255
|
||||
/processorParam:ColorKeyEnabled=True
|
||||
/processorParam:GenerateMipmaps=False
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:ResizeToPowerOfTwo=False
|
||||
/processorParam:MakeSquare=False
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:rain.png
|
||||
|
||||
#begin Right.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
@ -368,3 +404,15 @@
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:WheatIcon.png
|
||||
|
||||
#begin WoodBackground.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
/processorParam:ColorKeyColor=255,0,255,255
|
||||
/processorParam:ColorKeyEnabled=True
|
||||
/processorParam:GenerateMipmaps=False
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:ResizeToPowerOfTwo=False
|
||||
/processorParam:MakeSquare=False
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:WoodBackground.png
|
||||
|
||||
|
BIN
Game1/Content/Example.png
Normal file
After Width: | Height: | Size: 872 KiB |
BIN
Game1/Content/ML/MLmodel_Joel
Normal file
BIN
Game1/Content/ML/MLmodel_Joel_area
Normal file
1048576
Game1/Content/ML/Rainfall.csv
Normal file
1048576
Game1/Content/ML/Rainfall_area.csv
Normal file
3
Game1/Content/ML/report_Joel
Normal file
@ -0,0 +1,3 @@
|
||||
Mean Absolute Error: 0.0108015636096701
|
||||
Mean Squared Error: 0.0434908452113952
|
||||
R Squared: 0.702723944791744
|
2
Game1/Content/ML/report_Joel_area
Normal file
@ -0,0 +1,2 @@
|
||||
Mean Absolute Error: 187.060835104336
|
||||
R Squared: 0.913526230109177
|
BIN
Game1/Content/Rainfall.bmp
Normal file
After Width: | Height: | Size: 4.7 MiB |
BIN
Game1/Content/Rainfall.png
Normal file
After Width: | Height: | Size: 2.8 MiB |
BIN
Game1/Content/WoodBackground.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
Game1/Content/rain.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.IO;
|
||||
using WinForm = System.Windows.Forms;
|
||||
|
||||
namespace Game1
|
||||
{
|
||||
@ -18,9 +19,11 @@ namespace Game1
|
||||
private Texture2D[] tileConnected = new Texture2D[5];
|
||||
private Texture2D[] Crops = new Texture2D[12];
|
||||
private Texture2D tractor;
|
||||
private Texture2D Background;
|
||||
private Texture2D house;
|
||||
private Texture2D markers;
|
||||
private Texture2D mouseCursor;
|
||||
private Texture2D Rain;
|
||||
string directory = Directory.GetCurrentDirectory();
|
||||
|
||||
|
||||
@ -43,6 +46,10 @@ namespace Game1
|
||||
|
||||
MouseState state;
|
||||
|
||||
private int cloudAnimationSpeed = 3;
|
||||
private int cloudFrame = 0;
|
||||
private int cloudSprite;
|
||||
|
||||
|
||||
public Game1()
|
||||
{
|
||||
@ -69,14 +76,19 @@ namespace Game1
|
||||
cropTypesNames[11] = "Wheat";
|
||||
|
||||
Engine.init();
|
||||
Sources.ML_Joel.Engine.initArea();
|
||||
//Sources.ML_Joel.Engine.CreateModel();
|
||||
//Sources.ML_Joel.Engine.CreateModelArea();
|
||||
|
||||
|
||||
|
||||
//Generates the map with some random values
|
||||
inventory.initInventorySystem();
|
||||
|
||||
|
||||
string path = directory + "Game1/Content/ML/Fertilizer_Prediction.csv";
|
||||
input.init(graphics, new Vector2(16,16), 56, 0); //Generates the starting size
|
||||
int res = WinForm.Screen.PrimaryScreen.Bounds.Height;
|
||||
input.init(graphics, new Vector2((float)Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width/56*0.6f), (float)Math.Floor((WinForm.Screen.PrimaryScreen.Bounds.Height / 56f) - 7)), 56, 0); //Generates the starting size
|
||||
houseUnit.init(input.getTileSize(), input.getSpacing()); //Generates the house position
|
||||
tractorUnit.init(houseUnit.GetRectangle(), input); //Generates the Tractor
|
||||
tractorUnit.updateSizing(input, 0, houseUnit.getVector(), Time); //Updates the first Size of the Tractor
|
||||
@ -86,7 +98,7 @@ namespace Game1
|
||||
|
||||
|
||||
graphics.PreferredBackBufferWidth = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().X;
|
||||
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 300;
|
||||
graphics.PreferredBackBufferHeight = (input.getTileSize() + input.getSpacing()) * (int)input.getSize().Y + 380;
|
||||
graphics.ApplyChanges();
|
||||
}
|
||||
|
||||
@ -108,8 +120,10 @@ namespace Game1
|
||||
tileConnected[2] = Content.Load<Texture2D>("Right");
|
||||
tileConnected[3] = Content.Load<Texture2D>("Bottom");
|
||||
|
||||
Rain = Content.Load<Texture2D>("Clouds");
|
||||
|
||||
|
||||
Background = Content.Load<Texture2D>("WoodBackground");
|
||||
|
||||
|
||||
Crops[0] = Content.Load<Texture2D>("Markers");
|
||||
@ -159,9 +173,9 @@ namespace Game1
|
||||
input.controlWindowSize(); //Controls the size of the screen depending on the number of tiles
|
||||
houseUnit.updateRectangle(input.getSize(), input.getTileSize(), input.getSpacing()); //Updates the position of the house if the house appears out of bound
|
||||
Time.updateTime(tractorUnit.getSpeed());
|
||||
|
||||
|
||||
|
||||
//System.Threading.Thread updatethread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Update));
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
||||
@ -171,7 +185,6 @@ namespace Game1
|
||||
GraphicsDevice.Clear(Color.FromNonPremultiplied(255,255,255,140));
|
||||
|
||||
spriteBatch.Begin();
|
||||
|
||||
DrawTiles();
|
||||
|
||||
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getTargetPosition().X / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, (int)tractorUnit.getTargetPosition().Y / input.getSpacingTile() * (input.getTileSize() + input.getSpacing()) + input.getTileSize() / 4, input.getTileSize()/2, input.getTileSize()/2), Color.White);
|
||||
@ -183,52 +196,62 @@ namespace Game1
|
||||
|
||||
|
||||
|
||||
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
|
||||
|
||||
spriteBatch.Draw(markers, new Rectangle((int)tractorUnit.getPath().getFinalDest().getCords().X * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), (int)tractorUnit.getPath().getFinalDest().getCords().Y * (input.getSpacingTile()) + Convert.ToInt32(input.getTileSize() / 6), Convert.ToInt32(input.getTileSize() / 1.5), Convert.ToInt32(input.getTileSize() / 1.5)), Color.White); //Draws the current target of the tractor
|
||||
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
spriteBatch.Draw(ProgressionBar, new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 295), Color.White);
|
||||
}
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
spriteBatch.Draw(ProgressionBar, new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
spriteBatch.Draw(Background, new Rectangle(i * 512, (int)input.getSize().Y * (input.getTileSize() + input.getSpacing()) + j * 512, 512, 512), Color.FromNonPremultiplied(125, 125, 125, 255));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
spriteBatch.Draw(tile[0], new Rectangle(i * 227, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())), 5, 500), Color.White);
|
||||
}
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
spriteBatch.Draw(tile[0], new Rectangle(0, (int)(input.getSize().Y * (input.getTileSize() + input.getSpacing())) + i * 20, (int)(input.getSize().X * (input.getTileSize() + input.getSpacing())), 1), Color.White);
|
||||
}
|
||||
|
||||
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
|
||||
spriteBatch.DrawString(Bold, "Time: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Days " + Time.getDays(), new Vector2(60, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, Time.getTimeOfYear(), new Vector2(120, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Day Progression: ", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, Time.GetTimeOfDayInt().ToString() + "%", new Vector2(140, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
|
||||
|
||||
spriteBatch.DrawString(Bold, "Tractor Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 62), Color.DarkRed);
|
||||
|
||||
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82) , Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Speed:" + tractorUnit.getSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 82), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Tractor Position:" + new Vector2((float)Math.Round(tractorUnit.getPos().X / input.getSpacingTile(), 1), (float)Math.Round(tractorUnit.getPos().Y / input.getSpacingTile(), 1)), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 102), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Tractor Rotation:" + Math.Round(tractorUnit.getRotation(), 2).ToString() + " Degrees", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 122), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Tractor Speed:" + tractorUnit.getTractorSpeed().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 142), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Tractor Target:" + tractorUnit.getPath().getFinalDest().getCords().ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 162), Color.Teal);
|
||||
|
||||
|
||||
|
||||
spriteBatch.DrawString(Bold, "Map Properties:", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 202), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.DarkBlue); //Draws the tile size
|
||||
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.DarkBlue);
|
||||
|
||||
spriteBatch.DrawString(Bold, "Tile Size:" + input.getTileSize().ToString() + "pix", new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 222), Color.Teal); //Draws the tile size
|
||||
spriteBatch.DrawString(Bold, "Matrix Size: " + input.getSize().X.ToString() + " X " + input.getSize().Y.ToString(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 242), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "House Position: " + houseUnit.getVector() / input.getSpacingTile(), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 262), Color.Teal);
|
||||
tractorUnit.getFarm().drawWeatherInformation(spriteBatch, Bold, input);
|
||||
spriteBatch.DrawString(Bold, "Total Weight: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.DarkBlue);
|
||||
|
||||
tractorUnit.drawInventory(input, spriteBatch, Bold, inventory.getPredefinedItems());
|
||||
|
||||
InspectTile();
|
||||
|
||||
spriteBatch.DrawString(Bold, "(" + tractorUnit.getInventory().getWeight() + "/" + tractorUnit.getInventory().getMaxWeight() + ")", new Vector2(800, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 182), Color.Teal);
|
||||
spriteBatch.Draw(mouseCursor, new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 14, 21), Color.White);
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin();
|
||||
InspectTile();
|
||||
spriteBatch.End();
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
|
||||
@ -239,10 +262,9 @@ namespace Game1
|
||||
{
|
||||
for (int j = 0; j < input.getSize().Y; j++)
|
||||
{
|
||||
|
||||
|
||||
Rectangle tilePos = new Rectangle(i * (input.getSpacingTile()), j * (input.getSpacingTile()), input.getTileSize(), input.getTileSize());
|
||||
|
||||
|
||||
|
||||
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Time.GetTimeOfDay());
|
||||
if (i > 0)
|
||||
{
|
||||
@ -306,12 +328,23 @@ namespace Game1
|
||||
|
||||
}
|
||||
}
|
||||
spriteBatch.Draw(house, houseUnit.GetRectangle(), Time.GetTimeOfDay());
|
||||
spriteBatch.Draw(tractor, new Vector2((int)tractorUnit.getPos().X + input.getTileSize() / 2, (int)tractorUnit.getPos().Y + input.getTileSize() / 2), new Rectangle(0, 0, input.getTileSize(), input.getTileSize()), Time.GetTimeOfDay(), tractorUnit.getRotation(), new Vector2(input.getTileSize() / 2, input.getTileSize() / 2), 1.0f, SpriteEffects.None, 1);
|
||||
|
||||
for (int i = -1; i < input.getSize().X + 1; i++) //Draw the tiles
|
||||
{
|
||||
for (int j = -1; j < input.getSize().Y + 1; j++)
|
||||
{
|
||||
spriteBatch.Draw(Rain, tractorUnit.getFarm().getRainPosition(input.getTileSize(), i, j, input.getSize()), tractorUnit.getFarm().getDestinationRectangle(i, j, input.getSize()), tractorUnit.getFarm().getRainAmount(i, j, Time.GetTimeOfDay(), input.getSize()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void InspectTile()
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Crop:", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Selected tile: (" + x.ToString() + ", " + y.ToString() + ")", new Vector2(240, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 22), Color.Teal);
|
||||
tractorUnit.getFarm().getCrop(x, y).Inspect(input.getTileSize(), input.getSpacing(), Bold, new SpriteBatch(GraphicsDevice), cropTypesNames);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,12 @@
|
||||
<Compile Include="Sources\Crops\PerlinNoise.cs" />
|
||||
<Compile Include="Sources\Crops\SoilProperties.cs" />
|
||||
<Compile Include="Sources\ML\Engine.cs" />
|
||||
<Compile Include="Sources\ML_Joel\DataModel\InputArea.cs" />
|
||||
<Compile Include="Sources\ML_Joel\DataModel\Input.cs" />
|
||||
<Compile Include="Sources\ML_Joel\DataModel\OutputArea.cs" />
|
||||
<Compile Include="Sources\ML_Joel\DataModel\Output.cs" />
|
||||
<Compile Include="Sources\ML_Joel\Engine.cs" />
|
||||
<Compile Include="Sources\ML_Joel\Model.cs" />
|
||||
<Compile Include="Sources\Objects\DayNightCycle.cs" />
|
||||
<Compile Include="Sources\Objects\Fertilizer.cs" />
|
||||
<Compile Include="Sources\Objects\FertilizerHolder.cs" />
|
||||
@ -130,6 +136,7 @@
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -166,6 +173,9 @@
|
||||
<PackageReference Include="LightGBM">
|
||||
<Version>2.3.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common">
|
||||
<Version>3.6.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.ML">
|
||||
<Version>1.4.0</Version>
|
||||
</PackageReference>
|
||||
|
@ -2,6 +2,8 @@
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using WinForm = System.Windows.Forms;
|
||||
|
||||
class Controller
|
||||
{
|
||||
@ -17,7 +19,7 @@ class Controller
|
||||
public Vector2 updateWindow(int tileSize, int Spacing, Vector2 Size)
|
||||
{
|
||||
KeyboardState state = Keyboard.GetState();
|
||||
if (state.IsKeyDown(Keys.D) && Size.X < 90)
|
||||
if (state.IsKeyDown(Keys.D) && Size.X < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Width / (float)tileSize))
|
||||
{
|
||||
Size.X++;
|
||||
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
||||
@ -29,16 +31,16 @@ class Controller
|
||||
graphics.PreferredBackBufferWidth = (tileSize + Spacing) * (int)Size.X - Spacing;
|
||||
}
|
||||
|
||||
if (state.IsKeyDown(Keys.W) && Size.Y < 20)
|
||||
if (state.IsKeyDown(Keys.W) && Size.Y < Math.Floor(WinForm.Screen.PrimaryScreen.Bounds.Height / (float)tileSize) - 7)
|
||||
{
|
||||
Size.Y++;
|
||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
|
||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
|
||||
}
|
||||
|
||||
if (state.IsKeyDown(Keys.S) && Size.Y > 2)
|
||||
{
|
||||
Size.Y--;
|
||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 300;
|
||||
graphics.PreferredBackBufferHeight = (tileSize + Spacing) * (int)Size.Y - Spacing + 380;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
@ -12,12 +12,16 @@ class CropTypes
|
||||
public string[] soilType = new string[3];
|
||||
public int[] Times = new int[3];
|
||||
public string CropName;
|
||||
public string[] Season = new string[5];
|
||||
public float Temparature;
|
||||
public float Humidity;
|
||||
public float Moisture;
|
||||
public float Nitrogen;
|
||||
public float Potassium;
|
||||
public float Phosphorous;
|
||||
public float Area;
|
||||
public int AreaMin;
|
||||
public int AreaMax;
|
||||
|
||||
|
||||
public CropTypes()
|
||||
|
@ -36,6 +36,10 @@ class CropTypesHolder
|
||||
cropTypes[1].Nitrogen = 21 + 12.6f;
|
||||
cropTypes[1].Potassium = 10 + 5.3f;
|
||||
cropTypes[1].Phosphorous = 20 + 26.0f;
|
||||
cropTypes[1].Season[0] = "Spring";
|
||||
cropTypes[1].Season[1] = "Autumn";
|
||||
cropTypes[1].AreaMin = 1;
|
||||
cropTypes[1].AreaMax = 8000;
|
||||
|
||||
|
||||
// Cotton
|
||||
@ -53,6 +57,11 @@ class CropTypesHolder
|
||||
cropTypes[2].Nitrogen = 21 + 16.4f;
|
||||
cropTypes[2].Potassium = 10 + 3.3f;
|
||||
cropTypes[2].Phosphorous = 20 + 23.8f;
|
||||
cropTypes[2].Season[0] = "Spring";
|
||||
cropTypes[2].Season[1] = "Autumn";
|
||||
cropTypes[2].Season[2] = "Whole Year";
|
||||
cropTypes[2].AreaMin = 1;
|
||||
cropTypes[2].AreaMax = 199000;
|
||||
|
||||
// Ground Nuts
|
||||
cropTypes[3] = new CropTypes();
|
||||
@ -66,6 +75,13 @@ class CropTypesHolder
|
||||
cropTypes[3].Nitrogen = 21 + 23.3f;
|
||||
cropTypes[3].Potassium = 10 + 2.0f;
|
||||
cropTypes[3].Phosphorous = 20 + 21.6f;
|
||||
cropTypes[3].Season[0] = "Spring";
|
||||
cropTypes[3].Season[1] = "Autumn";
|
||||
cropTypes[3].Season[2] = "Whole Year";
|
||||
cropTypes[3].Season[3] = "Winter";
|
||||
cropTypes[3].Season[4] = "Summer";
|
||||
cropTypes[3].AreaMin = 1;
|
||||
cropTypes[3].AreaMax = 147000;
|
||||
|
||||
|
||||
// Maize
|
||||
@ -80,6 +96,13 @@ class CropTypesHolder
|
||||
cropTypes[4].Nitrogen = 21 + 18.3f;
|
||||
cropTypes[4].Potassium = 10 + 5.7f;
|
||||
cropTypes[4].Phosphorous = 20 + 18.7f;
|
||||
cropTypes[4].Season[0] = "Spring";
|
||||
cropTypes[4].Season[1] = "Autumn";
|
||||
cropTypes[4].Season[2] = "Whole Year";
|
||||
cropTypes[4].Season[3] = "Winter";
|
||||
cropTypes[4].Season[4] = "Summer";
|
||||
cropTypes[4].AreaMin = 1;
|
||||
cropTypes[4].AreaMax = 73000;
|
||||
|
||||
// Millets
|
||||
cropTypes[5] = new CropTypes();
|
||||
@ -95,6 +118,11 @@ class CropTypesHolder
|
||||
cropTypes[5].Nitrogen = 21 + 23.2f;
|
||||
cropTypes[5].Potassium = 10 + 0.1f;
|
||||
cropTypes[5].Phosphorous = 20 + 14.4f;
|
||||
cropTypes[5].Season[0] = "Spring";
|
||||
cropTypes[5].Season[1] = "Autumn";
|
||||
cropTypes[5].Season[2] = "Whole Year";
|
||||
cropTypes[5].AreaMin = 1;
|
||||
cropTypes[5].AreaMax = 59000;
|
||||
|
||||
//Oil Seeds
|
||||
cropTypes[6] = new CropTypes();
|
||||
@ -108,6 +136,9 @@ class CropTypesHolder
|
||||
cropTypes[6].Nitrogen = 21 + 19.0f;
|
||||
cropTypes[6].Potassium = 10 + 2.3f;
|
||||
cropTypes[6].Phosphorous = 20 + 17.3f;
|
||||
cropTypes[6].Season[0] = "Whole Year";
|
||||
cropTypes[6].AreaMin = 25;
|
||||
cropTypes[6].AreaMax = 25000;
|
||||
|
||||
//Paddys
|
||||
cropTypes[7] = new CropTypes();
|
||||
@ -121,6 +152,11 @@ class CropTypesHolder
|
||||
cropTypes[7].Nitrogen = 21 + 20.8f;
|
||||
cropTypes[7].Potassium = 10 + 3.7f;
|
||||
cropTypes[7].Phosphorous = 20 + 16.3f;
|
||||
cropTypes[7].Season[0] = "Autumn";
|
||||
cropTypes[7].Season[1] = "Winter";
|
||||
cropTypes[7].Season[2] = "Summer";
|
||||
cropTypes[7].AreaMin = 200;
|
||||
cropTypes[7].AreaMax = 270000;
|
||||
|
||||
//Pulses
|
||||
cropTypes[8] = new CropTypes();
|
||||
@ -134,6 +170,12 @@ class CropTypesHolder
|
||||
cropTypes[8].Nitrogen = 21 + 18.4f;
|
||||
cropTypes[8].Potassium = 10 + 4.2f;
|
||||
cropTypes[8].Phosphorous = 20 + 17.5f;
|
||||
cropTypes[8].Season[0] = "Spring";
|
||||
cropTypes[8].Season[1] = "Autumn";
|
||||
cropTypes[8].Season[2] = "Whole Year";
|
||||
cropTypes[8].Season[3] = "Summer";
|
||||
cropTypes[8].AreaMin = 40;
|
||||
cropTypes[8].AreaMax = 140000;
|
||||
|
||||
//Sugarcane
|
||||
cropTypes[9] = new CropTypes();
|
||||
@ -149,6 +191,12 @@ class CropTypesHolder
|
||||
cropTypes[9].Nitrogen = 21 + 14.6f;
|
||||
cropTypes[9].Potassium = 10 + 4.2f;
|
||||
cropTypes[9].Phosphorous = 20 + 17.6f;
|
||||
cropTypes[9].Season[0] = "Spring";
|
||||
cropTypes[9].Season[1] = "Autumn";
|
||||
cropTypes[9].Season[2] = "Whole Year";
|
||||
cropTypes[9].Season[3] = "Winter";
|
||||
cropTypes[9].AreaMin = 1;
|
||||
cropTypes[9].AreaMax = 23000;
|
||||
|
||||
|
||||
//Tobacco
|
||||
@ -163,6 +211,11 @@ class CropTypesHolder
|
||||
cropTypes[10].Nitrogen = 21 + 19.1f;
|
||||
cropTypes[10].Potassium = 10 + 4.9f;
|
||||
cropTypes[10].Phosphorous = 20 + 19.3f;
|
||||
cropTypes[10].Season[0] = "Spring";
|
||||
cropTypes[10].Season[1] = "Autumn";
|
||||
cropTypes[10].Season[2] = "Whole Year";
|
||||
cropTypes[10].AreaMin = 1;
|
||||
cropTypes[10].AreaMax = 9500;
|
||||
|
||||
|
||||
//Wheat
|
||||
@ -177,6 +230,12 @@ class CropTypesHolder
|
||||
cropTypes[11].Nitrogen = 21 + 23.3f;
|
||||
cropTypes[11].Potassium = 10 + 2.9f;
|
||||
cropTypes[11].Phosphorous = 20 + 14.4f;
|
||||
cropTypes[11].Season[0] = "Spring";
|
||||
cropTypes[11].Season[1] = "Autumn";
|
||||
cropTypes[11].Season[2] = "Whole Year";
|
||||
cropTypes[11].Season[3] = "Summer";
|
||||
cropTypes[11].AreaMin = 1;
|
||||
cropTypes[11].AreaMax = 266000;
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,18 +14,23 @@ 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();
|
||||
private CropTypes DataSet;
|
||||
SoilProperties soilProperties = new SoilProperties();
|
||||
private float ProductionRate;
|
||||
private float tempRain;
|
||||
private float prevpred;
|
||||
private DayNightCycle Time = new DayNightCycle();
|
||||
private int previousDay = 0;
|
||||
|
||||
|
||||
|
||||
public void updateCrop(Vector2 newSize)
|
||||
public void updateCrop(Vector2 newSize, DayNightCycle nTime)
|
||||
{
|
||||
getProductionRate(DataSet);
|
||||
Time = nTime;
|
||||
if (UpdateCrop == 60)
|
||||
{
|
||||
degradeSoil();
|
||||
@ -45,6 +50,11 @@ class Crops
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProductionRate()
|
||||
{
|
||||
getProductionRate(DataSet);
|
||||
}
|
||||
|
||||
public float getSpeedFactor(float tractorSpeed)
|
||||
{
|
||||
if (getCostOnMovement() == 1)
|
||||
@ -197,27 +207,57 @@ class Crops
|
||||
|
||||
public void degradeSoil()
|
||||
{
|
||||
|
||||
Random r = new Random();
|
||||
if (soilProperties.Nitrogen > 4.0f)
|
||||
{
|
||||
soilProperties.Nitrogen = soilProperties.Nitrogen - (soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2));
|
||||
soilProperties.Nitrogen = soilProperties.Nitrogen - ((soilProperties.NitrogenDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
||||
}
|
||||
if (soilProperties.Phosphorous > 0.1f)
|
||||
{
|
||||
soilProperties.Phosphorous = soilProperties.Phosphorous - (soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2));
|
||||
soilProperties.Phosphorous = soilProperties.Phosphorous - ((soilProperties.PhosphorousDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
||||
}
|
||||
if (soilProperties.Potassium > 0.1f)
|
||||
{
|
||||
soilProperties.Potassium = soilProperties.Potassium - (soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2));
|
||||
soilProperties.Potassium = soilProperties.Potassium - ((soilProperties.PotassiumDegradeRate * (float)Math.Pow(ProductionRate, 2)) * (float)Math.Pow((r.NextDouble() + 0.5f), 2));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRainfall(float Rain)
|
||||
{
|
||||
if (Rain >= 0.45f)
|
||||
{
|
||||
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrevRainfall()
|
||||
{
|
||||
|
||||
soilProperties.prevRainfall = soilProperties.Rainfall;
|
||||
if (soilProperties.prevRainfall > 3616)
|
||||
soilProperties.prevRainfall = 3616;
|
||||
else if (soilProperties.prevRainfall < 236)
|
||||
soilProperties.prevRainfall = 236;
|
||||
soilProperties.Rainfall = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setCropType(int Type, CropTypes nCropType)
|
||||
{
|
||||
DataSet = nCropType;
|
||||
cropType = Type;
|
||||
if (Timer == fullTimer)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
@ -240,6 +280,7 @@ class Crops
|
||||
public void setStatus(int newStatus)
|
||||
{
|
||||
Status = newStatus;
|
||||
Timer = getCropTimer();
|
||||
}
|
||||
|
||||
public void setOriginalStatus()
|
||||
@ -253,6 +294,7 @@ class Crops
|
||||
housePos = state;
|
||||
if (state)
|
||||
{
|
||||
Timer = 1;
|
||||
Status = 1;
|
||||
}
|
||||
else
|
||||
@ -297,6 +339,12 @@ class Crops
|
||||
|
||||
public float getProductionRate(CropTypes Sample)
|
||||
{
|
||||
float predProd = 1.0f;
|
||||
if (Status > 1 && Time.getDays() != previousDay)
|
||||
{
|
||||
predProd = updateMLModel(Sample, predProd);
|
||||
}
|
||||
prevpred = predProd;
|
||||
ProductionRate = 1;
|
||||
float min = 1.0f;
|
||||
if (DataSet != null)
|
||||
@ -335,7 +383,31 @@ class Crops
|
||||
ProductionRate = ProductionRate / 1.5f;
|
||||
}
|
||||
ProductionRate = (float)Math.Pow(ProductionRate, 2.5f);
|
||||
return ProductionRate;
|
||||
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()
|
||||
@ -363,26 +435,26 @@ class Crops
|
||||
spriteBatch.Begin();
|
||||
if (housePos)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tiletype: House", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
||||
}
|
||||
else if (Status == 0)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Boulders", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
||||
}
|
||||
else if (Status == 1)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Grassfield", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
||||
}
|
||||
else if (Status == 2)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Soil", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
||||
}
|
||||
else if (Status == 3)
|
||||
{
|
||||
int x = (int)(((float)Timer / fullTimer) * 100);
|
||||
x = 100 - x;
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Tiletype: Crop ", new Vector2(240, Size.Y * (tileSize + Spacing) + 42), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Completion: " + x + "%", new Vector2(240, Size.Y * (tileSize + Spacing) + 82), Color.Teal);
|
||||
}
|
||||
if (Status != 3)
|
||||
{
|
||||
@ -390,29 +462,37 @@ class Crops
|
||||
}
|
||||
if (Status > 1)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "Prefered Crop: " + cropTypesNames[cropType], new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, "None", new Vector2(240, Size.Y * (tileSize + Spacing) + 62), Color.Teal);
|
||||
}
|
||||
spriteBatch.DrawString(Bold, "Soil Properties:", new Vector2(240, Size.Y * (tileSize + Spacing) + 122), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "Soil Type: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 142), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, soilProperties.soilType, new Vector2(370, Size.Y * (tileSize + Spacing) + 142), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Temparature: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 162), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Temperature.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 162), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Moisture: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 182), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Moisture.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 182), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Humidity: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 202), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Humidity.ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 202), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Phosphorous: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 222), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Phosphorous,1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 222), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Potassium: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 242), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Potassium, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 242), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Nitrogen: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 262), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, Math.Round(soilProperties.Nitrogen, 1).ToString(), new Vector2(370, Size.Y * (tileSize + Spacing) + 262), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Production Rate: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 282), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, Math.Round((ProductionRate * 100), 1).ToString() + "%", new Vector2(370, Size.Y * (tileSize + Spacing) + 282), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Last Years Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 302), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round((soilProperties.prevRainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 302), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Rainfall: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 322), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round((soilProperties.Rainfall), 1).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 322), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Rain mm/s: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 342), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, Math.Round((tempRain * 2), 2).ToString() + "mm", new Vector2(370, Size.Y * (tileSize + Spacing) + 342), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, "Area: ", new Vector2(240, Size.Y * (tileSize + Spacing) + 362), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, soilProperties.Area + "m^2", new Vector2(370, Size.Y * (tileSize + Spacing) + 362), Color.Teal);
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -14,8 +16,17 @@ class Farm
|
||||
private int Update;
|
||||
private Astar astar = new Astar();
|
||||
private PerlinNoise perlin = new PerlinNoise();
|
||||
private Vector2 RainPosition;
|
||||
private Vector2 WindSpeed = new Vector2(0,0);
|
||||
private System.Drawing.Color[][] RainfallMap;
|
||||
private float[][] whiteNoise;
|
||||
private float[][] perlinNoise;
|
||||
private DayNightCycle Time;
|
||||
private float updatePerc = 0.01f;
|
||||
private float updateProgress = 0;
|
||||
private float nextUpdate = 0;
|
||||
private int productionUpdate = 0;
|
||||
private string path_base = FindPath();
|
||||
|
||||
|
||||
//initializes the crops
|
||||
@ -32,17 +43,7 @@ class Farm
|
||||
for (int j = 0; j < 99; j++)
|
||||
{
|
||||
int x = 0;
|
||||
/*
|
||||
int x = r.Next(0, 3);
|
||||
if (x == 0)
|
||||
{
|
||||
x = r.Next(0, 2);
|
||||
}
|
||||
if (x == 2)
|
||||
{
|
||||
x = r.Next(1, 3);
|
||||
}
|
||||
*/
|
||||
|
||||
if (perlinNoise[i][j] > 0 && perlinNoise[i][j] < 0.15f)
|
||||
x = 0;
|
||||
else if (perlinNoise[i][j] >= 0.15f && perlinNoise[i][j] < 0.8f)
|
||||
@ -52,7 +53,7 @@ class Farm
|
||||
crops[i, j] = new Crops();
|
||||
crops[i, j].setStatus(x);
|
||||
crops[i, j].setOriginalStatus();
|
||||
x = r.Next(0, 12);
|
||||
x = r.Next(1, 12);
|
||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
||||
crops[i, j].init();
|
||||
|
||||
@ -70,7 +71,6 @@ class Farm
|
||||
{
|
||||
if (!astar.isReachable(crops, new Vector2((int)i, (int)j), housepos))
|
||||
{
|
||||
//crops[i, j].setStatus(1);
|
||||
dirtCount--;
|
||||
}
|
||||
}
|
||||
@ -78,6 +78,52 @@ class Farm
|
||||
}
|
||||
if (dirtCount != 0)
|
||||
init(Size, housepos);
|
||||
RainPosition.X = r.Next(0, 1900);
|
||||
RainPosition.Y = r.Next(0, 1950);
|
||||
float coef = GetRandomNumber(-1f, 1f);
|
||||
if (coef < 0)
|
||||
coef = -1.0f;
|
||||
else
|
||||
coef = 1.0f;
|
||||
WindSpeed.X = GetRandomNumber(0.9f, 1f) / 50 * coef;
|
||||
WindSpeed.Y = GetRandomNumber(0.9f, 1f) / 50 * coef;
|
||||
RainfallMap = PerlinNoise.LoadImage(System.IO.Path.Combine(path_base, "Content/Rainfall.png"));
|
||||
}
|
||||
|
||||
public Rectangle getRainPosition(int TileSize, int x, int y, Vector2 Size)
|
||||
{
|
||||
float xtrunc = RainPosition.X - (float)Math.Truncate(RainPosition.X);
|
||||
float ytrunc = RainPosition.Y - (float)Math.Truncate(RainPosition.Y);
|
||||
|
||||
if (xtrunc > 0.5)
|
||||
xtrunc = xtrunc - 1;
|
||||
|
||||
if (ytrunc > 0.5)
|
||||
ytrunc = ytrunc - 1;
|
||||
xtrunc = -xtrunc;
|
||||
ytrunc = -ytrunc;
|
||||
|
||||
|
||||
|
||||
//return new Rectangle((int)(xtrunc * TileSize) + x * TileSize,(int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
|
||||
return new Rectangle((int)(xtrunc * TileSize) + x * TileSize, (int)(ytrunc * TileSize) + y * TileSize, TileSize, TileSize);
|
||||
}
|
||||
|
||||
public Rectangle getDestinationRectangle(int x, int y, Vector2 Size)
|
||||
{
|
||||
Vector2 temp = new Vector2((int)Math.Round(x + RainPosition.X), y + (int)Math.Round(RainPosition.Y));
|
||||
if (temp.X >= 1999 - Size.X - 1)
|
||||
temp.X = -(1999 - (int)Math.Round(RainPosition.X));
|
||||
if (temp.Y >= 1999 - Size.Y - 1)
|
||||
temp.Y = -(1999 - (int)Math.Round(RainPosition.Y));
|
||||
return new Rectangle((int)temp.X, (int)temp.Y, 1, 1);
|
||||
}
|
||||
|
||||
public void drawWeatherInformation(SpriteBatch spriteBatch, SpriteFont Bold, Input input)
|
||||
{
|
||||
spriteBatch.DrawString(Bold, "WindSpeed: " + Math.Round(WindSpeed.X, 4), new Vector2(10, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, " : ", new Vector2(153, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, Math.Round(WindSpeed.Y, 4).ToString(), new Vector2(163, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 282), Color.Teal);
|
||||
}
|
||||
|
||||
public void updateFarm(Vector2 Size)
|
||||
@ -89,13 +135,58 @@ class Farm
|
||||
{
|
||||
for (int j = 0; j < Size.Y; j++)
|
||||
{
|
||||
|
||||
crops[i, j].updateCrop(Size);
|
||||
Vector2 temp = new Vector2((int)Math.Round(i + RainPosition.X), j + (int)Math.Round(RainPosition.Y));
|
||||
if (temp.X >= 1999 - Size.X - 1)
|
||||
temp.X = i + ((1999 - (int)Math.Round(RainPosition.X)));
|
||||
if (temp.Y >= 1999 - Size.Y - 1)
|
||||
temp.Y = i + ((1999 - (int)Math.Round(RainPosition.Y)));
|
||||
crops[i, j].updateCrop(Size, Time);
|
||||
crops[i, j].updateRainfall(RainfallMap[(int)Math.Round(temp.X)][(int)Math.Round(temp.Y)].GetBrightness());
|
||||
}
|
||||
}
|
||||
|
||||
Update = 0;
|
||||
}
|
||||
updateRainMapPosition(Size);
|
||||
if (productionUpdate == 2)
|
||||
{
|
||||
nextUpdate = updateProgress + updatePerc;
|
||||
for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++)
|
||||
{
|
||||
for (int j = 0; j < Size.Y; j++)
|
||||
{
|
||||
if (crops[i, j].getStatus() > 1)
|
||||
{
|
||||
int x = getHighestProductionRate(i, j);
|
||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
||||
crops[i, j].updateProductionRate();
|
||||
}
|
||||
}
|
||||
}
|
||||
updateProgress = updateProgress + updatePerc;
|
||||
if (updateProgress >= 1)
|
||||
{
|
||||
updateProgress = 0;
|
||||
}
|
||||
productionUpdate = 0;
|
||||
nextUpdate = 0;
|
||||
}
|
||||
productionUpdate++;
|
||||
}
|
||||
|
||||
public void updateRainFall(Vector2 Size, DayNightCycle nTime)
|
||||
{
|
||||
Time = nTime;
|
||||
if (nTime.nDay())
|
||||
{
|
||||
for (int i = 0; i < Size.X; i++)
|
||||
{
|
||||
for (int j = 0; j < Size.Y; j++)
|
||||
{
|
||||
crops[i, j].setPrevRainfall();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Changes the properties of the tile when the tractor reaches this tile.
|
||||
@ -129,6 +220,42 @@ class Farm
|
||||
return crops;
|
||||
}
|
||||
|
||||
private void updateRainMapPosition(Vector2 Size)
|
||||
{
|
||||
double x, y;
|
||||
x = WindSpeed.X + GetRandomNumber(-1f, 1f) / 20000;
|
||||
y = WindSpeed.Y + GetRandomNumber(-1f, 1f) / 20000;
|
||||
if (x <= 0.02f && x >= -0.02f)
|
||||
{
|
||||
WindSpeed.X = (float)x;
|
||||
}
|
||||
|
||||
if (y < 0.02f && y > -0.02f)
|
||||
{
|
||||
WindSpeed.Y = (float)y;
|
||||
}
|
||||
|
||||
if (WindSpeed.X > 0 && RainPosition.X < 2000)
|
||||
RainPosition.X = RainPosition.X + WindSpeed.X;
|
||||
else if (WindSpeed.X < 0 && RainPosition.X > 0)
|
||||
RainPosition.X = RainPosition.X + WindSpeed.X;
|
||||
|
||||
if (WindSpeed.Y > 0 && RainPosition.Y < 2000)
|
||||
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
|
||||
else if (WindSpeed.Y < 0 && RainPosition.Y > 0)
|
||||
RainPosition.Y = RainPosition.Y + WindSpeed.Y;
|
||||
|
||||
if (Math.Round(RainPosition.X) == 1999 && WindSpeed.X > 0)
|
||||
RainPosition.X = 0;
|
||||
else if (Math.Round(RainPosition.X) == 1 && WindSpeed.X < 0)
|
||||
RainPosition.X = 1999;
|
||||
|
||||
if (Math.Round(RainPosition.Y) == 1999 && WindSpeed.Y > 0)
|
||||
RainPosition.Y = 0;
|
||||
else if (Math.Round(RainPosition.Y) == 1 && WindSpeed.Y < 0)
|
||||
RainPosition.Y = 1999;
|
||||
}
|
||||
|
||||
public void setNewHousePos(Vector2 pos, bool newState)
|
||||
{
|
||||
crops[(int)pos.X, (int)pos.Y].setHousePos(newState);
|
||||
@ -136,7 +263,7 @@ class Farm
|
||||
|
||||
public CropTypes getPresetCropTypes(int Index)
|
||||
{
|
||||
return PresetCrops.getPresetCropTypes(Index - 1);
|
||||
return PresetCrops.getPresetCropTypes(Index);
|
||||
}
|
||||
|
||||
public void setCropType(int x, int y, int Type)
|
||||
@ -150,7 +277,7 @@ class Farm
|
||||
{
|
||||
for (int j = 0; j < Size.X; j++)
|
||||
{
|
||||
if (crops[i, j].getStatus() != 3)
|
||||
if (crops[i, j].getStatus() == 2)
|
||||
{
|
||||
int x = getHighestProductionRate(i, j);
|
||||
crops[i, j].setCropType(x, PresetCrops.getPresetCropTypes(x));
|
||||
@ -161,7 +288,7 @@ class Farm
|
||||
|
||||
private int getHighestProductionRate(int x, int y)
|
||||
{
|
||||
int i = 1, holderIndex = 0;
|
||||
int i = 6, holderIndex = 0;
|
||||
float holder = 0, SampleHolder = 0;
|
||||
do
|
||||
{
|
||||
@ -176,8 +303,47 @@ class Farm
|
||||
return holderIndex;
|
||||
}
|
||||
|
||||
public Color getRainAmount(int x, int y, Color color, Vector2 Size)
|
||||
{
|
||||
Vector2 temp = new Vector2(x + (int)Math.Round(RainPosition.X), y + (int)Math.Round(RainPosition.Y));
|
||||
if (temp.X >= 1999)
|
||||
temp.X = -(1999 - (int)Math.Round(temp.X));
|
||||
if (temp.Y >= 1999)
|
||||
temp.Y = -(1999 - (int)Math.Round(temp.Y));
|
||||
if (temp.X == -1)
|
||||
temp.X = 1999;
|
||||
if (temp.Y == -1)
|
||||
temp.Y = 1999;
|
||||
if (RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness() < 0.45f)
|
||||
{
|
||||
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.FromNonPremultiplied(color.R, color.G, color.B, (int)(255 * RainfallMap[(int)temp.X][(int)temp.Y].GetBrightness()));
|
||||
}
|
||||
}
|
||||
|
||||
public float getProductionRate(int x, int y, int Type)
|
||||
{
|
||||
return crops[x, y].getProductionRate(PresetCrops.getPresetCropTypes(Type));
|
||||
return crops[x, y]. getProductionRate(PresetCrops.getPresetCropTypes(Type));
|
||||
}
|
||||
|
||||
public float GetRandomNumber(double minimum, double maximum)
|
||||
{
|
||||
return (float)(Math.Round(r.NextDouble() * (maximum - minimum) + minimum, 2));
|
||||
}
|
||||
|
||||
private static string FindPath()
|
||||
{
|
||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
||||
while (true)
|
||||
{
|
||||
path = Directory.GetParent(path).ToString();
|
||||
if (path.EndsWith("\\Game1"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,13 @@ class SoilProperties
|
||||
public float Nitrogen;
|
||||
public float Potassium;
|
||||
public float Phosphorous;
|
||||
public float NitrogenDegradeRate = 1.0f - (1.0f/55 * 40);
|
||||
public float PotassiumDegradeRate = 1.0f - (1.0f/28 * 23);
|
||||
public float PhosphorousDegradeRate = 1.0f - (1.0f/60 * 37);
|
||||
public float Rainfall;
|
||||
public float prevRainfall;
|
||||
public float NitrogenDegradeRate = 0.8f / 1.5f;
|
||||
public float PotassiumDegradeRate = 0.3f / 1.5f;
|
||||
public float PhosphorousDegradeRate = 0.6f / 1.5f;
|
||||
public int Capacity = 80;
|
||||
public int Area;
|
||||
|
||||
public void setSoilProperties()
|
||||
{
|
||||
@ -51,6 +54,8 @@ class SoilProperties
|
||||
Nitrogen = GetRandomNumber(4 , 42); //was 4, 60
|
||||
Potassium = GetRandomNumber(0.01f, 19); // was 0, 28
|
||||
Phosphorous = GetRandomNumber(0.01f, 42); // was 0, 60
|
||||
prevRainfall = r.Next(247, 3617);
|
||||
Area = r.Next(1, 270000);
|
||||
}
|
||||
|
||||
public float GetRandomNumber(double minimum, double maximum)
|
||||
|
@ -10,6 +10,7 @@ static class Engine
|
||||
{
|
||||
private static MLContext mlContext = new MLContext(seed: 1);
|
||||
private static PredictionEngine<ModelInput, ModelOutput> PredictionEngine;
|
||||
private static ModelOutput modelOutput;
|
||||
|
||||
public static void init()
|
||||
{
|
||||
@ -30,7 +31,9 @@ static class Engine
|
||||
Phosporous = crop.getSoilProperties().Phosphorous
|
||||
};
|
||||
|
||||
return PredictionEngine.Predict(modelInput).Prediction;
|
||||
//ModelOutput modelOutput = new ModelOutput();
|
||||
PredictionEngine.Predict(modelInput, ref modelOutput);
|
||||
return modelOutput.Prediction;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML;
|
||||
@ -11,12 +12,16 @@ using Microsoft.ML.Trainers.LightGbm;
|
||||
class MLModel
|
||||
{
|
||||
private static MLContext mlContext = new MLContext(seed: 1);
|
||||
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 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_base = FindPath();
|
||||
|
||||
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Fertilizer_Prediction.csv");
|
||||
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel");
|
||||
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report");
|
||||
|
||||
private static string pathBig = System.IO.Path.Combine(path_base, "Content/ML/BigFertPredict.csv");
|
||||
private static string modelpathBig = System.IO.Path.Combine(path_base, "Content/ML/MLmodelBig");
|
||||
private static string reportBig = System.IO.Path.Combine(path_base, "Content/ML/report_BigModel");
|
||||
|
||||
// Loading data, creatin and saving ML model for smaller dataset (100)
|
||||
public static void CreateModel()
|
||||
@ -157,11 +162,25 @@ class MLModel
|
||||
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
|
||||
}
|
||||
|
||||
public static Microsoft.ML.PredictionEngine<ModelInput, ModelOutput> CreateEngine()
|
||||
public static PredictionEngine<ModelInput, ModelOutput> CreateEngine()
|
||||
{
|
||||
ITransformer mlModel = LoadModel(false);
|
||||
return mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);
|
||||
}
|
||||
|
||||
private static string FindPath()
|
||||
{
|
||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
||||
while (true)
|
||||
{
|
||||
path = Directory.GetParent(path).ToString();
|
||||
if (path.EndsWith("\\Game1"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
24
Game1/Sources/ML_Joel/DataModel/Input.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
class Input
|
||||
{
|
||||
[ColumnName("Season"), LoadColumn(0)]
|
||||
public String Season { get; set; }
|
||||
|
||||
[ColumnName("Crop"), LoadColumn(1)]
|
||||
public String Crop { get; set; }
|
||||
|
||||
[ColumnName("Rainfall"), LoadColumn(2)]
|
||||
public float Rainfall { get; set; }
|
||||
|
||||
[ColumnName("Production"), LoadColumn(3)]
|
||||
public float Production { get; set; }
|
||||
}
|
||||
}
|
27
Game1/Sources/ML_Joel/DataModel/InputArea.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
class InputArea
|
||||
{
|
||||
[ColumnName("Season"), LoadColumn(0)]
|
||||
public String Season { get; set; }
|
||||
|
||||
[ColumnName("Crop"), LoadColumn(1)]
|
||||
public String Crop { get; set; }
|
||||
|
||||
[ColumnName("Area"), LoadColumn(2)]
|
||||
public float Area { get; set; }
|
||||
|
||||
[ColumnName("Rainfall"), LoadColumn(3)]
|
||||
public float Rainfall { get; set; }
|
||||
|
||||
[ColumnName("Production"), LoadColumn(4)]
|
||||
public float Production { get; set; }
|
||||
}
|
||||
}
|
20
Game1/Sources/ML_Joel/DataModel/Output.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
class Output
|
||||
{
|
||||
//[ColumnName("PredictedLabel")]
|
||||
public float Prediction { get; set; }
|
||||
public float Score { get; set; }
|
||||
|
||||
//[ColumnName("Score")]
|
||||
// public float[] Score { get; set; }
|
||||
|
||||
}
|
||||
}
|
15
Game1/Sources/ML_Joel/DataModel/OutputArea.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
class OutputArea
|
||||
{
|
||||
public float Prediction { get; set; }
|
||||
public float Score { get; set; }
|
||||
}
|
||||
}
|
55
Game1/Sources/ML_Joel/Engine.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML;
|
||||
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
static class Engine
|
||||
{
|
||||
private static MLContext mlContext = new MLContext(seed: 1);
|
||||
private static PredictionEngine<Input, Output> PredictionEngine;
|
||||
private static PredictionEngine<InputArea, OutputArea> PredictionEngineArea;
|
||||
private static OutputArea modelOutput;
|
||||
|
||||
|
||||
public static void CreateModel()
|
||||
{
|
||||
Model.CreateModel();
|
||||
}
|
||||
|
||||
public static void CreateModelArea()
|
||||
{
|
||||
Model.CreateModelArea();
|
||||
}
|
||||
|
||||
public static void init()
|
||||
{
|
||||
PredictionEngine = Model.CreateEngine();
|
||||
}
|
||||
|
||||
public static void initArea()
|
||||
{
|
||||
PredictionEngineArea = Model.CreateEngineArea();
|
||||
}
|
||||
|
||||
public static float PredictProductionwithRainfall(SoilProperties soilProperties, DayNightCycle Time)
|
||||
{
|
||||
InputArea modelInput = new InputArea
|
||||
{
|
||||
Season = Time.getTimeOfYear(),
|
||||
Area = soilProperties.Area,
|
||||
Rainfall = soilProperties.prevRainfall,
|
||||
};
|
||||
|
||||
//OutputArea modelOutput = new OutputArea();
|
||||
PredictionEngineArea.Predict(modelInput, ref modelOutput);
|
||||
return modelOutput.Score;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
190
Game1/Sources/ML_Joel/Model.cs
Normal file
@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ML;
|
||||
using Microsoft.ML.Data;
|
||||
using Microsoft.ML.Trainers.LightGbm;
|
||||
|
||||
namespace Game1.Sources.ML_Joel
|
||||
{
|
||||
class Model
|
||||
{
|
||||
private static MLContext mlContext = new MLContext(seed: 1);
|
||||
|
||||
private static string path_base = FindPath();
|
||||
|
||||
private static string path = System.IO.Path.Combine(path_base, "Content/ML/Rainfall.csv");
|
||||
private static string modelpath = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel");
|
||||
private static string report = System.IO.Path.Combine(path_base, "Content/ML/report_Joel");
|
||||
|
||||
private static string path_area = System.IO.Path.Combine(path_base, "Content/ML/Rainfall_area.csv");
|
||||
private static string modelpath_area = System.IO.Path.Combine(path_base, "Content/ML/MLmodel_Joel_area");
|
||||
private static string report_area = System.IO.Path.Combine(path_base, "Content/ML/report_Joel_area");
|
||||
|
||||
// Loading data, creatin and saving ML model for smaller dataset (100)
|
||||
public static void CreateModel()
|
||||
{
|
||||
|
||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<Input>(
|
||||
path: path,
|
||||
hasHeader: true,
|
||||
separatorChar: ',',
|
||||
allowQuoting: true,
|
||||
allowSparse: false);
|
||||
|
||||
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
|
||||
trainingDataView = splitData.TrainSet;
|
||||
IDataView testDataView = splitData.TestSet;
|
||||
Input sample = mlContext.Data.CreateEnumerable<Input>(trainingDataView, false).ElementAt(0);
|
||||
ITransformer MLModel = BuildAndTrain(mlContext, trainingDataView, testDataView, sample, report);
|
||||
SaveModel(mlContext, MLModel, modelpath, trainingDataView.Schema);
|
||||
}
|
||||
|
||||
// Building and training ML model
|
||||
public static ITransformer BuildAndTrain(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, Input sample, string reportPath)
|
||||
{
|
||||
|
||||
var options = new LightGbmRegressionTrainer.Options
|
||||
{
|
||||
MaximumBinCountPerFeature = 40,
|
||||
LearningRate = 0.00020,
|
||||
NumberOfIterations = 20000,
|
||||
NumberOfLeaves = 55,
|
||||
LabelColumnName = "Production",
|
||||
FeatureColumnName = "Features",
|
||||
|
||||
Booster = new DartBooster.Options()
|
||||
{
|
||||
MaximumTreeDepth = 10
|
||||
}
|
||||
};
|
||||
|
||||
var pipeline = mlContext.Transforms
|
||||
.Text.FeaturizeText("SeasonF", "Season")
|
||||
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
|
||||
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Rainfall"))
|
||||
.AppendCacheCheckpoint(mLContext)
|
||||
.Append(mLContext.Regression.Trainers.LightGbm(options));
|
||||
|
||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
||||
var testEval = MLModel.Transform(testDataView);
|
||||
|
||||
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
|
||||
|
||||
return MLModel;
|
||||
}
|
||||
|
||||
public static void CreateModelArea()
|
||||
{
|
||||
|
||||
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<InputArea>(
|
||||
path: path_area,
|
||||
hasHeader: true,
|
||||
separatorChar: ',',
|
||||
allowQuoting: true,
|
||||
allowSparse: false);
|
||||
|
||||
var splitData = mlContext.Data.TrainTestSplit(trainingDataView, testFraction: 0.2);
|
||||
trainingDataView = splitData.TrainSet;
|
||||
IDataView testDataView = splitData.TestSet;
|
||||
ITransformer MLModel = BuildAndTrainArea(mlContext, trainingDataView, testDataView, report_area);
|
||||
SaveModel(mlContext, MLModel, modelpath_area, trainingDataView.Schema);
|
||||
}
|
||||
|
||||
// Building and training ML model
|
||||
public static ITransformer BuildAndTrainArea(MLContext mLContext, IDataView trainingDataView, IDataView testDataView, string reportPath)
|
||||
{
|
||||
|
||||
var options = new LightGbmRegressionTrainer.Options
|
||||
{
|
||||
MaximumBinCountPerFeature = 40,
|
||||
LearningRate = 0.00020,
|
||||
NumberOfIterations = 20000,
|
||||
NumberOfLeaves = 55,
|
||||
LabelColumnName = "Production",
|
||||
FeatureColumnName = "Features",
|
||||
|
||||
Booster = new DartBooster.Options()
|
||||
{
|
||||
MaximumTreeDepth = 10
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
ITransformer MLModel = pipeline.Fit(trainingDataView);
|
||||
var testEval = MLModel.Transform(testDataView);
|
||||
|
||||
Evaluate(mlContext, testEval, pipeline, 10, reportPath, "Production");
|
||||
|
||||
return MLModel;
|
||||
}
|
||||
|
||||
public static ITransformer TrainModel(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline)
|
||||
{
|
||||
ITransformer model = trainingPipeline.Fit(trainingDataView);
|
||||
return model;
|
||||
}
|
||||
|
||||
// Evaluate and save results to a text file
|
||||
public static void Evaluate(MLContext mlContext, IDataView trainingDataView, IEstimator<ITransformer> trainingPipeline, int folds, string reportPath, string labelColumnName)
|
||||
{
|
||||
var eval = mlContext.Regression.Evaluate(trainingDataView, labelColumnName: labelColumnName);
|
||||
|
||||
var report = File.CreateText(reportPath);
|
||||
report.Write("Mean Absolute Error: " + eval.MeanAbsoluteError + '\n' + "R Squared: " + eval.RSquared, 0, 0);
|
||||
report.Flush();
|
||||
report.Close();
|
||||
}
|
||||
|
||||
|
||||
public static void SaveModel(MLContext mlContext, ITransformer Model, string modelPath, DataViewSchema modelInputSchema)
|
||||
{
|
||||
mlContext.Model.Save(Model, modelInputSchema, modelPath);
|
||||
}
|
||||
|
||||
public static ITransformer LoadModel()
|
||||
{
|
||||
return mlContext.Model.Load(modelpath, out DataViewSchema inputSchema);
|
||||
}
|
||||
|
||||
public static PredictionEngine<Input, Output> CreateEngine()
|
||||
{
|
||||
ITransformer mlModel = LoadModel();
|
||||
return mlContext.Model.CreatePredictionEngine<Input, Output>(mlModel);
|
||||
}
|
||||
|
||||
public static ITransformer LoadModelArea()
|
||||
{
|
||||
return mlContext.Model.Load(modelpath_area, out DataViewSchema inputSchema);
|
||||
}
|
||||
|
||||
public static PredictionEngine<InputArea, OutputArea> CreateEngineArea()
|
||||
{
|
||||
ITransformer mlModel = LoadModelArea();
|
||||
return mlContext.Model.CreatePredictionEngine<InputArea, OutputArea>(mlModel);
|
||||
}
|
||||
|
||||
private static string FindPath()
|
||||
{
|
||||
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).ToString();
|
||||
while(true)
|
||||
{
|
||||
path = Directory.GetParent(path).ToString();
|
||||
if (path.EndsWith("\\Game1"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,22 +8,30 @@ using Microsoft.Xna.Framework;
|
||||
class DayNightCycle
|
||||
{
|
||||
private bool Time = true;
|
||||
private bool Day = true;
|
||||
private int nightTime = 0;
|
||||
private int dayTime = 0;
|
||||
private int lengthOfDay = 20000;
|
||||
private int lengthOfNight = 20000;
|
||||
private int Days = 1;
|
||||
private int Days = 1;
|
||||
private int DaysOfYear = 0;
|
||||
private int speed = 1;
|
||||
private bool nextDay = true;
|
||||
|
||||
|
||||
public void updateTime(int Speed)
|
||||
{
|
||||
speed = Speed;
|
||||
Time = false;
|
||||
for (int i = 0; i < Speed; i++)
|
||||
{
|
||||
if (Time)
|
||||
if (Day)
|
||||
{
|
||||
dayTime++;
|
||||
if (dayTime == lengthOfDay)
|
||||
{
|
||||
Time = false;
|
||||
Day = false;
|
||||
dayTime = 0;
|
||||
}
|
||||
}
|
||||
@ -33,32 +41,47 @@ class DayNightCycle
|
||||
if (nightTime == lengthOfNight)
|
||||
{
|
||||
Time = true;
|
||||
Day = true;
|
||||
nightTime = 0;
|
||||
Days++;
|
||||
DaysOfYear++;
|
||||
}
|
||||
}
|
||||
if (DaysOfYear == 48)
|
||||
{
|
||||
DaysOfYear = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string getDayNight()
|
||||
//Season:
|
||||
//0 - Whole Year
|
||||
//1 - Spring
|
||||
//2 - Summer
|
||||
//3 - Autumn
|
||||
//4 - Winter
|
||||
|
||||
public string getTimeOfYear()
|
||||
{
|
||||
if (Time)
|
||||
{
|
||||
return "Day";
|
||||
}
|
||||
if (DaysOfYear < 12)
|
||||
return "Spring";
|
||||
else if (DaysOfYear < 24)
|
||||
return "Summer";
|
||||
else if (DaysOfYear < 36)
|
||||
return "Autumn";
|
||||
else
|
||||
{
|
||||
return "Night";
|
||||
}
|
||||
return "Winter";
|
||||
}
|
||||
|
||||
public Color GetTimeOfDay()
|
||||
{
|
||||
int blue, red, brightness;
|
||||
int blue, red, brightness, green, potatorate = 255;
|
||||
if (nightTime == 0 && dayTime == 0)
|
||||
{
|
||||
red = 1;
|
||||
blue = 1;
|
||||
green = 1;
|
||||
brightness = 1;
|
||||
|
||||
}
|
||||
@ -66,20 +89,29 @@ class DayNightCycle
|
||||
{
|
||||
if ((float)dayTime / lengthOfDay < 0.5)
|
||||
{
|
||||
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)((1.0f - (float)dayTime / lengthOfDay) * 255);
|
||||
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)((1.0f - (float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
else
|
||||
{
|
||||
blue = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||
blue = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
|
||||
if ((float)nightTime / lengthOfNight < 0.5)
|
||||
{
|
||||
red = (int)((1.0 - (float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||
red = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
else
|
||||
{
|
||||
red = (int)(((float)nightTime / lengthOfNight) * 255) + (int)(((float)dayTime / lengthOfDay) * 255);
|
||||
red = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
|
||||
if ((float)nightTime / lengthOfNight < 0.5)
|
||||
{
|
||||
green = (int)((1.0 - (float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
else
|
||||
{
|
||||
green = (int)(((float)nightTime / lengthOfNight) * potatorate) + (int)(((float)dayTime / lengthOfDay) * potatorate);
|
||||
}
|
||||
|
||||
if (Time)
|
||||
@ -98,13 +130,20 @@ class DayNightCycle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Color.FromNonPremultiplied(red, 255, blue, brightness);
|
||||
return Color.FromNonPremultiplied(red, green, blue, 255);
|
||||
}
|
||||
|
||||
public bool nDay()
|
||||
{
|
||||
if (Time)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetTimeOfDayInt()
|
||||
{
|
||||
if (Time)
|
||||
if (Day)
|
||||
{
|
||||
return (int)(100 * ((float)(dayTime + nightTime) / (lengthOfDay + lengthOfNight))) + 1;
|
||||
}
|
||||
|
@ -16,72 +16,72 @@ class FertilizerHolder
|
||||
{
|
||||
ID = 999,
|
||||
Name = "None",
|
||||
Nitrogen = 0.0f / 5,
|
||||
Phosphorus = 0 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 0.0f / 2,
|
||||
Phosphorus = 0 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[1] = new Fertilizer
|
||||
{
|
||||
ID = 0,
|
||||
Name = "10-26-26",
|
||||
Nitrogen = 10.0f / 5,
|
||||
Phosphorus = 26 * 0.436f / 5,
|
||||
Potassium = 26 * 0.83f / 5
|
||||
Nitrogen = 10.0f / 2,
|
||||
Phosphorus = 26 * 0.436f / 2,
|
||||
Potassium = 26 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[2] = new Fertilizer
|
||||
{
|
||||
ID = 1,
|
||||
Name = "14-35-14",
|
||||
Nitrogen = 14.0f / 5,
|
||||
Phosphorus = 35 * 0.436f / 5,
|
||||
Potassium = 14 * 0.83f / 5
|
||||
Nitrogen = 14.0f / 2,
|
||||
Phosphorus = 35 * 0.436f / 2,
|
||||
Potassium = 14 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[3] = new Fertilizer
|
||||
{
|
||||
ID = 2,
|
||||
Name = "17-17-17",
|
||||
Nitrogen = 17.0f / 5,
|
||||
Phosphorus = 17 * 0.436f / 5,
|
||||
Potassium = 17 * 0.83f / 5
|
||||
Nitrogen = 17.0f / 2,
|
||||
Phosphorus = 17 * 0.436f / 2,
|
||||
Potassium = 17 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[4] = new Fertilizer
|
||||
{
|
||||
ID = 3,
|
||||
Name = "20-20",
|
||||
Nitrogen = 20.0f / 5,
|
||||
Phosphorus = 20 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 20.0f / 2,
|
||||
Phosphorus = 20 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[5] = new Fertilizer
|
||||
{
|
||||
ID = 4,
|
||||
Name = "28-28",
|
||||
Nitrogen = 28.0f / 5,
|
||||
Phosphorus = 28 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 28.0f / 2,
|
||||
Phosphorus = 28 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[6] = new Fertilizer
|
||||
{
|
||||
ID = 5,
|
||||
Name = "DAP",
|
||||
Nitrogen = 18.0f / 5,
|
||||
Phosphorus = 46 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 18.0f / 2,
|
||||
Phosphorus = 46 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[7] = new Fertilizer
|
||||
{
|
||||
ID = 6,
|
||||
Name = "Urea",
|
||||
Nitrogen = 46.0f / 5,
|
||||
Phosphorus = 0 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 46.0f / 2,
|
||||
Phosphorus = 0 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
}
|
||||
*/
|
||||
@ -89,72 +89,72 @@ class FertilizerHolder
|
||||
{
|
||||
ID = 999,
|
||||
Name = "None",
|
||||
Nitrogen = 0.0f / 5,
|
||||
Phosphorus = 0 * 0.436f / 5,
|
||||
Potassium = 0 * 0.83f / 5
|
||||
Nitrogen = 0.0f / 2,
|
||||
Phosphorus = 0 * 0.436f / 2,
|
||||
Potassium = 0 * 0.83f / 2
|
||||
};
|
||||
|
||||
FertilizerType[1] = new Fertilizer
|
||||
{
|
||||
ID = 0,
|
||||
Name = "10-26-26",
|
||||
Nitrogen = 17.21f / 5,
|
||||
Phosphorus = 12.14f / 5,
|
||||
Potassium = 0.64f / 5
|
||||
Nitrogen = 17.21f / 2,
|
||||
Phosphorus = 12.14f / 2,
|
||||
Potassium = 0.64f / 2
|
||||
};
|
||||
|
||||
FertilizerType[2] = new Fertilizer
|
||||
{
|
||||
ID = 1,
|
||||
Name = "14-35-14",
|
||||
Nitrogen = 16.89f / 5,
|
||||
Phosphorus = 6.21f / 5,
|
||||
Potassium = 5.21f / 5
|
||||
Nitrogen = 16.89f / 2,
|
||||
Phosphorus = 6.21f / 2,
|
||||
Potassium = 5.21f / 2
|
||||
};
|
||||
|
||||
FertilizerType[3] = new Fertilizer
|
||||
{
|
||||
ID = 2,
|
||||
Name = "17-17-17",
|
||||
Nitrogen = 14.92f / 5,
|
||||
Phosphorus = 14.42f / 5,
|
||||
Potassium = 3.0f / 5
|
||||
Nitrogen = 14.92f / 2,
|
||||
Phosphorus = 14.42f / 2,
|
||||
Potassium = 3.0f / 2
|
||||
};
|
||||
|
||||
FertilizerType[4] = new Fertilizer
|
||||
{
|
||||
ID = 3,
|
||||
Name = "20-20",
|
||||
Nitrogen = 15.39f / 5,
|
||||
Phosphorus = 15.21f / 5,
|
||||
Potassium = 9.5f / 5
|
||||
Nitrogen = 15.39f / 2,
|
||||
Phosphorus = 15.21f / 2,
|
||||
Potassium = 9.5f / 2
|
||||
};
|
||||
|
||||
FertilizerType[5] = new Fertilizer
|
||||
{
|
||||
ID = 4,
|
||||
Name = "28-28",
|
||||
Nitrogen = 9.67f / 5,
|
||||
Phosphorus = 10.47f / 5,
|
||||
Potassium = 9.5f / 5
|
||||
Nitrogen = 9.67f / 2,
|
||||
Phosphorus = 10.47f / 2,
|
||||
Potassium = 9.5f / 2
|
||||
};
|
||||
|
||||
FertilizerType[6] = new Fertilizer
|
||||
{
|
||||
ID = 5,
|
||||
Name = "DAP",
|
||||
Nitrogen = 14.52f / 5,
|
||||
Phosphorus = 1.77f / 5,
|
||||
Potassium = 9.5f / 5
|
||||
Nitrogen = 14.52f / 2,
|
||||
Phosphorus = 1.77f / 2,
|
||||
Potassium = 9.5f / 2
|
||||
};
|
||||
|
||||
FertilizerType[7] = new Fertilizer
|
||||
{
|
||||
ID = 6,
|
||||
Name = "Urea",
|
||||
Nitrogen = 1.81f / 5,
|
||||
Phosphorus = 21.0f / 5,
|
||||
Potassium = 9.5f / 5
|
||||
Nitrogen = 1.81f / 2,
|
||||
Phosphorus = 21.0f / 2,
|
||||
Potassium = 9.5f / 2
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
class Cargo
|
||||
{
|
||||
private Items[,] items = new Items[2, 351];
|
||||
private Items[,] items = new Items[2, 281];
|
||||
private int[] Count = new int[2];
|
||||
|
||||
|
||||
|
@ -11,11 +11,12 @@ using Microsoft.Xna.Framework.Input;
|
||||
class Inventory
|
||||
{
|
||||
private int Weight = 0;
|
||||
private int maxWeight = 350;
|
||||
private int maxWeight = 280;
|
||||
private int[] totalHarvested = new int[11];
|
||||
private int[] totalFertilizerUsed = new int[8];
|
||||
private Cargo cargo = new Cargo();
|
||||
private Cargo itemStorage = new Cargo();
|
||||
private int Refills = 0;
|
||||
|
||||
// Item list by index:
|
||||
// ---------------------------------------
|
||||
@ -128,18 +129,64 @@ class Inventory
|
||||
|
||||
for (int i = 0; i <= 10; i++)
|
||||
while (useItem(i, 1, true)) ;
|
||||
|
||||
}
|
||||
|
||||
public void fillWithFertilizer()
|
||||
{
|
||||
int i = 0;
|
||||
while (getWeight() < getMaxWeight())
|
||||
Refills++;
|
||||
int fert_amount = 7;
|
||||
float weightPerFertilizer = maxWeight / fert_amount;
|
||||
float min = weightPerFertilizer / 10;
|
||||
float max = (2 * weightPerFertilizer) - min;
|
||||
float expectedUse = Refills * weightPerFertilizer;
|
||||
|
||||
double[] useFactor = new double[fert_amount];
|
||||
for (int i = 0; i < fert_amount; i++)
|
||||
{
|
||||
if (i > 6)
|
||||
i = 0;
|
||||
addItem(i, 0);
|
||||
i++;
|
||||
if (Refills <= 1)
|
||||
useFactor[i] = weightPerFertilizer;
|
||||
else
|
||||
if (totalFertilizerUsed[i] / expectedUse + 0.85f > 1.0f)
|
||||
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 0.6f + Math.Min(Refills / 6.0f, 1.0f)) * weightPerFertilizer);
|
||||
else
|
||||
useFactor[i] = Math.Round(Math.Pow((totalFertilizerUsed[i] / expectedUse) + 0.50f, 1.0f + Math.Min(Refills / 6.0f, 1.8f)) * weightPerFertilizer);
|
||||
if (useFactor[i] < min)
|
||||
useFactor[i] = min;
|
||||
else if (useFactor[i] > max)
|
||||
useFactor[i] = max;
|
||||
}
|
||||
int j = 0;
|
||||
bool change = false;
|
||||
while (getWeight() < getMaxWeight() - fert_amount)
|
||||
{
|
||||
if (useFactor[j] > 0)
|
||||
{
|
||||
addItem(j, 0);
|
||||
useFactor[j]--;
|
||||
change = true;
|
||||
}
|
||||
j++;
|
||||
if (j >= fert_amount)
|
||||
{
|
||||
if (!change)
|
||||
break;
|
||||
else
|
||||
{
|
||||
j = 0;
|
||||
change = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int m = 0;
|
||||
while (getWeight() < getMaxWeight()- fert_amount)
|
||||
{
|
||||
if (m > 6)
|
||||
m = 0;
|
||||
addItem(m, 0);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
public bool isMissingFertilizer()
|
||||
@ -159,16 +206,16 @@ class Inventory
|
||||
spriteBatch.DrawString(Bold, "Harvested:", new Vector2(600, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||
for (int i = 0; i < 11; i++) //Print Crops
|
||||
{
|
||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, totalHarvested[i].ToString(), new Vector2(620, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 1) + " " + itemStorage.getItemByIndex(i, 1).getItemType(), new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, totalHarvested[i].ToString(), new Vector2(620, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
||||
}
|
||||
|
||||
spriteBatch.DrawString(Bold, "Fertilizers: ", new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||
spriteBatch.DrawString(Bold, "Used ", new Vector2(830, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
|
||||
for (int i = 0; i < 7; i++) //Print Fertilizers
|
||||
{
|
||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, totalFertilizerUsed[i].ToString(), new Vector2(835, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.DarkBlue);
|
||||
spriteBatch.DrawString(Bold, cargo.getCount(i, 0) + " " + itemStorage.getItemByIndex(i, 0).getItemType(), new Vector2(700, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
||||
spriteBatch.DrawString(Bold, totalFertilizerUsed[i].ToString(), new Vector2(835, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 20 * i + 22), Color.Teal);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,11 +6,10 @@ class Tractor
|
||||
{
|
||||
private int Spacing, sizeTile, Speed = 1;
|
||||
private float tractorSpeed = 1;
|
||||
private Vector2 Position, TargetPosition, Size, housePos, oldDeltaPosition, DeltaPosition;
|
||||
private Vector2 Position, TargetPosition, Size, housePos, DeltaPosition;
|
||||
private Path path = new Path();
|
||||
private SmartTractor smartTractor = new SmartTractor();
|
||||
private HandleRotation handleRotation = new HandleRotation();
|
||||
private int WaitFrame = 30;
|
||||
private int j;
|
||||
|
||||
|
||||
@ -22,8 +21,7 @@ class Tractor
|
||||
Size = input.getSize();
|
||||
updatePosition(input.getSize(), Status);
|
||||
housePos = newHousePos;
|
||||
smartTractor.UpdateCrops(Speed);
|
||||
|
||||
smartTractor.UpdateCrops(Speed, Time);
|
||||
}
|
||||
|
||||
public void init(Rectangle house, Input input)
|
||||
|
@ -54,11 +54,16 @@ class AI
|
||||
int testsize = 2;
|
||||
Path newTarget;
|
||||
Nodes nodes;
|
||||
Random random = new Random();
|
||||
|
||||
if (astar.GetAdjacentNodes(tractorPos).Count == 0)
|
||||
nodes = new Nodes(housePos);
|
||||
else
|
||||
nodes = astar.GetAdjacentNodes(tractorPos)[0];
|
||||
{
|
||||
List<Nodes> templist = astar.GetAdjacentNodes(tractorPos);
|
||||
nodes = templist[random.Next(0, templist.Count())];
|
||||
templist.Clear();
|
||||
}
|
||||
|
||||
if (tractorPos != housePos)
|
||||
if (inventory.getWeight() == inventory.getMaxWeight() || inventory.isMissingFertilizer())
|
||||
@ -168,7 +173,7 @@ class AI
|
||||
saturationScore = -100;
|
||||
}
|
||||
|
||||
return score + (-aproxDistance * 5) + statusScore + timerScore + saturationScore;
|
||||
return score + (-aproxDistance * 10) + statusScore + timerScore + saturationScore;
|
||||
}
|
||||
|
||||
private float norm(float min, float max, float val)
|
||||
|
@ -16,8 +16,9 @@ class SmartTractor
|
||||
//What to do next
|
||||
public Path returnChoice()
|
||||
{
|
||||
//System.Threading.ThreadStart tractorThread = new System.Threading.ThreadStart(farm.UpdatePreferedCrops);
|
||||
ai.update(farm, Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Target / (tileSize + Spacing), Rotation);
|
||||
farm.UpdatePreferedCrops(Size);
|
||||
//farm.UpdatePreferedCrops(Size);
|
||||
farm = ai.changeCropStatus();
|
||||
astar.update(farm.getCrops(), Size, tractorPos / (tileSize + Spacing), housePos / (tileSize + Spacing), Rotation);
|
||||
//getTargetPosition(ai.newTarget());
|
||||
@ -43,7 +44,6 @@ class SmartTractor
|
||||
tileSize = newTileSize;
|
||||
Spacing = newSpacing;
|
||||
Rotation = rotation;
|
||||
|
||||
}
|
||||
|
||||
public void init(Vector2 nHousePos)
|
||||
@ -51,6 +51,7 @@ class SmartTractor
|
||||
ai.init();
|
||||
housePos = nHousePos;
|
||||
farm.init(new Vector2(100, (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height / tileSize) - 125 / tileSize), housePos / (tileSize + Spacing));
|
||||
farm.UpdatePreferedCrops(Size);
|
||||
}
|
||||
|
||||
public void drawInventory(Input input, SpriteBatch spriteBatch, SpriteFont Bold, Cargo itemStorageDefined)
|
||||
@ -73,12 +74,13 @@ class SmartTractor
|
||||
farm.setNewHousePos(pos, newState);
|
||||
}
|
||||
|
||||
public void UpdateCrops(int Speed)
|
||||
public void UpdateCrops(int Speed, DayNightCycle nTime)
|
||||
{
|
||||
for (int i = 0; i < Speed; i++)
|
||||
{
|
||||
farm.updateFarm(Size);
|
||||
}
|
||||
farm.updateRainFall(Size, nTime);
|
||||
}
|
||||
|
||||
public Inventory getInventory()
|
||||
|
103
Joels Individual Report.md
Normal file
@ -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<ModelInput>(
|
||||
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.
|