gaming
11 TopicsThe Gate Is the Product: Human-Verified Artifacts in a Foundry Multi-Agent Game
Part 2 of 5. In Part 1 the loop ended at a verification gate. This post is about why that gate is not a confirmation dialog - it is the core mechanic, the reliability story, and the thing that lets a reasoning-agent system be demoed live without praying. Most multi-agent demos gate on "did the model produce something." That is a vibe check. A reasoning-agent system that touches anything real needs a harder question: who is allowed to say this artifact is good enough - and can a human stop it? A model can create. A model must not be the thing that certifies its own creation. This post is a code walkthrough of how that rule is enforced. We build the three-layer scoring ladder from the bottom up - deterministic validators, a model rubric floored by them, and a human gate - then look at the parts that make it survive contact with real reasoning models: tolerant JSON parsing, capped self-check tools, a failure-degradation ladder, and four proof points that are tested on every run. Every snippet is from the shipped repo, and a file map at the end tells you where to read the rest. Three layers, one rule: no agent grades itself When a worker finishes a chapter, the artifact passes through three layers before it can become progress. Each layer has a different scorer, and only the last one - a human - can award XP. Layer Who scores Can it award XP? Mid-run tool calls Deterministic validators No - advisory to the model rubric_evaluate Foundry model judging weighted dimensions, floored by validators No CEO gate The human Yes - the only path to XP The order is the whole point. Deterministic validators set a floor the score can never fall below. The Foundry model's rubric judgement can move the score above that floor - reward genuine quality - but it can never talk the score below the facts the validators established. Then the work stops and waits for a person. Everything below is in the repo, so this post reads as a code walkthrough as much as an essay. The three layers live in three files: the validators in submission/tools/code_interpreter_wrappers.py , the rubric and floor in submission/agents/worker_factory.py , and the human gate that awards XP in submission/tools/server.py . Open them alongside this post. The thing being judged: what a worker actually returns Before you can score an artifact you have to agree on its shape. A worker does not return prose - it returns a typed JSON object whose keys the validators know how to read. A designer returns a landing page ( hero_headline , cta_text , url , features ); a strategist returns positioning ( target_audience , core_problem , value_proposition , primary_benefit ) and an org chart ( org_chart , okrs_q1 ); a marketer returns a financial plan ( gtm_channels , financial_plan ) and an email ( subject , body ). This contract is the hinge of the whole reliability story. Because the shape is fixed, the validator that reads it can be a dumb, fast, deterministic function - not a second model trying to interpret freeform text. In simulation mode the very same shapes are produced by _mock_artifact in worker_factory.py , which is why the gate behaves identically after a fresh clone with zero credentials: the artifact the validator reads looks the same whether a Foundry model wrote it or the simulator did. There is one wrinkle worth calling out, because it is where most "the validator says zero but the page looks fine" bugs come from: models are inconsistent about keys. One run returns hero_headline , another headline , another a nested hero.headline . Rather than make the validator guess, a small adapter - _landing_payload - coalesces those variants into the canonical shape before the validator ever sees them: # submission/agents/worker_factory.py - _landing_payload (excerpt) return { "hero_headline": page.get("hero_headline") or page.get("headline") or hero.get("headline") or artifact.get("headline") or "", "cta_text": page.get("cta_text") or cta.get("text") or artifact.get("cta") or "", # ... features, url ... } Normalising at the boundary keeps the validators pure: they assume one schema, and the messy job of mapping a model's many spellings onto that schema lives in one adapter, not smeared through every check. Layer 1: deterministic validators you could unit-test Layer 1 is a handful of pure functions in submission/tools/code_interpreter_wrappers.py . Each takes the artifact dict, runs structural checks, accumulates a 0-100 score, and returns (success, results) where results carries a per-check breakdown and human-readable feedback. Here is the landing-page validator, trimmed to its spine, because it is representative: # submission/tools/code_interpreter_wrappers.py def validate_landing_page(data): results = {"checks": {}, "score": 0, "feedback": []} if len(data.get("hero_headline", "").strip()) >= 15: results["checks"]["hero_headline_valid"] = True results["score"] += 30 cta = data.get("cta_text", "") if len(cta.strip()) >= 3: results["checks"]["cta_valid"] = True results["score"] += 20 # ... url format (+30) and a simulated http_status_200 (+20) ... success = results["score"] >= 70 return success, results There is no model anywhere in that function. A headline shorter than fifteen characters earns zero points and a line of feedback; a missing call to action earns zero points and a line of feedback. The thresholds are explicit and the points are explicit, so the score is reproducible to the digit - run it a thousand times, get the same number a thousand times. The other validators follow the same grammar, and each one encodes a small piece of domain judgement as code rather than as a prompt: validate_positioning requires four fields - target audience, core problem, value proposition, primary benefit - each non-trivial (more than ten characters). Four fields, twenty-five points each, pass at seventy-five. validate_org_chart wants a non-empty org chart that contains a Founder role, and OKRs where each objective carries at least two key results. A chart with no founder, or objectives with no measurable key results, simply does not score. validate_marketing_email checks a subject of real length, body copy past a hundred characters, and the literal presence of a call-to-action marker ( [CTA] , a link, "Sign up"). validate_financial_plan is the most opinionated, and the best illustration of the principle. It checks that the MRR ramp is monotonically increasing and that the breakeven month lands in a sane 1-24 range: # submission/tools/code_interpreter_wrappers.py is_monotonic = all(nums[i] <= nums[i + 1] for i in range(len(nums) - 1)) # ... be = fp.get("breakeven_month") if isinstance(be, (int, float)) and 1 <= be <= 24: results["checks"]["breakeven_sane"] = True results["score"] += 15 A model can write a beautiful narrative around a revenue plan that quietly shrinks in month four, or that breaks even in month ninety. A monotonicity check catches the first; a range check catches the second. Neither needs a second opinion from a language model - they are arithmetic. That is the whole thesis of Layer 1: anything you can state as a rule, state as a rule. One set of validators, two jobs The same pure functions do double duty, and that is deliberate. Through _score_artifact they compute the floor - the role's validators run, and the floor is the highest score any of them returns, plus a richness heuristic so an off-schema artifact never floors at a flat zero: Through _maf_tool_fns the same functions are wrapped as the mid-run FunctionTools we capped earlier. One implementation, one source of truth for "is this artifact structurally sound" - exposed both as the gate's floor and as the tool the model calls on its own draft. When you change a validator, the model's self-check and the gate's floor move together; they can never drift apart. The max is a deliberate choice, not a shortcut. A strategist artifact carries both an org chart and a positioning block; taking the best validator score means a strong org chart is not dragged down by a thin positioning section, while a worker that nails neither still cannot fake a floor. It is a forgiving floor for partial work and an honest one for empty work. Layer 2: rubric_evaluate, floored Layer 1 tells you whether an artifact is well-formed. It cannot tell you whether the positioning is sharp or the OKRs are ambitious. That nuance is what Layer 2 is for, and it is where a Foundry model finally gets to judge - inside a cage. rubric_evaluate in submission/agents/worker_factory.py scores the artifact on four weighted dimensions: # submission/agents/worker_factory.py RUBRIC_DIMENSIONS = [ ("Relevance to goal", 30), ("Completeness", 25), ("Actionability", 25), ("Clarity & structure", 20), ] In live mode it asks the narrator deployment - the same Foundry model that powers the Master Narrator - to score each dimension 0-100 and return strict JSON, with a generous token budget because reasoning models spend tokens thinking before they answer: # submission/agents/worker_factory.py - inside rubric_evaluate resp = create_chat_completion( deployment, [ {"role": "system", "content": ( "You are a strict rubric evaluator for business artifacts. " "Score the artifact 0-100 on each dimension: " + dims_spec + ". " "Return ONLY JSON: {dimensions: [...], verdict: one sentence}.")}, {"role": "user", "content": ( f"Venture brief: {brief[:600]}\nStage goal: {stage.goal}\n" f"Artifact JSON:\n{json.dumps(artifact)[:4000]}")}, ], max_completion_tokens=2500, ) parsed = _extract_json(resp.choices[0].message.content or "") or {} The prompt names the dimensions and their weights inline (via dims_spec ), demands JSON only, and caps the artifact at 4000 characters so a sprawling object cannot blow the context window. The response still goes through the same _extract_json we will meet in a moment - because even a "return ONLY JSON" instruction is a request, not a guarantee. Then it does something important: it does not trust the model's structure. It re-anchors the model's answer to our own spec - our dimension names, our weights - and keeps only the model's scores: # submission/agents/worker_factory.py - inside rubric_evaluate by_name = {str(d.get("name", "")).strip().lower(): d for d in dims if isinstance(d, dict)} dimensions = [] for name, weight in RUBRIC_DIMENSIONS: d = by_name.get(name.lower(), {}) dimensions.append({ "name": name, "weight": weight, "score": max(0, min(100, int(d.get("score", floor)))), "note": str(d.get("note", ""))[:120], }) This is a small piece of defensive engineering with a large payoff. A model asked for four dimensions might return three, invent a fifth, or quietly reweight them so its favourite one dominates. By looping over our RUBRIC_DIMENSIONS and pulling scores by name - defaulting any missing dimension to the validator floor, clamping every score to 0-100 - the weighting stays ours. The model colours inside lines it did not draw. Then the two layers meet in one line: rubric["final"] = max(floor, rubric["weighted_total"]) . The final score is one line of math That single line - final = max(floor, weighted_total) - is the entire trust model, and it is worth seeing as a picture, because it is only three numbers: If the artifact is structurally sound, the floor is high and the model can only push the score higher by recognising genuine quality. If the model is having a bad day and lowballs a perfectly valid artifact, the floor protects it. The model's judgement is additive, never subtractive. You get the nuance of a model evaluator with the safety of a deterministic one - and you can explain, to the point, exactly why any score is what it is. Why a deterministic floor, not just a model judge This is the single most important reliability decision, and it is the same principle Lee Stott states in his Hybrid AI Agents in Python post: code the rules, and let the LLM judge only what is left. As he puts it about privacy controls - if your check depends on an LLM correctly classifying every input, you do not have a control, you have a probability distribution. We apply the identical principle to artifact quality. The validators are boring on purpose. Does the landing page have a headline, a CTA, a hero section? Is the marketing email parseable? Do the URLs resolve? Does the org chart have a Founder and key results on every objective? These are structural facts, checked in code, that no amount of confident prose can override. A model that has just written a landing page is the worst-placed party to certify it - so it is graded by something it cannot sweet-talk. In the game you can watch this happen. A worker delivers, and the report names the score and the verdict in plain language: the deterministic validator scored it 100 of 100 - it passes the gate and the company graph grows. A worker delivers a positioning brief, an org chart, and Q1 OKRs; the deterministic validator scores it 100/100 and it passes the gate Reasoning models and strict JSON do not mix There is a sharp edge hiding in Layer 2 that bites everyone who puts a reasoning model behind a JSON contract: the model wraps its answer in think-blocks, prepends a sentence of preamble, or fences the JSON in markdown - and json.loads throws. If your rubric evaluator crashes on a stray backtick, your "deterministic floor" was never deterministic; it was one parse error away from no score at all. So every agent that must read JSON out of a model goes through a tolerant extractor. The same _extract_json shape appears in worker_factory.py , org_designer.py , founder_analyst.py , and world_designer.py - kept local to each module on purpose, so every agent is self-contained. It tries, in order: strip a Markdown code fence; parse the whole string; parse the substring from the first { to the last } ; then scan character by character and let json.JSONDecoder().raw_decode find the first valid object: # submission/agents/worker_factory.py decoder = json.JSONDecoder() for index, char in enumerate(text): if char != "{": continue try: parsed, _ = decoder.raw_decode(text[index:]) return parsed if isinstance(parsed, dict) else None except Exception: continue return None When all four strategies fail, the function returns None and the caller falls through to _rubric_from_floor - the deterministic rubric derived from the validator floor. There is no path where a malformed model response yields no score; the floor is always there to catch it. Tolerant parsing plus a deterministic fallback is what lets you run reasoning models inside a scoring loop without the loop ever dropping a frame. The receipts panel: scoring you can audit, not trust Every worker exposes a receipts panel - the artifact's scoring proof, broken out so a skeptic can audit it instead of taking the number on faith. Status, the model that ran, token usage, estimated call cost, latency, and how many tool calls the worker made out of its capped budget. The receipts panel: status, model, tokens, est. call cost, latency, and tool-call count for a worker run This is the runtime equivalent of carrying a correlation ID through every path. Four proof points are emitted on every invocation, in live mode and simulation mode alike, and they are written straight into the STAGE_EXECUTED replay event in submission/tools/server.py : # submission/tools/server.py - the STAGE_EXECUTED event payload "iq_hits": invocation.iq_sources, "memory_injected": invocation.maf_memory, "tools_called": invocation.maf_tools_called, "inference_usage": {"client": invocation.maf_client or "openai-direct", "fallback_reason": invocation.maf_fallback_reason, "tokens_in": invocation.tokens_in, "tokens_out": invocation.tokens_out, "reasoning_tokens": invocation.reasoning_tokens}, "rubric": stage.rubric, iq_hits - which Foundry IQ sources grounded the work memory_injected - whether the CEO's prior decisions entered the brief tools_called - which deterministic tools the worker actually ran inference_usage - the client used, tokens in and out, and reasoning tokens These are not decoration; they are enforced. submission/tools/demo_smoke_test.py walks every invocation in a simulated run and fails the build if any proof point is absent: # submission/tools/demo_smoke_test.py _require(bool(p.get("iq_hits")), f"{cid}: iq_hits empty - IQ recall not evidenced") _require(bool(p.get("memory_injected")), f"{cid}: memory_injected empty") _require("tools_called" in p, f"{cid}: tools_called missing") usage = p.get("inference_usage") or {} _require(bool(usage.get("client")), f"{cid}: inference_usage.client missing") When a judge asks "did the agent actually do anything, or is this theatre?", the answer is a panel you open, not a sentence you say - backed by a test that would have gone red if the panel were empty. Tools the model can call - but capped On the Agent Framework path the validators are not just a post-hoc gate; they are @tool FunctionTools the worker can call mid-run to test its own draft. That is good - a model that can check itself produces better artifacts. But an unbounded self-check is a failure mode: a model in a tight spot will call the same validator in a loop and burn your budget. So in submission/agents/maf_runtime.py every tool is wrapped with a hard cap, and every call leaves a receipt carrying its arguments, result, and latency: # submission/agents/maf_runtime.py @tool(name=tool_name, description=f"Run the deterministic '{tool_name}' check on a draft artifact " "(pass the artifact as a JSON string). Call at most once.", max_invocations=2) def _t(artifact_json: str) -> str: meta["maf_tools_called"].append(tool_name) receipt = {"tool": tool_name, "source": "maf-midrun", "args": {}, "result": "", "ms": 0.0} meta["maf_tool_trace"].append(receipt) t0 = time.perf_counter() # ... parse artifact, run fn(payload), summarise ... receipt["result"] = f"score={score} checks {passed}/{len(checks)}" receipt["ms"] = round((time.perf_counter() - t0) * 1000, 1) The model may check its draft twice. It may not certify it. max_invocations=2 is enforced by the runtime, not by a polite instruction the model can choose to ignore. And because every call appends to maf_tool_trace , the receipts panel can show you the exact tool, the artifact keys it inspected, the score it got back, and how many milliseconds it took. The certification is the human's, at the gate; the tool is only ever advisory. The same proof in simulation mode Forkability is a rubric criterion, so the gate cannot depend on Azure. After a git clone with zero credentials the system runs in simulation mode - and crucially, the same three layers run. _mock_artifact produces a well-formed artifact, the real validators score it, and rubric_evaluate falls through to _rubric_from_floor - a deterministic breakdown anchored to the validator score with a tiny, fixed spread: # submission/agents/worker_factory.py def _rubric_from_floor(floor): spread = [5, 0, -5, 0] # mild, deterministic variation around the floor dimensions = [ {"name": name, "weight": weight, "score": max(0, min(100, floor + spread[i])), "note": "derived from deterministic validators"} for i, (name, weight) in enumerate(RUBRIC_DIMENSIONS) ] # ... returns the same shape rubric_evaluate returns in live mode ... The four proof points are emitted on this path too. inference_usage.client reads "openai-direct" or a simulation marker instead of FoundryChatClient , but the field is present - which is exactly why demo_smoke_test.py passes offline. The rule we hold to: if your simulation mode does not emit the same evidence as live, you are testing a different program than the one you ship. When the model fails the artifact A model in a scoring loop will, eventually, hand you garbage: JSON truncated because it hit the token ceiling, prose where you asked for an object, or an outright exception from the endpoint. The gate cannot ship a blank stage, so the worker degrades down a fixed ladder rather than failing open. First, a weak Agent Framework run falls through. After the MAF path returns, the artifact is scored; if it is unparseable or the floor is below 40, the code raises and the worker retries on the direct OpenAI-compatible path. A half-formed artifact never reaches the gate: # submission/agents/worker_factory.py artifact = _extract_json(content) floor = _score_artifact(role, artifact) if not artifact or floor < 40: raise ValueError(f"MAF artifact too weak (floor={floor})") Second, an empty live artifact degrades to the deterministic mock. If even the direct call returns nothing parseable, the worker substitutes _mock_artifact , records a maf_fallback_reason , and the validators score the mock - so every stage still produces a real, gradeable artifact instead of a blank one. This is the same "simulation fallback for everything" law the rest of the repo follows. Third, a thrown exception becomes a receipt, not a crash. When the endpoint itself fails, the invocation is marked status="failed" with the error string captured, and the STAGE_EXECUTED event carries status , error , and whatever partial tool_trace accumulated straight into the replay log: # submission/agents/worker_factory.py except Exception as e: invocation.status = "failed" invocation.error = f"{type(e).__name__}: {e}" invocation.completed_at = time.time() return invocation, None, 0 The point is not that failures never happen - it is that a failure is visible and bounded. The floor still applies, the receipt still renders, the replay log still carries the error. A failed run is auditable; it is not a blank space where progress silently appeared. Layer 3: the gate has a third option - redirect Approve and reject are obvious. The interesting one is redirect - the gate can present a genuine strategic fork, two defensible options, and the CEO's pick becomes binding direction for the next worker. That turns the verification gate from a quality checkpoint into a steering wheel. A decision gate: two strategist proposals - Depth versus Breadth - each with tradeoffs, grounded in IQ sources and memory items Notice the metadata on that fork: the proposals are grounded in 2 IQ sources and 7 memory items in brief, and the worker reached them by calling recall , web_search , and calculate_consequence - a tool that previews the org and economic consequence before the CEO commits. The human is not rubber-stamping; they are choosing between options the workforce reasoned out and priced. Where XP is actually awarded The whole architecture funnels into one function. Approval - and only approval - calls approve_current_step in submission/tools/server.py , which awards XP and advances the campaign: # submission/tools/server.py - approve_current_step xp_earned = 10 + (score // 10) There is no other code path that mints XP. Not the validators, not the rubric, not the model. A high gate score enables a large reward, but a human pressing approve is what releases it. That is the responsible-AI guarantee expressed as control flow: the model can make the case, the validators can vouch for the structure, but the only function that turns work into progress is gated behind a person. How the approve, reject, or redirect decision is then written to memory and visibly changes the next chapter's brief is the subject of Part 3. Operational lessons learned Floor first, judge second. A model rubric on top of a deterministic floor gives you nuance without giving up safety. A model rubric alone gives you a confident scoreboard with no foundation. Re-anchor the model's structure to yours. Keep the model's scores, throw away its shape. Loop over your dimensions and weights so the model cannot reweight the rubric in its own favour. Cap every tool. max_invocations=2 is not a performance tweak; it is a containment boundary the runtime enforces. Log the proof on every path, then test for it. If your simulation mode does not emit the same proof points as live, you are testing a different program than you ship - so write a smoke test that fails the build when a proof point goes missing. Make the gate diegetic. Players (and judges) trust a control they can see. A score with a visible floor and an audit panel reads as engineering; a score from nowhere reads as marketing. Reasoning models and strict JSON do not mix. Anything that must emit JSON gets a tolerant extractor that survives think-blocks and markdown fences, with a deterministic fallback when every strategy fails. Responsible AI The gate is the responsible-AI architecture, stated as a game rule: nothing becomes progress without explicit human approval. Every approval is logged with the full reasoning chain in the replay log. Every rejection is written to memory as binding direction, so the same mistake is not made twice. Deterministic validators bound what the model can claim about its own output, the rubric re-anchors the model's judgement to weights it does not control, and the replay log preserves the whole chain for audit. The human's authority is not a courtesy - it is the only function that awards XP, enforced in code. Where this lives in the repo If you want to read the implementation, every piece of this post is in five files: Concern File Key symbol Deterministic validators (Layer 1) submission/tools/code_interpreter_wrappers.py validate_landing_page , validate_positioning , validate_org_chart , validate_financial_plan , validate_marketing_email Rubric + floor + tolerant JSON (Layer 2) submission/agents/worker_factory.py rubric_evaluate , _rubric_from_floor , _extract_json Capped mid-run tools + receipts submission/agents/maf_runtime.py _wrap , max_invocations=2 , maf_tool_trace Proof points, human gate, XP award (Layer 3) submission/tools/server.py approve_current_step , the STAGE_EXECUTED payload Build-fails-without-evidence test submission/tools/demo_smoke_test.py the _require evidence checks Try it Play a chapter and reject the first artifact on purpose - watch the rejection reshape the next brief: Play the live app or run it locally: git clone https://github.com/princepspolycap/agentsleague-afterbuild cd agentsleague-afterbuild && python3 -m venv .venv && source .venv/bin/activate pip install -r submission/requirements.txt python3 submission/tools/run_quest_simulation.py --pitch "Your idea here" The simulator runs the same three layers with zero Azure credentials, so you can step through approve, reject, and redirect offline before you ever wire up Foundry. Key takeaways Three scoring layers, one rule: no agent grades itself; only a human awards progress. Deterministic validators set a floor the model's rubric can raise but never lower - final = max(floor, weighted_total) . Re-anchor the model's rubric to your own dimensions and weights; keep its scores, not its structure. Expose receipts - model, tokens, cost, latency, tool calls - so scores are audited, not trusted, and test for them so the build fails without them. Cap every tool the model can call; an uncapped self-check is a budget leak. The gate's third option, redirect, turns verification into steering. A gate that only ever says "yes" is a dialog box. A gate that can say no, can redirect, floors a model with facts, re-anchors its judgement, and logs every decision is a reliability architecture. That is the difference between a demo and a system you would let touch something real. Part 2 of 5. Next: agents that remember the boss - how a gate decision becomes binding memory and visibly changes the next artifact on Microsoft Foundry. About this project I built a reasoning-agent game where you play a founder solving a world-improvement mission, and an AI workforce does the work while you make the calls. How it plays: You pitch a mission (like "solar microgrids for rural clinics") A Foundry-powered Master Narrator breaks it into an 8-stage quest graph An Org Designer agent builds you a custom digital workforce (Strategist, Designer, Marketer, Ops) Each stage runs as a real agent on the Microsoft Agent Framework, grounded in Foundry IQ You play tactical cards, counter a rival antagonist, and approve every artifact at a verification gate before it counts Why it's different: the reasoning IS the gameplay. Decomposition, IQ citations, memory, tool calls, and a deterministic validator floor are all visible as cards and receipts. Every reasoning agent runs on Microsoft Foundry. Runs after git clone with zero credentials (simulation mode), so it's fully forkable and MIT. Try it / check it out: Live app (hosted on Azure): worldforge-game.mangowater-fa8b860a.eastus2.azurecontainerapps.io GitHub (public, MIT): github.com/princepspolycap/agentsleague-afterbuild Demo video: youtu.be/ElGXboGh6NE Live battle replay: Agents League - Reasoning Agents on Microsoft Reactor Would love any feedback, pull requests, or ideas. Built for the Reasoning Agents track. Microsoft Agent Framework and Microsoft Foundry docs79Views0likes0CommentsCreating a Fun Multi-Agent Content Strategy System with Microsoft Agent Framework
This tutorial walks you through building a multi-agent content strategy system using Microsoft's AutoGen framework. Three specialised AI agents — a Content Creator, an Algorithm Simulator, and an Audience Persona — collaborate to help gaming content creators pressure-test their social media posts before publishing. Using live Google Trends data and platform-specific scoring rubrics for TikTok, Twitter/X, YouTube, and Instagram, the system generates content, predicts how each platform's algorithm would distribute it, and simulates authentic audience reactions. The tutorial covers core multi-agent patterns including role specialisation, structured evaluation, iterative feedback loops, and resilient tool integration — all running on GitHub Models' free tier.851Views0likes0CommentsMake the most of Microsoft Learn Cloud Games
To help foster such positive outcomes, Microsoft Learn has brought to life an innovative experiential approach with the introduction of interactive Cloud Games. Designed especially for security and data & AI professionals with an intermediate knowledge level across a range of Microsoft solutions, Who Hacked? and Data Feeds are fun, immersive role-playing games with the mission of refreshing and reinforcing your IT expertise7.6KViews4likes1CommentAI and Gaming Research Summit
This exciting new Microsoft Research event aims to facilitate open discussion and critical dialogue by bringing together academia and industry to better understand each other’s perspectives at the intersection of AI and gaming research. AI and Gaming Research Summit - Microsoft Research2KViews0likes0CommentsMaking games with C# and Unity – Beginner’s Tutorial
First published on MSDN on Feb 24, 2018 Guest post by Sondre Agledahl: Games programmer, CS student and Microsoft Student Partner at UCLMicrosoft Student Partners ran an introductory workshop to game development with C# and Unity at UCL.3.8KViews0likes0Comments
