Compare commits

...

79 Commits

Author SHA1 Message Date
BOTLester
48da4d4736 doc updates 2020-06-15 11:47:47 +02:00
BOTLester
8efb2d2d38 doc update 2020-06-15 11:45:38 +02:00
BOTLester
5dd6cd0020 docs 2020-06-15 11:37:24 +02:00
BOTLester
df77db10af docs 2020-06-15 11:35:38 +02:00
BOTLester
c1ef96716f doc updates 2020-06-15 11:34:11 +02:00
BOTLester
7211266f90 doc updates 2020-06-15 11:29:37 +02:00
BOTLester
43001006b8 final project report 2020-06-15 11:25:16 +02:00
BOTLester
48c90afe77 Window fixes 2020-06-15 09:52:17 +02:00
BOTLester
412a0969f0 Dynamic max window size 2020-06-15 02:51:44 +02:00
BOTLester
72a7a8aab3 Proper files paths for debug only 2020-06-15 01:45:16 +02:00
BOTLester
9e07e0f6bd Fixes and fixes 2020-06-15 00:59:39 +02:00
BOTLester
ad92969137 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-06-14 18:02:02 +02:00
BOTLester
2e96d5a2d5 fixes 2020-06-14 18:01:51 +02:00
Joel
cb5a4ea733 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-25 13:13:25 +02:00
Joel
b6078e14ac fixed the croptype change and runs the ML for those that change in the middle of the day with no lag 2020-05-25 13:13:11 +02:00
0d4c1a0276 Upload files to '' 2020-05-25 09:57:22 +00:00
3b733f9d20 Upload files to '' 2020-05-25 09:57:11 +00:00
ef1c8c4386 Delete 'Example.png' 2020-05-25 09:52:19 +00:00
bf86c760b1 Delete 'Joels Individual Report.md' 2020-05-25 09:52:03 +00:00
5a6d7ecb48 Upload files to '' 2020-05-25 09:50:02 +00:00
49c41e3594 Delete 'Joels Individual Report.md' 2020-05-25 09:49:50 +00:00
1bbd343e74 Upload files to '' 2020-05-25 09:48:22 +00:00
d19c3cbc41 Delete 'Joels Individual Report.md' 2020-05-25 09:48:13 +00:00
9f57f7b00c Upload files to '' 2020-05-25 09:46:32 +00:00
cdc23ff3ed Delete 'Joel Individual Report.md' 2020-05-25 09:46:23 +00:00
3114994c8b Upload files to '' 2020-05-25 09:41:11 +00:00
daf7810dac Upload files to '' 2020-05-25 09:36:34 +00:00
670acee8f2 Delete 'Game1/Joel Individual Report.docx' 2020-05-25 09:30:51 +00:00
d8246cce37 Upload files to 'Game1' 2020-05-25 09:30:24 +00:00
Joel
631ad7c12f Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-25 11:08:14 +02:00
Joel
8b115ec1f5 fixed everything 2020-05-25 11:07:58 +02:00
Joel
090a612660 asd 2020-05-25 10:59:17 +02:00
BOTLester
561287f99e merge 2020-05-25 00:05:11 +02:00
BOTLester
0b7ff8a949 fixes 2020-05-25 00:03:32 +02:00
Joel
c89fee6b05 asd 2020-05-25 00:03:26 +02:00
Joel
8ab1d77d9c asd 2020-05-24 23:10:51 +02:00
Joel
94c2792ef3 asd 2020-05-24 22:24:32 +02:00
Joel
5e9c9f503d asd 2020-05-24 22:22:09 +02:00
BOTLester
e406823e47 ml implement 2020-05-24 22:21:49 +02:00
BOTLester
6bb5073048 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-24 21:22:50 +02:00
BOTLester
fe04a5cd07 enigne 2020-05-24 21:22:47 +02:00
Joel
10e58f984f Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-24 21:22:26 +02:00
Joel
14e0e92f9b zxdfzdf 2020-05-24 21:22:17 +02:00
BOTLester
c858261c89 merge 2020-05-24 21:02:46 +02:00
BOTLester
cfbe80cb25 ML update 2020-05-24 21:00:54 +02:00
Joel
5e907deca7 asd 2020-05-24 21:00:24 +02:00
BOTLester
0dfef73667 MERGIN 2020-05-24 18:50:47 +02:00
BOTLester
585522b4df changes 2020-05-24 18:50:01 +02:00
Joel
50fd54ee3b asd 2020-05-24 18:49:23 +02:00
Joel
0a31c36c93 asd 2020-05-24 17:08:41 +02:00
Joel
f63bdcee77 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-24 16:51:40 +02:00
Joel
eb99fd3f02 gtyhsy 2020-05-24 16:51:29 +02:00
BOTLester
5a208e116f merge 2020-05-24 16:27:28 +02:00
BOTLester
8b84387c81 asdasd 2020-05-24 16:26:28 +02:00
Joel
64aaef69dd asd 2020-05-24 16:26:04 +02:00
Joel
2e48e49239 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-24 13:39:32 +02:00
Joel
46d27ab057 asd 2020-05-24 13:36:31 +02:00
BOTLester
38df90d9b5 merge 2020-05-24 13:27:09 +02:00
BOTLester
ec0819a337 lol 2020-05-24 13:25:46 +02:00
Joel
700979aded asd 2020-05-24 13:24:15 +02:00
Joel
9b99e0e710 added clouds 2020-05-24 13:21:17 +02:00
BOTLester
848cd6598a ml model created 2020-05-24 01:57:27 +02:00
Joel
444b5b0585 Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-23 20:55:55 +02:00
Joel
ba557d98f6 asd 2020-05-23 20:55:45 +02:00
BOTLester
57a9076771 rainfall noisemap 2020-05-23 20:55:38 +02:00
BOTLester
4a786a166e Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML 2020-05-23 20:39:08 +02:00
BOTLester
2a7c06fbd2 ML 2020-05-23 20:39:05 +02:00
Joel
32370470b5 yolo 2020-05-23 20:37:11 +02:00
Joel
710cd8581e asd 2020-05-23 14:13:31 +02:00
Joel
a656d768f6 Merge branch 'dev' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into dev 2020-05-23 13:57:59 +02:00
Joel
037f15f2e4 joined textures 2020-05-23 13:54:47 +02:00
BOTLester
7a520ab7b4 updated connected textures 2020-05-17 01:37:16 +02:00
BOTLester
122f957673 updated contect file 2020-05-12 16:40:45 +02:00
BOTLester
40996b3cdf Merging Oskar into dev 2020-05-12 16:37:53 +02:00
BOTLester
93802f3331 small adjustments 2020-05-11 01:54:47 +02:00
BOTLester
14490daf9f new UI wip 2020-05-11 01:48:10 +02:00
BOTLester
5293312938 Merge branch 'Oskar-ML' into dev 2020-05-11 01:47:24 +02:00
BOTLester
70be7e0151 PerlinNoise map generator 2020-05-11 01:16:01 +02:00
BOTLester
8c976c4beb updating dev branch 2020-05-11 00:29:09 +02:00
49 changed files with 2098765 additions and 192 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
Example.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 KiB

38
Final_evaluation.md Normal file
View 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.bnp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
Game1/Content/Cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
Game1/Content/Clouds Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
Game1/Content/Clouds.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

View File

@ -37,6 +37,18 @@
/processorParam:TextureFormat=Color
/build:BerriesIcon.png
#begin Bottom.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:Bottom.png
#begin CarronIcon.png
/importer:TextureImporter
/processor:TextureProcessor
@ -49,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
@ -104,6 +140,18 @@
/processorParam:TextureFormat=Color
/build:house.png
#begin Left.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:Left.png
#begin MaizeIcon.png
/importer:TextureImporter
/processor:TextureProcessor
@ -188,18 +236,6 @@
/processorParam:TextureFormat=Color
/build:Plantable.png
#begin Planted.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:Planted.png
#begin ProgressionBar.png
/importer:TextureImporter
/processor:TextureProcessor
@ -236,6 +272,30 @@
/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
/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:Right.png
#begin SeedOilIcon.png
/importer:TextureImporter
/processor:TextureProcessor
@ -296,6 +356,18 @@
/processorParam:TextureFormat=Color
/build:TobaccoIcon.png
#begin Top.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:Top.png
#begin Tractor.png
/importer:TextureImporter
/processor:TextureProcessor
@ -332,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

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Binary file not shown.

1048576
Game1/Content/ML/Rainfall.csv Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
Mean Absolute Error: 0.0108015636096701
Mean Squared Error: 0.0434908452113952
R Squared: 0.702723944791744

View File

@ -0,0 +1,2 @@
Mean Absolute Error: 187.060835104336
R Squared: 0.913526230109177

BIN
Game1/Content/Rainfall.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

BIN
Game1/Content/Rainfall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
Game1/Content/rain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -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
{
@ -15,11 +16,14 @@ namespace Game1
SpriteBatch spriteBatch;
SpriteFont Bold;
private Texture2D[] tile = new Texture2D[5];
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();
@ -42,6 +46,10 @@ namespace Game1
MouseState state;
private int cloudAnimationSpeed = 3;
private int cloudFrame = 0;
private int cloudSprite;
public Game1()
{
@ -68,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
@ -85,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();
}
@ -102,8 +115,15 @@ namespace Game1
tile[2] = Content.Load<Texture2D>("Plantable");
tile[3] = Content.Load<Texture2D>("Crop");
tileConnected[0] = Content.Load<Texture2D>("Left");
tileConnected[1] = Content.Load<Texture2D>("Top");
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");
@ -153,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);
}
@ -165,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);
@ -177,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);
}
@ -233,11 +262,38 @@ 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)
{
if (tractorUnit.getFarm().getCrop(i - 1, j).getStatus() == 2 || tractorUnit.getFarm().getCrop(i - 1, j).getStatus() == 3)
{
spriteBatch.Draw(tileConnected[0], tilePos, Time.GetTimeOfDay());
}
}
if (j > 0)
{
if (tractorUnit.getFarm().getCrop(i, j - 1).getStatus() == 2 || tractorUnit.getFarm().getCrop(i, j - 1).getStatus() == 3)
{
spriteBatch.Draw(tileConnected[1], tilePos, Time.GetTimeOfDay());
}
}
if (i < input.getSize().X)
{
if (tractorUnit.getFarm().getCrop(i + 1, j).getStatus() == 2 || tractorUnit.getFarm().getCrop(i + 1, j).getStatus() == 3)
{
spriteBatch.Draw(tileConnected[2], tilePos, Time.GetTimeOfDay());
}
}
if (j < input.getSize().Y)
{
if (tractorUnit.getFarm().getCrop(i, j + 1).getStatus() == 2 || tractorUnit.getFarm().getCrop(i, j + 1).getStatus() == 3)
{
spriteBatch.Draw(tileConnected[3], tilePos, Time.GetTimeOfDay());
}
}
if (tilePos.Intersects(mousePosition))
{
spriteBatch.Draw(tile[tractorUnit.getFarm().getCrop(i, j).getStatus()], tilePos, Color.FromNonPremultiplied(0, 0, 20, 40));
@ -272,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);
}
}

View File

@ -87,8 +87,15 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sources\Crops\CropType.cs" />
<Compile Include="Sources\Crops\CropTypesHolder.cs" />
<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" />
@ -129,6 +136,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Numerics" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
@ -159,9 +167,15 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="LibNoise">
<Version>0.2.0</Version>
</PackageReference>
<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>
@ -183,6 +197,9 @@
<PackageReference Include="System.Collections.Immutable">
<Version>1.7.0</Version>
</PackageReference>
<PackageReference Include="System.Drawing.Common">
<Version>4.7.0</Version>
</PackageReference>
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>

View File

@ -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;
}

View File

@ -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()

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -1,4 +1,6 @@
using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -13,11 +15,25 @@ class Farm
private CropTypesHolder PresetCrops = new CropTypesHolder();
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
public void init(Vector2 Size, Vector2 housepos)
{
whiteNoise = PerlinNoise.GenerateWhiteNoise(100, 100);
perlinNoise = PerlinNoise.GeneratePerlinNoise(whiteNoise, 1);
PresetCrops.init();
r = new Random();
crops = new Crops[100, 100];
@ -26,19 +42,18 @@ class Farm
{
for (int j = 0; j < 99; j++)
{
int x = r.Next(0, 3);
if (x == 0)
{
x = r.Next(0, 2);
}
if (x == 2)
{
x = r.Next(1, 3);
}
int x = 0;
if (perlinNoise[i][j] > 0 && perlinNoise[i][j] < 0.15f)
x = 0;
else if (perlinNoise[i][j] >= 0.15f && perlinNoise[i][j] < 0.8f)
x = 1;
else if (perlinNoise[i][j] >= 0.8f)
x = 2;
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();
@ -56,7 +71,6 @@ class Farm
{
if (!astar.isReachable(crops, new Vector2((int)i, (int)j), housepos))
{
//crops[i, j].setStatus(1);
dirtCount--;
}
}
@ -64,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)
@ -75,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.
@ -115,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);
@ -122,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)
@ -136,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));
@ -147,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
{
@ -162,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;
}
}
}
}

View File

@ -0,0 +1,333 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
class PerlinNoise
{
#region Feilds
static Random random = new Random();
#endregion
#region Reusable Functions
public static float[][] GenerateWhiteNoise(int width, int height)
{
float[][] noise = GetEmptyArray<float>(width, height);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
noise[i][j] = (float)random.NextDouble() % 1;
}
}
return noise;
}
public static float Interpolate(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
public static Color Interpolate(Color col0, Color col1, float alpha)
{
float beta = 1 - alpha;
return Color.FromArgb(
255,
(int)(col0.R * alpha + col1.R * beta),
(int)(col0.G * alpha + col1.G * beta),
(int)(col0.B * alpha + col1.B * beta));
}
public static Color GetColor(Color gradientStart, Color gradientEnd, float t)
{
float u = 1 - t;
Color color = Color.FromArgb(
255,
(int)(gradientStart.R * u + gradientEnd.R * t),
(int)(gradientStart.G * u + gradientEnd.G * t),
(int)(gradientStart.B * u + gradientEnd.B * t));
return color;
}
public static Color[][] MapGradient(Color gradientStart, Color gradientEnd, float[][] perlinNoise)
{
int width = perlinNoise.Length;
int height = perlinNoise[0].Length;
Color[][] image = GetEmptyArray<Color>(width, height); //an array of colours
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
image[i][j] = GetColor(gradientStart, gradientEnd, perlinNoise[i][j]);
}
}
return image;
}
public static T[][] GetEmptyArray<T>(int width, int height)
{
T[][] image = new T[width][];
for (int i = 0; i < width; i++)
{
image[i] = new T[height];
}
return image;
}
public static float[][] GenerateSmoothNoise(float[][] baseNoise, int octave)
{
int width = baseNoise.Length;
int height = baseNoise[0].Length;
float[][] smoothNoise = GetEmptyArray<float>(width, height);
int samplePeriod = 1 << octave; // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++)
{
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++)
{
//calculate the vertical sampling indices
int sample_j0 = (j / samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = Interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
public static float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
{
int width = baseNoise.Length;
int height = baseNoise[0].Length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = 0.7f;
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = GetEmptyArray<float>(width, height); //an array of floats initialised to 0
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalisation
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
public static float[][] GeneratePerlinNoise(int width, int height, int octaveCount)
{
float[][] baseNoise = GenerateWhiteNoise(width, height);
return GeneratePerlinNoise(baseNoise, octaveCount);
}
public static Color[][] MapToGrey(float[][] greyValues)
{
int width = greyValues.Length;
int height = greyValues[0].Length;
Color[][] image = GetEmptyArray<Color>(width, height);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
int grey = (int)(255 * greyValues[i][j]);
Color color = Color.FromArgb(255, grey, grey, grey);
image[i][j] = color;
}
}
return image;
}
public static void SaveImage(Color[][] image, string fileName)
{
int width = image.Length;
int height = image[0].Length;
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
bitmap.SetPixel(i, j, image[i][j]);
}
}
bitmap.Save(fileName);
}
public static Color[][] LoadImage(string fileName)
{
Bitmap bitmap = new Bitmap(fileName);
int width = bitmap.Width;
int height = bitmap.Height;
Color[][] image = GetEmptyArray<Color>(width, height);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
image[i][j] = bitmap.GetPixel(i, j);
}
}
return image;
}
public static Color[][] BlendImages(Color[][] image1, Color[][] image2, float[][] perlinNoise)
{
int width = image1.Length;
int height = image1[0].Length;
Color[][] image = GetEmptyArray<Color>(width, height); //an array of colours for the new image
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
image[i][j] = Interpolate(image1[i][j], image2[i][j], perlinNoise[i][j]);
}
}
return image;
}
public static void DemoGradientMap()
{
int width = 256;
int height = 256;
int octaveCount = 8;
Color gradientStart = Color.FromArgb(255, 0, 0);
Color gradientEnd = Color.FromArgb(255, 0, 255);
float[][] perlinNoise = GeneratePerlinNoise(width, height, octaveCount);
Color[][] perlinImage = MapGradient(gradientStart, gradientEnd, perlinNoise);
SaveImage(perlinImage, "perlin_noise.png");
}
public static float[][] AdjustLevels(float[][] image, float low, float high)
{
int width = image.Length;
int height = image[0].Length;
float[][] newImage = GetEmptyArray<float>(width, height);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
float col = image[i][j];
if (col <= low)
{
newImage[i][j] = 0;
}
else if (col >= high)
{
newImage[i][j] = 1;
}
else
{
newImage[i][j] = (col - low) / (high - low);
}
}
}
return newImage;
}
private static Color[][][] AnimateTransition(Color[][] image1, Color[][] image2, int frameCount)
{
Color[][][] animation = new Color[frameCount][][];
float low = 0;
float increment = 1.0f / frameCount;
float high = increment;
float[][] perlinNoise = AdjustLevels(
GeneratePerlinNoise(image1.Length, image1[0].Length, 9),
0.2f, 0.8f);
for (int i = 0; i < frameCount; i++)
{
AdjustLevels(perlinNoise, low, high);
float[][] blendMask = AdjustLevels(perlinNoise, low, high);
animation[i] = BlendImages(image1, image2, blendMask);
//SaveImage(animation[i], "blend_animation" + i + ".png");
SaveImage(MapToGrey(blendMask), "blend_mask" + i + ".png");
low = high;
high += increment;
}
return animation;
}
#endregion
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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/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";
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 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;
}
}
}
}

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}

View 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;
}
}
}

View 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;
}
}
}
}
}

View File

@ -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;
}

View File

@ -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
};
}

View File

@ -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];

View File

@ -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()
@ -156,19 +203,19 @@ class Inventory
{
spriteBatch.DrawString(Bold, "Crops: ", new Vector2(470, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
//spriteBatch.DrawString(Bold, "Harvested:", new Vector2(600, input.getSize().Y * (input.getTileSize() + input.getSpacing()) + 2), Color.DarkRed);
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);
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);
}

View File

@ -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)

View File

@ -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)

View File

@ -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
View 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 havent done anything to mitigate this but it doesnt 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.