Source code for timApp.gamification.generateMap

import json
from copy import deepcopy

from flask import Blueprint
from flask import request

from timApp.gamification import gamificationdata
from timApp.gamification.gamificationdata import GamificationException
from timApp.util.flask.requesthelper import RouteException
from timApp.util.flask.responsehelper import json_response

generateMap = Blueprint("generateMap", __name__, url_prefix="")


[docs]@generateMap.post("/generateMap") def generate_map(): # Configuring the data is here to make the map load lazier. try: coursedata = gamificationdata.gamify(request.get_json()) except GamificationException as e: raise RouteException(str(e)) # Get lectures from json lecturejson = coursedata["lectures"] # Get demos from json demojson = coursedata["demos"] # Get map mapname = select_map(len(lecturejson), len(demojson)) # Read map with open(mapname) as f: g_map = json.loads(f.read()) # Dict for properties added to every layer. properties = { "studentpoints": 0, # Points student got from this demo/lecture "maxpoints": 0, # Maximum points attainable from this demo/lecture "site": "", # Link to this demo/lecture "title": "", # Title of this demo/lecture } # Width of the map, needed for calculating tiles. mapwidth = g_map["width"] g_map["layers"] = add_properties(g_map["layers"], properties) # The number of demos and lectures in the map. demosinmap = 0 lecturesinmap = 0 # Replace all of the tables with dicts and get number of lectures and demos in map. for layer in g_map["layers"]: layer = replace_table_with_dict(layer) if layer["name"][0:1] == "l": lecturesinmap += 1 if layer["name"][0:1] == "d": demosinmap += 1 # Indexes for lectures and demos so correct information can be sent to layers in a loop. # Starts at -abs(len - number of demos/lectures) so that excess layers can be removed. lectureindex = -abs(len(lecturejson) - lecturesinmap) demoindex = -abs(len(demojson) - demosinmap) # Index for iterating over the layers. layerindex = 0 # Table of layers to be removed due to them not being needed. dellayers = [] # Add layers for buildings. for layer in g_map["layers"]: if layer["name"][0:1] == "l": # Attach properties and create buildings if there are still lectures to be added. if len(lecturejson) - 1 >= lectureindex >= 0: points = 1 maxpoints = 1 title = lecturejson[len(lecturejson) - lectureindex - 1]["name"] lectureproperties = { "studentpoints": 0, # Points student got from this demo/lecture "maxpoints": 0, # Maximum points attainable from this demo/lecture "site": lecturejson[len(lecturejson) - lectureindex - 1][ "link" ], # Li$ "title": title, # Title of this demo/lecture } # Change the name of the layer so it doesnt get caught in the loop a$ layer["name"] = "L" + layer["name"][1:] layer["properties"] = lectureproperties g_map["layers"] = create_lecture_layers( g_map["layers"], layerindex, int(points), int(maxpoints), mapwidth, lectureproperties, ) # Delete layer if no more lectures need to be added. else: dellayers.append(layer) lectureindex += 1 if layer["name"][0:1] == "d": # Attach properties and create buildings if there are still demos to be added. if len(demojson) - 1 >= demoindex >= 0: points = demojson[len(demojson) - demoindex - 1]["gotPoints"] maxpoints = demojson[len(demojson) - demoindex - 1]["maxPoints"] demoproperties = { "studentpoints": points, # Points student got from this demo/lecture "maxpoints": maxpoints, # Maximum points attainable from this demo/lecture "site": demojson[len(demojson) - demoindex - 1][ "link" ], # Link to this demo/lecture "title": demojson[len(demojson) - demoindex - 1][ "name" ], # Title of this demo/lecture } # Change the name of the layer so it doesnt get caught in the loop again. layer["name"] = "D" + layer["name"][1:] layer["properties"] = demoproperties g_map["layers"] = create_demo_layers( g_map["layers"], layerindex, points, maxpoints, mapwidth, demoproperties, ) # If there is no need for the layer delete it. else: dellayers.append(layer) demoindex += 1 layerindex += 1 # If a layer has no data remove it. for layer in g_map["layers"]: if len(layer["data"]) == 0: dellayers.append(layer) # Remove unused layers. for dellayer in dellayers: g_map["layers"].remove(dellayer) # layers = create_lecture_layers(map['layers'],2,mapwidth) return json_response(g_map)
# Creates zero to three layers on top of a demo layer # layers are the layers which need to be appended with more layers # layerid is the id for the layer above which the layers need to be appended # layerdict is the dictionary for the layer above which the layers need to be added
[docs]def create_lecture_layers(layers, layerid, points, maxpoints, mapwidth, properties): # Lets not divide by zero. if maxpoints == 0: maxpoints = 1 if float(points / maxpoints) > 0: layers.insert(layerid + 1, deepcopy(layers[layerid])) layers[layerid + 1]["name"] += "b1" layers[layerid + 1]["data"] = make_build_blocks(layers[layerid + 1]["data"], 0) layers[layerid + 1]["properties"] = properties if float(points / maxpoints) > 0.5: layers.insert(layerid + 2, deepcopy(layers[layerid])) layers[layerid + 2]["name"] += "b2" layers[layerid + 2]["data"] = make_build_blocks(layers[layerid + 2]["data"], 3) layers[layerid + 2]["properties"] = properties # Delete unused keys, create offset for roof. deltable = [] if float(points / maxpoints) > 0: for key in layers[layerid + 2]["data"].keys(): deltable.append(key) if float(points / maxpoints) > 0.5: for key in deltable: layers[layerid + 2]["data"][str(int(key) - mapwidth)] = layers[layerid + 2][ "data" ][key] del layers[layerid + 2]["data"][key] return layers
# Creates zero to three layers on top of a demo layer # layers are the layers which need to be appended with more layers # layerid is the id for the layer above which the layers need to be appended # layerdict is the dictionary for the layer above which the layers need to be added # percentage is the percentage of points gotten from the demo.
[docs]def create_demo_layers(layers, layerid, points, maxpoints, mapwidth, properties): if maxpoints == 0 and points == 0: maxpoints = 1 points = 1 if maxpoints <= 0: maxpoints = 1 max_tiles = 12 totaltiles = max_tiles * points / maxpoints if totaltiles > max_tiles: totaltiles = max_tiles totaltiles = round(totaltiles) floors = totaltiles // 3 + 1 tiles = totaltiles % 3 # index used to track progress of loop floorindex = 0 while floorindex < floors: layers.insert(layerid + 1 + floorindex, deepcopy(layers[layerid])) layers[layerid + 1 + floorindex]["name"] = ( layers[layerid]["name"] + "b" + str(1 + floorindex) ) layers[layerid + 1 + floorindex]["data"] = make_build_blocks( layers[layerid + 1 + floorindex]["data"], floorindex ) layers[layerid + 1 + floorindex]["properties"] = properties if floorindex != 0: deltable = [] # Insert layers into the deletable table if they have no data in them for key in layers[layerid + 1 + floorindex]["data"].keys(): deltable.append(key) for key in deltable: layers[layerid + 1 + floorindex]["data"][ str(int(key) - mapwidth * floorindex) ] = layers[layerid + 1 + floorindex]["data"][key] del layers[layerid + 1 + floorindex]["data"][key] floorindex += 1 # Remove extra tiles if this is the last run of the loop. deltiles = 3 if floorindex == floors: while tiles < deltiles: # Delete keys starting with the latest so that the frames look better. for key in reversed(list(layers[layerid + floorindex]["data"].keys())): del layers[layerid + floorindex]["data"][key] deltiles -= 1 break return layers
# Makes buildblocks for tiles, dict is the dict to be modified, # floor defines the blocks to be added. 0 = ground floor, 1 = middle, 2 = middle, 3 = roof
[docs]def make_build_blocks(data, floor): if floor == 0: for key in data.keys(): data[key] = 23 if floor == 1 or floor == 2: for key in data.keys(): data[key] = 20 if floor == 3: for key in data.keys(): data[key] = 101 return data
# Select a map based on the number of lectures and demos.
[docs]def select_map(lectures, demos): map_file = "static/map_files/d" # If there are more than twice as many demos as there are lectures select map based on lectures if 2 * demos < lectures: if lectures % 2 == 0: map_file += str(int(lectures / 2)) + ".json" if lectures % 2 == 1: map_file += str(int(int(lectures / 2) + 1)) + ".json" # Otherwise select map based on demos. else: map_file += str(demos if demos > 0 else 1) + ".json" return map_file
# Add properties to every layer in the map. Properties dont contain anything of actual value at this point.
[docs]def add_properties(layers, properties): for layer in layers: layer["properties"] = properties return layers
# replaces data table of layer with a dict containing tile and image id.
[docs]def replace_table_with_dict(layer): toptiles = find_tiles(layer) # Dictionary the data will be replaced with. data = {} for tile in toptiles: # Dict is updated with line tile:image id data.update({"" + str(tile): layer["data"][tile]}) # Replace data with dict layer["data"] = data return layer
# This method returns a list of tiles in the given data.
[docs]def find_tiles(layer): data = layer["data"] # Table of the tiles ret = [] i = 0 for n in data: if n != 0: ret.append(i) i += 1 return ret